@tanstack/solid-hotkeys 0.5.1 → 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/HotkeysProvider.cjs.map +1 -1
- package/dist/HotkeysProvider.d.cts +2 -1
- package/dist/HotkeysProvider.d.ts +2 -1
- package/dist/HotkeysProvider.js.map +1 -1
- package/dist/createHotkey.cjs +27 -8
- package/dist/createHotkey.cjs.map +1 -1
- package/dist/createHotkey.js +27 -8
- package/dist/createHotkey.js.map +1 -1
- package/dist/createHotkeySequence.cjs +27 -8
- package/dist/createHotkeySequence.cjs.map +1 -1
- package/dist/createHotkeySequence.js +28 -9
- package/dist/createHotkeySequence.js.map +1 -1
- package/dist/createHotkeySequenceRecorder.cjs +43 -0
- package/dist/createHotkeySequenceRecorder.cjs.map +1 -0
- package/dist/createHotkeySequenceRecorder.d.cts +19 -0
- package/dist/createHotkeySequenceRecorder.d.ts +19 -0
- package/dist/createHotkeySequenceRecorder.js +43 -0
- package/dist/createHotkeySequenceRecorder.js.map +1 -0
- package/dist/createHotkeySequences.cjs +110 -0
- package/dist/createHotkeySequences.cjs.map +1 -0
- package/dist/createHotkeySequences.d.cts +57 -0
- package/dist/createHotkeySequences.d.ts +57 -0
- package/dist/createHotkeySequences.js +110 -0
- package/dist/createHotkeySequences.js.map +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/package.json +2 -2
- package/src/HotkeysProvider.tsx +5 -1
- package/src/createHotkey.ts +32 -13
- package/src/createHotkeySequence.ts +33 -16
- package/src/createHotkeySequenceRecorder.ts +66 -0
- package/src/createHotkeySequences.ts +176 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const require_HotkeysProvider = require('./HotkeysProvider.cjs');
|
|
2
|
+
let _tanstack_hotkeys = require("@tanstack/hotkeys");
|
|
3
|
+
let solid_js = require("solid-js");
|
|
4
|
+
|
|
5
|
+
//#region src/createHotkeySequences.ts
|
|
6
|
+
/**
|
|
7
|
+
* SolidJS primitive for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
8
|
+
*
|
|
9
|
+
* Uses the singleton SequenceManager. Accepts a dynamic array of definitions, or accessors,
|
|
10
|
+
* so you can react to variable-length lists.
|
|
11
|
+
*
|
|
12
|
+
* Options are merged in this order:
|
|
13
|
+
* HotkeysProvider defaults < commonOptions < per-definition options
|
|
14
|
+
*
|
|
15
|
+
* Definitions with an empty `sequence` are skipped (no registration).
|
|
16
|
+
*
|
|
17
|
+
* @param sequences - Array of sequence definitions, or accessor returning them
|
|
18
|
+
* @param commonOptions - Shared options for all sequences, or accessor
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* function VimPalette() {
|
|
23
|
+
* createHotkeySequences([
|
|
24
|
+
* { sequence: ['G', 'G'], callback: () => scrollToTop() },
|
|
25
|
+
* { sequence: ['D', 'D'], callback: () => deleteLine() },
|
|
26
|
+
* ])
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* function Dynamic(props) {
|
|
33
|
+
* createHotkeySequences(
|
|
34
|
+
* () => props.items.map((item) => ({
|
|
35
|
+
* sequence: item.chords,
|
|
36
|
+
* callback: item.action,
|
|
37
|
+
* options: { enabled: item.enabled },
|
|
38
|
+
* })),
|
|
39
|
+
* { preventDefault: true },
|
|
40
|
+
* )
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function createHotkeySequences(sequences, commonOptions = {}) {
|
|
45
|
+
const defaultOptions = require_HotkeysProvider.useDefaultHotkeysOptions();
|
|
46
|
+
const manager = (0, _tanstack_hotkeys.getSequenceManager)();
|
|
47
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
48
|
+
(0, solid_js.onCleanup)(() => {
|
|
49
|
+
for (const { handle } of registrations.values()) if (handle.isActive) handle.unregister();
|
|
50
|
+
registrations.clear();
|
|
51
|
+
});
|
|
52
|
+
(0, solid_js.createEffect)(() => {
|
|
53
|
+
const resolved = typeof sequences === "function" ? sequences() : sequences;
|
|
54
|
+
const resolvedCommonOptions = typeof commonOptions === "function" ? commonOptions() : commonOptions;
|
|
55
|
+
const nextKeys = /* @__PURE__ */ new Set();
|
|
56
|
+
const prepared = [];
|
|
57
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
58
|
+
const def = resolved[i];
|
|
59
|
+
const resolvedDefOptions = def.options ?? {};
|
|
60
|
+
const mergedOptions = {
|
|
61
|
+
...defaultOptions.hotkeySequence,
|
|
62
|
+
...resolvedCommonOptions,
|
|
63
|
+
...resolvedDefOptions
|
|
64
|
+
};
|
|
65
|
+
if (def.sequence.length === 0) continue;
|
|
66
|
+
const sequenceString = (0, _tanstack_hotkeys.formatHotkeySequence)(def.sequence);
|
|
67
|
+
const resolvedTarget = "target" in mergedOptions ? mergedOptions.target ?? null : typeof document !== "undefined" ? document : null;
|
|
68
|
+
if (!resolvedTarget) continue;
|
|
69
|
+
const registrationKey = `${i}:${sequenceString}`;
|
|
70
|
+
nextKeys.add(registrationKey);
|
|
71
|
+
prepared.push({
|
|
72
|
+
registrationKey,
|
|
73
|
+
def,
|
|
74
|
+
mergedOptions,
|
|
75
|
+
sequenceString,
|
|
76
|
+
resolvedTarget
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
for (const [key, record] of [...registrations.entries()]) if (!nextKeys.has(key)) {
|
|
80
|
+
if (record.handle.isActive) record.handle.unregister();
|
|
81
|
+
registrations.delete(key);
|
|
82
|
+
}
|
|
83
|
+
for (const p of prepared) {
|
|
84
|
+
const existing = registrations.get(p.registrationKey);
|
|
85
|
+
if (existing?.handle.isActive && existing.target === p.resolvedTarget) {
|
|
86
|
+
existing.handle.callback = p.def.callback;
|
|
87
|
+
const { target: _target, ...optionsWithoutTarget } = p.mergedOptions;
|
|
88
|
+
existing.handle.setOptions(optionsWithoutTarget);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (existing) {
|
|
92
|
+
if (existing.handle.isActive) existing.handle.unregister();
|
|
93
|
+
registrations.delete(p.registrationKey);
|
|
94
|
+
}
|
|
95
|
+
const { target: _target, ...optionsWithoutTarget } = p.mergedOptions;
|
|
96
|
+
const handle = manager.register(p.def.sequence, p.def.callback, {
|
|
97
|
+
...optionsWithoutTarget,
|
|
98
|
+
target: p.resolvedTarget
|
|
99
|
+
});
|
|
100
|
+
registrations.set(p.registrationKey, {
|
|
101
|
+
handle,
|
|
102
|
+
target: p.resolvedTarget
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
exports.createHotkeySequences = createHotkeySequences;
|
|
110
|
+
//# sourceMappingURL=createHotkeySequences.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createHotkeySequences.cjs","names":["useDefaultHotkeysOptions"],"sources":["../src/createHotkeySequences.ts"],"sourcesContent":["import { createEffect, onCleanup } from 'solid-js'\nimport { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'\nimport { useDefaultHotkeysOptions } from './HotkeysProvider'\nimport type { CreateHotkeySequenceOptions } from './createHotkeySequence'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceRegistrationHandle,\n} from '@tanstack/hotkeys'\n\n/**\n * A single sequence definition for use with `createHotkeySequences`.\n */\nexport interface CreateHotkeySequenceDefinition {\n /** Array of hotkey strings that form the sequence */\n sequence: 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?: CreateHotkeySequenceOptions\n}\n\n/**\n * SolidJS primitive for registering multiple keyboard shortcut sequences at once (Vim-style).\n *\n * Uses the singleton SequenceManager. Accepts a dynamic array of definitions, or accessors,\n * so you can react to variable-length lists.\n *\n * Options are merged in this order:\n * HotkeysProvider defaults < commonOptions < per-definition options\n *\n * Definitions with an empty `sequence` are skipped (no registration).\n *\n * @param sequences - Array of sequence definitions, or accessor returning them\n * @param commonOptions - Shared options for all sequences, or accessor\n *\n * @example\n * ```tsx\n * function VimPalette() {\n * createHotkeySequences([\n * { sequence: ['G', 'G'], callback: () => scrollToTop() },\n * { sequence: ['D', 'D'], callback: () => deleteLine() },\n * ])\n * }\n * ```\n *\n * @example\n * ```tsx\n * function Dynamic(props) {\n * createHotkeySequences(\n * () => props.items.map((item) => ({\n * sequence: item.chords,\n * callback: item.action,\n * options: { enabled: item.enabled },\n * })),\n * { preventDefault: true },\n * )\n * }\n * ```\n */\nexport function createHotkeySequences(\n sequences:\n | Array<CreateHotkeySequenceDefinition>\n | (() => Array<CreateHotkeySequenceDefinition>),\n commonOptions:\n | CreateHotkeySequenceOptions\n | (() => CreateHotkeySequenceOptions) = {},\n): void {\n type RegistrationRecord = {\n handle: SequenceRegistrationHandle\n target: Document | HTMLElement | Window\n }\n\n const defaultOptions = useDefaultHotkeysOptions()\n const manager = getSequenceManager()\n\n const registrations = new Map<string, RegistrationRecord>()\n\n onCleanup(() => {\n for (const { handle } of registrations.values()) {\n if (handle.isActive) {\n handle.unregister()\n }\n }\n registrations.clear()\n })\n\n createEffect(() => {\n const resolved = 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: CreateHotkeySequenceDefinition\n mergedOptions: CreateHotkeySequenceOptions\n sequenceString: string\n resolvedTarget: Document | HTMLElement | Window\n }> = []\n\n for (let i = 0; i < resolved.length; i++) {\n const def = resolved[i]!\n const resolvedDefOptions = def.options ?? {}\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedCommonOptions,\n ...resolvedDefOptions,\n } as CreateHotkeySequenceOptions\n\n if (def.sequence.length === 0) {\n continue\n }\n\n const sequenceString = formatHotkeySequence(def.sequence)\n\n const resolvedTarget =\n 'target' in mergedOptions\n ? (mergedOptions.target ?? null)\n : typeof document !== 'undefined'\n ? document\n : null\n\n if (!resolvedTarget) {\n continue\n }\n\n const registrationKey = `${i}:${sequenceString}`\n nextKeys.add(registrationKey)\n prepared.push({\n registrationKey,\n def,\n mergedOptions,\n sequenceString,\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.mergedOptions\n existing.handle.setOptions(optionsWithoutTarget)\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 { target: _target, ...optionsWithoutTarget } = p.mergedOptions\n const handle = manager.register(p.def.sequence, p.def.callback, {\n ...optionsWithoutTarget,\n target: p.resolvedTarget,\n })\n registrations.set(p.registrationKey, {\n handle,\n target: p.resolvedTarget,\n })\n }\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DA,SAAgB,sBACd,WAGA,gBAE0C,EAAE,EACtC;CAMN,MAAM,iBAAiBA,kDAA0B;CACjD,MAAM,qDAA8B;CAEpC,MAAM,gCAAgB,IAAI,KAAiC;AAE3D,+BAAgB;AACd,OAAK,MAAM,EAAE,YAAY,cAAc,QAAQ,CAC7C,KAAI,OAAO,SACT,QAAO,YAAY;AAGvB,gBAAc,OAAO;GACrB;AAEF,kCAAmB;EACjB,MAAM,WAAW,OAAO,cAAc,aAAa,WAAW,GAAG;EACjE,MAAM,wBACJ,OAAO,kBAAkB,aAAa,eAAe,GAAG;EAE1D,MAAM,2BAAW,IAAI,KAAa;EAClC,MAAM,WAMD,EAAE;AAEP,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;GACxC,MAAM,MAAM,SAAS;GACrB,MAAM,qBAAqB,IAAI,WAAW,EAAE;GAE5C,MAAM,gBAAgB;IACpB,GAAG,eAAe;IAClB,GAAG;IACH,GAAG;IACJ;AAED,OAAI,IAAI,SAAS,WAAW,EAC1B;GAGF,MAAM,6DAAsC,IAAI,SAAS;GAEzD,MAAM,iBACJ,YAAY,gBACP,cAAc,UAAU,OACzB,OAAO,aAAa,cAClB,WACA;AAER,OAAI,CAAC,eACH;GAGF,MAAM,kBAAkB,GAAG,EAAE,GAAG;AAChC,YAAS,IAAI,gBAAgB;AAC7B,YAAS,KAAK;IACZ;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,qBAAqB;AAChD;;AAGF,OAAI,UAAU;AACZ,QAAI,SAAS,OAAO,SAClB,UAAS,OAAO,YAAY;AAE9B,kBAAc,OAAO,EAAE,gBAAgB;;GAGzC,MAAM,EAAE,QAAQ,SAAS,GAAG,yBAAyB,EAAE;GACvD,MAAM,SAAS,QAAQ,SAAS,EAAE,IAAI,UAAU,EAAE,IAAI,UAAU;IAC9D,GAAG;IACH,QAAQ,EAAE;IACX,CAAC;AACF,iBAAc,IAAI,EAAE,iBAAiB;IACnC;IACA,QAAQ,EAAE;IACX,CAAC;;GAEJ"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { CreateHotkeySequenceOptions } from "./createHotkeySequence.cjs";
|
|
2
|
+
import { HotkeyCallback, HotkeySequence } from "@tanstack/hotkeys";
|
|
3
|
+
|
|
4
|
+
//#region src/createHotkeySequences.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A single sequence definition for use with `createHotkeySequences`.
|
|
7
|
+
*/
|
|
8
|
+
interface CreateHotkeySequenceDefinition {
|
|
9
|
+
/** Array of hotkey strings that form the sequence */
|
|
10
|
+
sequence: 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?: CreateHotkeySequenceOptions;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* SolidJS primitive for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
18
|
+
*
|
|
19
|
+
* Uses the singleton SequenceManager. Accepts a dynamic array of definitions, or accessors,
|
|
20
|
+
* so you can react to variable-length lists.
|
|
21
|
+
*
|
|
22
|
+
* Options are merged in this order:
|
|
23
|
+
* HotkeysProvider defaults < commonOptions < per-definition options
|
|
24
|
+
*
|
|
25
|
+
* Definitions with an empty `sequence` are skipped (no registration).
|
|
26
|
+
*
|
|
27
|
+
* @param sequences - Array of sequence definitions, or accessor returning them
|
|
28
|
+
* @param commonOptions - Shared options for all sequences, or accessor
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* function VimPalette() {
|
|
33
|
+
* createHotkeySequences([
|
|
34
|
+
* { sequence: ['G', 'G'], callback: () => scrollToTop() },
|
|
35
|
+
* { sequence: ['D', 'D'], callback: () => deleteLine() },
|
|
36
|
+
* ])
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* function Dynamic(props) {
|
|
43
|
+
* createHotkeySequences(
|
|
44
|
+
* () => props.items.map((item) => ({
|
|
45
|
+
* sequence: item.chords,
|
|
46
|
+
* callback: item.action,
|
|
47
|
+
* options: { enabled: item.enabled },
|
|
48
|
+
* })),
|
|
49
|
+
* { preventDefault: true },
|
|
50
|
+
* )
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare function createHotkeySequences(sequences: Array<CreateHotkeySequenceDefinition> | (() => Array<CreateHotkeySequenceDefinition>), commonOptions?: CreateHotkeySequenceOptions | (() => CreateHotkeySequenceOptions)): void;
|
|
55
|
+
//#endregion
|
|
56
|
+
export { CreateHotkeySequenceDefinition, createHotkeySequences };
|
|
57
|
+
//# sourceMappingURL=createHotkeySequences.d.cts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { CreateHotkeySequenceOptions } from "./createHotkeySequence.js";
|
|
2
|
+
import { HotkeyCallback, HotkeySequence } from "@tanstack/hotkeys";
|
|
3
|
+
|
|
4
|
+
//#region src/createHotkeySequences.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A single sequence definition for use with `createHotkeySequences`.
|
|
7
|
+
*/
|
|
8
|
+
interface CreateHotkeySequenceDefinition {
|
|
9
|
+
/** Array of hotkey strings that form the sequence */
|
|
10
|
+
sequence: 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?: CreateHotkeySequenceOptions;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* SolidJS primitive for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
18
|
+
*
|
|
19
|
+
* Uses the singleton SequenceManager. Accepts a dynamic array of definitions, or accessors,
|
|
20
|
+
* so you can react to variable-length lists.
|
|
21
|
+
*
|
|
22
|
+
* Options are merged in this order:
|
|
23
|
+
* HotkeysProvider defaults < commonOptions < per-definition options
|
|
24
|
+
*
|
|
25
|
+
* Definitions with an empty `sequence` are skipped (no registration).
|
|
26
|
+
*
|
|
27
|
+
* @param sequences - Array of sequence definitions, or accessor returning them
|
|
28
|
+
* @param commonOptions - Shared options for all sequences, or accessor
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* function VimPalette() {
|
|
33
|
+
* createHotkeySequences([
|
|
34
|
+
* { sequence: ['G', 'G'], callback: () => scrollToTop() },
|
|
35
|
+
* { sequence: ['D', 'D'], callback: () => deleteLine() },
|
|
36
|
+
* ])
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* function Dynamic(props) {
|
|
43
|
+
* createHotkeySequences(
|
|
44
|
+
* () => props.items.map((item) => ({
|
|
45
|
+
* sequence: item.chords,
|
|
46
|
+
* callback: item.action,
|
|
47
|
+
* options: { enabled: item.enabled },
|
|
48
|
+
* })),
|
|
49
|
+
* { preventDefault: true },
|
|
50
|
+
* )
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare function createHotkeySequences(sequences: Array<CreateHotkeySequenceDefinition> | (() => Array<CreateHotkeySequenceDefinition>), commonOptions?: CreateHotkeySequenceOptions | (() => CreateHotkeySequenceOptions)): void;
|
|
55
|
+
//#endregion
|
|
56
|
+
export { CreateHotkeySequenceDefinition, createHotkeySequences };
|
|
57
|
+
//# sourceMappingURL=createHotkeySequences.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { useDefaultHotkeysOptions } from "./HotkeysProvider.js";
|
|
2
|
+
import { formatHotkeySequence, getSequenceManager } from "@tanstack/hotkeys";
|
|
3
|
+
import { createEffect, onCleanup } from "solid-js";
|
|
4
|
+
|
|
5
|
+
//#region src/createHotkeySequences.ts
|
|
6
|
+
/**
|
|
7
|
+
* SolidJS primitive for registering multiple keyboard shortcut sequences at once (Vim-style).
|
|
8
|
+
*
|
|
9
|
+
* Uses the singleton SequenceManager. Accepts a dynamic array of definitions, or accessors,
|
|
10
|
+
* so you can react to variable-length lists.
|
|
11
|
+
*
|
|
12
|
+
* Options are merged in this order:
|
|
13
|
+
* HotkeysProvider defaults < commonOptions < per-definition options
|
|
14
|
+
*
|
|
15
|
+
* Definitions with an empty `sequence` are skipped (no registration).
|
|
16
|
+
*
|
|
17
|
+
* @param sequences - Array of sequence definitions, or accessor returning them
|
|
18
|
+
* @param commonOptions - Shared options for all sequences, or accessor
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* function VimPalette() {
|
|
23
|
+
* createHotkeySequences([
|
|
24
|
+
* { sequence: ['G', 'G'], callback: () => scrollToTop() },
|
|
25
|
+
* { sequence: ['D', 'D'], callback: () => deleteLine() },
|
|
26
|
+
* ])
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* function Dynamic(props) {
|
|
33
|
+
* createHotkeySequences(
|
|
34
|
+
* () => props.items.map((item) => ({
|
|
35
|
+
* sequence: item.chords,
|
|
36
|
+
* callback: item.action,
|
|
37
|
+
* options: { enabled: item.enabled },
|
|
38
|
+
* })),
|
|
39
|
+
* { preventDefault: true },
|
|
40
|
+
* )
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function createHotkeySequences(sequences, commonOptions = {}) {
|
|
45
|
+
const defaultOptions = useDefaultHotkeysOptions();
|
|
46
|
+
const manager = getSequenceManager();
|
|
47
|
+
const registrations = /* @__PURE__ */ new Map();
|
|
48
|
+
onCleanup(() => {
|
|
49
|
+
for (const { handle } of registrations.values()) if (handle.isActive) handle.unregister();
|
|
50
|
+
registrations.clear();
|
|
51
|
+
});
|
|
52
|
+
createEffect(() => {
|
|
53
|
+
const resolved = typeof sequences === "function" ? sequences() : sequences;
|
|
54
|
+
const resolvedCommonOptions = typeof commonOptions === "function" ? commonOptions() : commonOptions;
|
|
55
|
+
const nextKeys = /* @__PURE__ */ new Set();
|
|
56
|
+
const prepared = [];
|
|
57
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
58
|
+
const def = resolved[i];
|
|
59
|
+
const resolvedDefOptions = def.options ?? {};
|
|
60
|
+
const mergedOptions = {
|
|
61
|
+
...defaultOptions.hotkeySequence,
|
|
62
|
+
...resolvedCommonOptions,
|
|
63
|
+
...resolvedDefOptions
|
|
64
|
+
};
|
|
65
|
+
if (def.sequence.length === 0) continue;
|
|
66
|
+
const sequenceString = formatHotkeySequence(def.sequence);
|
|
67
|
+
const resolvedTarget = "target" in mergedOptions ? mergedOptions.target ?? null : typeof document !== "undefined" ? document : null;
|
|
68
|
+
if (!resolvedTarget) continue;
|
|
69
|
+
const registrationKey = `${i}:${sequenceString}`;
|
|
70
|
+
nextKeys.add(registrationKey);
|
|
71
|
+
prepared.push({
|
|
72
|
+
registrationKey,
|
|
73
|
+
def,
|
|
74
|
+
mergedOptions,
|
|
75
|
+
sequenceString,
|
|
76
|
+
resolvedTarget
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
for (const [key, record] of [...registrations.entries()]) if (!nextKeys.has(key)) {
|
|
80
|
+
if (record.handle.isActive) record.handle.unregister();
|
|
81
|
+
registrations.delete(key);
|
|
82
|
+
}
|
|
83
|
+
for (const p of prepared) {
|
|
84
|
+
const existing = registrations.get(p.registrationKey);
|
|
85
|
+
if (existing?.handle.isActive && existing.target === p.resolvedTarget) {
|
|
86
|
+
existing.handle.callback = p.def.callback;
|
|
87
|
+
const { target: _target, ...optionsWithoutTarget } = p.mergedOptions;
|
|
88
|
+
existing.handle.setOptions(optionsWithoutTarget);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (existing) {
|
|
92
|
+
if (existing.handle.isActive) existing.handle.unregister();
|
|
93
|
+
registrations.delete(p.registrationKey);
|
|
94
|
+
}
|
|
95
|
+
const { target: _target, ...optionsWithoutTarget } = p.mergedOptions;
|
|
96
|
+
const handle = manager.register(p.def.sequence, p.def.callback, {
|
|
97
|
+
...optionsWithoutTarget,
|
|
98
|
+
target: p.resolvedTarget
|
|
99
|
+
});
|
|
100
|
+
registrations.set(p.registrationKey, {
|
|
101
|
+
handle,
|
|
102
|
+
target: p.resolvedTarget
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
export { createHotkeySequences };
|
|
110
|
+
//# sourceMappingURL=createHotkeySequences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createHotkeySequences.js","names":[],"sources":["../src/createHotkeySequences.ts"],"sourcesContent":["import { createEffect, onCleanup } from 'solid-js'\nimport { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'\nimport { useDefaultHotkeysOptions } from './HotkeysProvider'\nimport type { CreateHotkeySequenceOptions } from './createHotkeySequence'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceRegistrationHandle,\n} from '@tanstack/hotkeys'\n\n/**\n * A single sequence definition for use with `createHotkeySequences`.\n */\nexport interface CreateHotkeySequenceDefinition {\n /** Array of hotkey strings that form the sequence */\n sequence: 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?: CreateHotkeySequenceOptions\n}\n\n/**\n * SolidJS primitive for registering multiple keyboard shortcut sequences at once (Vim-style).\n *\n * Uses the singleton SequenceManager. Accepts a dynamic array of definitions, or accessors,\n * so you can react to variable-length lists.\n *\n * Options are merged in this order:\n * HotkeysProvider defaults < commonOptions < per-definition options\n *\n * Definitions with an empty `sequence` are skipped (no registration).\n *\n * @param sequences - Array of sequence definitions, or accessor returning them\n * @param commonOptions - Shared options for all sequences, or accessor\n *\n * @example\n * ```tsx\n * function VimPalette() {\n * createHotkeySequences([\n * { sequence: ['G', 'G'], callback: () => scrollToTop() },\n * { sequence: ['D', 'D'], callback: () => deleteLine() },\n * ])\n * }\n * ```\n *\n * @example\n * ```tsx\n * function Dynamic(props) {\n * createHotkeySequences(\n * () => props.items.map((item) => ({\n * sequence: item.chords,\n * callback: item.action,\n * options: { enabled: item.enabled },\n * })),\n * { preventDefault: true },\n * )\n * }\n * ```\n */\nexport function createHotkeySequences(\n sequences:\n | Array<CreateHotkeySequenceDefinition>\n | (() => Array<CreateHotkeySequenceDefinition>),\n commonOptions:\n | CreateHotkeySequenceOptions\n | (() => CreateHotkeySequenceOptions) = {},\n): void {\n type RegistrationRecord = {\n handle: SequenceRegistrationHandle\n target: Document | HTMLElement | Window\n }\n\n const defaultOptions = useDefaultHotkeysOptions()\n const manager = getSequenceManager()\n\n const registrations = new Map<string, RegistrationRecord>()\n\n onCleanup(() => {\n for (const { handle } of registrations.values()) {\n if (handle.isActive) {\n handle.unregister()\n }\n }\n registrations.clear()\n })\n\n createEffect(() => {\n const resolved = 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: CreateHotkeySequenceDefinition\n mergedOptions: CreateHotkeySequenceOptions\n sequenceString: string\n resolvedTarget: Document | HTMLElement | Window\n }> = []\n\n for (let i = 0; i < resolved.length; i++) {\n const def = resolved[i]!\n const resolvedDefOptions = def.options ?? {}\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedCommonOptions,\n ...resolvedDefOptions,\n } as CreateHotkeySequenceOptions\n\n if (def.sequence.length === 0) {\n continue\n }\n\n const sequenceString = formatHotkeySequence(def.sequence)\n\n const resolvedTarget =\n 'target' in mergedOptions\n ? (mergedOptions.target ?? null)\n : typeof document !== 'undefined'\n ? document\n : null\n\n if (!resolvedTarget) {\n continue\n }\n\n const registrationKey = `${i}:${sequenceString}`\n nextKeys.add(registrationKey)\n prepared.push({\n registrationKey,\n def,\n mergedOptions,\n sequenceString,\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.mergedOptions\n existing.handle.setOptions(optionsWithoutTarget)\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 { target: _target, ...optionsWithoutTarget } = p.mergedOptions\n const handle = manager.register(p.def.sequence, p.def.callback, {\n ...optionsWithoutTarget,\n target: p.resolvedTarget,\n })\n registrations.set(p.registrationKey, {\n handle,\n target: p.resolvedTarget,\n })\n }\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DA,SAAgB,sBACd,WAGA,gBAE0C,EAAE,EACtC;CAMN,MAAM,iBAAiB,0BAA0B;CACjD,MAAM,UAAU,oBAAoB;CAEpC,MAAM,gCAAgB,IAAI,KAAiC;AAE3D,iBAAgB;AACd,OAAK,MAAM,EAAE,YAAY,cAAc,QAAQ,CAC7C,KAAI,OAAO,SACT,QAAO,YAAY;AAGvB,gBAAc,OAAO;GACrB;AAEF,oBAAmB;EACjB,MAAM,WAAW,OAAO,cAAc,aAAa,WAAW,GAAG;EACjE,MAAM,wBACJ,OAAO,kBAAkB,aAAa,eAAe,GAAG;EAE1D,MAAM,2BAAW,IAAI,KAAa;EAClC,MAAM,WAMD,EAAE;AAEP,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;GACxC,MAAM,MAAM,SAAS;GACrB,MAAM,qBAAqB,IAAI,WAAW,EAAE;GAE5C,MAAM,gBAAgB;IACpB,GAAG,eAAe;IAClB,GAAG;IACH,GAAG;IACJ;AAED,OAAI,IAAI,SAAS,WAAW,EAC1B;GAGF,MAAM,iBAAiB,qBAAqB,IAAI,SAAS;GAEzD,MAAM,iBACJ,YAAY,gBACP,cAAc,UAAU,OACzB,OAAO,aAAa,cAClB,WACA;AAER,OAAI,CAAC,eACH;GAGF,MAAM,kBAAkB,GAAG,EAAE,GAAG;AAChC,YAAS,IAAI,gBAAgB;AAC7B,YAAS,KAAK;IACZ;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,qBAAqB;AAChD;;AAGF,OAAI,UAAU;AACZ,QAAI,SAAS,OAAO,SAClB,UAAS,OAAO,YAAY;AAE9B,kBAAc,OAAO,EAAE,gBAAgB;;GAGzC,MAAM,EAAE,QAAQ,SAAS,GAAG,yBAAyB,EAAE;GACvD,MAAM,SAAS,QAAQ,SAAS,EAAE,IAAI,UAAU,EAAE,IAAI,UAAU;IAC9D,GAAG;IACH,QAAQ,EAAE;IACX,CAAC;AACF,iBAAc,IAAI,EAAE,iBAAiB;IACnC;IACA,QAAQ,EAAE;IACX,CAAC;;GAEJ"}
|
package/dist/index.cjs
CHANGED
|
@@ -6,7 +6,9 @@ const require_createHeldKeys = require('./createHeldKeys.cjs');
|
|
|
6
6
|
const require_createHeldKeyCodes = require('./createHeldKeyCodes.cjs');
|
|
7
7
|
const require_createKeyHold = require('./createKeyHold.cjs');
|
|
8
8
|
const require_createHotkeySequence = require('./createHotkeySequence.cjs');
|
|
9
|
+
const require_createHotkeySequences = require('./createHotkeySequences.cjs');
|
|
9
10
|
const require_createHotkeyRecorder = require('./createHotkeyRecorder.cjs');
|
|
11
|
+
const require_createHotkeySequenceRecorder = require('./createHotkeySequenceRecorder.cjs');
|
|
10
12
|
|
|
11
13
|
exports.HotkeysProvider = require_HotkeysProvider.HotkeysProvider;
|
|
12
14
|
exports.createHeldKeyCodes = require_createHeldKeyCodes.createHeldKeyCodes;
|
|
@@ -14,6 +16,8 @@ exports.createHeldKeys = require_createHeldKeys.createHeldKeys;
|
|
|
14
16
|
exports.createHotkey = require_createHotkey.createHotkey;
|
|
15
17
|
exports.createHotkeyRecorder = require_createHotkeyRecorder.createHotkeyRecorder;
|
|
16
18
|
exports.createHotkeySequence = require_createHotkeySequence.createHotkeySequence;
|
|
19
|
+
exports.createHotkeySequenceRecorder = require_createHotkeySequenceRecorder.createHotkeySequenceRecorder;
|
|
20
|
+
exports.createHotkeySequences = require_createHotkeySequences.createHotkeySequences;
|
|
17
21
|
exports.createHotkeys = require_createHotkeys.createHotkeys;
|
|
18
22
|
exports.createKeyHold = require_createKeyHold.createKeyHold;
|
|
19
23
|
exports.useDefaultHotkeysOptions = require_HotkeysProvider.useDefaultHotkeysOptions;
|
package/dist/index.d.cts
CHANGED
|
@@ -5,6 +5,8 @@ import { CreateHotkeyDefinition, createHotkeys } from "./createHotkeys.cjs";
|
|
|
5
5
|
import { createHeldKeys } from "./createHeldKeys.cjs";
|
|
6
6
|
import { createHeldKeyCodes } from "./createHeldKeyCodes.cjs";
|
|
7
7
|
import { createKeyHold } from "./createKeyHold.cjs";
|
|
8
|
+
import { CreateHotkeySequenceDefinition, createHotkeySequences } from "./createHotkeySequences.cjs";
|
|
8
9
|
import { SolidHotkeyRecorder, createHotkeyRecorder } from "./createHotkeyRecorder.cjs";
|
|
10
|
+
import { SolidHotkeySequenceRecorder, createHotkeySequenceRecorder } from "./createHotkeySequenceRecorder.cjs";
|
|
9
11
|
export * from "@tanstack/hotkeys";
|
|
10
|
-
export { CreateHotkeyDefinition, CreateHotkeyOptions, CreateHotkeySequenceOptions, HotkeysProvider, HotkeysProviderOptions, HotkeysProviderProps, SolidHotkeyRecorder, createHeldKeyCodes, createHeldKeys, createHotkey, createHotkeyRecorder, createHotkeySequence, createHotkeys, createKeyHold, useDefaultHotkeysOptions, useHotkeysContext };
|
|
12
|
+
export { CreateHotkeyDefinition, CreateHotkeyOptions, CreateHotkeySequenceDefinition, CreateHotkeySequenceOptions, HotkeysProvider, HotkeysProviderOptions, HotkeysProviderProps, SolidHotkeyRecorder, SolidHotkeySequenceRecorder, createHeldKeyCodes, createHeldKeys, createHotkey, createHotkeyRecorder, createHotkeySequence, createHotkeySequenceRecorder, createHotkeySequences, createHotkeys, createKeyHold, useDefaultHotkeysOptions, useHotkeysContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { CreateHotkeyDefinition, createHotkeys } from "./createHotkeys.js";
|
|
|
5
5
|
import { createHeldKeys } from "./createHeldKeys.js";
|
|
6
6
|
import { createHeldKeyCodes } from "./createHeldKeyCodes.js";
|
|
7
7
|
import { createKeyHold } from "./createKeyHold.js";
|
|
8
|
+
import { CreateHotkeySequenceDefinition, createHotkeySequences } from "./createHotkeySequences.js";
|
|
8
9
|
import { SolidHotkeyRecorder, createHotkeyRecorder } from "./createHotkeyRecorder.js";
|
|
10
|
+
import { SolidHotkeySequenceRecorder, createHotkeySequenceRecorder } from "./createHotkeySequenceRecorder.js";
|
|
9
11
|
export * from "@tanstack/hotkeys";
|
|
10
|
-
export { CreateHotkeyDefinition, CreateHotkeyOptions, CreateHotkeySequenceOptions, HotkeysProvider, HotkeysProviderOptions, HotkeysProviderProps, SolidHotkeyRecorder, createHeldKeyCodes, createHeldKeys, createHotkey, createHotkeyRecorder, createHotkeySequence, createHotkeys, createKeyHold, useDefaultHotkeysOptions, useHotkeysContext };
|
|
12
|
+
export { CreateHotkeyDefinition, CreateHotkeyOptions, CreateHotkeySequenceDefinition, CreateHotkeySequenceOptions, HotkeysProvider, HotkeysProviderOptions, HotkeysProviderProps, SolidHotkeyRecorder, SolidHotkeySequenceRecorder, createHeldKeyCodes, createHeldKeys, createHotkey, createHotkeyRecorder, createHotkeySequence, createHotkeySequenceRecorder, createHotkeySequences, createHotkeys, createKeyHold, useDefaultHotkeysOptions, useHotkeysContext };
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,10 @@ import { createHeldKeys } from "./createHeldKeys.js";
|
|
|
5
5
|
import { createHeldKeyCodes } from "./createHeldKeyCodes.js";
|
|
6
6
|
import { createKeyHold } from "./createKeyHold.js";
|
|
7
7
|
import { createHotkeySequence } from "./createHotkeySequence.js";
|
|
8
|
+
import { createHotkeySequences } from "./createHotkeySequences.js";
|
|
8
9
|
import { createHotkeyRecorder } from "./createHotkeyRecorder.js";
|
|
10
|
+
import { createHotkeySequenceRecorder } from "./createHotkeySequenceRecorder.js";
|
|
9
11
|
|
|
10
12
|
export * from "@tanstack/hotkeys"
|
|
11
13
|
|
|
12
|
-
export { HotkeysProvider, createHeldKeyCodes, createHeldKeys, createHotkey, createHotkeyRecorder, createHotkeySequence, createHotkeys, createKeyHold, useDefaultHotkeysOptions, useHotkeysContext };
|
|
14
|
+
export { HotkeysProvider, createHeldKeyCodes, createHeldKeys, createHotkey, createHotkeyRecorder, createHotkeySequence, createHotkeySequenceRecorder, createHotkeySequences, createHotkeys, createKeyHold, useDefaultHotkeysOptions, useHotkeysContext };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/solid-hotkeys",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "SolidJS adapter for TanStack Hotkeys",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@tanstack/solid-store": "^0.9.2",
|
|
46
|
-
"@tanstack/hotkeys": "0.
|
|
46
|
+
"@tanstack/hotkeys": "0.5.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@solidjs/testing-library": "^0.8.10",
|
package/src/HotkeysProvider.tsx
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { createContext, useContext } from 'solid-js'
|
|
2
2
|
import type { JSX, ParentComponent } from 'solid-js'
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
HotkeyRecorderOptions,
|
|
5
|
+
HotkeySequenceRecorderOptions,
|
|
6
|
+
} from '@tanstack/hotkeys'
|
|
4
7
|
import type { CreateHotkeyOptions } from './createHotkey'
|
|
5
8
|
import type { CreateHotkeySequenceOptions } from './createHotkeySequence'
|
|
6
9
|
|
|
7
10
|
export interface HotkeysProviderOptions {
|
|
8
11
|
hotkey?: Partial<CreateHotkeyOptions>
|
|
9
12
|
hotkeyRecorder?: Partial<HotkeyRecorderOptions>
|
|
13
|
+
hotkeySequenceRecorder?: Partial<HotkeySequenceRecorderOptions>
|
|
10
14
|
hotkeySequence?: Partial<CreateHotkeySequenceOptions>
|
|
11
15
|
}
|
|
12
16
|
|
package/src/createHotkey.ts
CHANGED
|
@@ -89,6 +89,17 @@ export function createHotkey(
|
|
|
89
89
|
const manager = getHotkeyManager()
|
|
90
90
|
|
|
91
91
|
let registration: HotkeyRegistrationHandle | null = null
|
|
92
|
+
let lastHotkeyString: Hotkey | null = null
|
|
93
|
+
let lastTarget: HTMLElement | Document | Window | null = null
|
|
94
|
+
|
|
95
|
+
onCleanup(() => {
|
|
96
|
+
if (registration?.isActive) {
|
|
97
|
+
registration.unregister()
|
|
98
|
+
registration = null
|
|
99
|
+
}
|
|
100
|
+
lastHotkeyString = null
|
|
101
|
+
lastTarget = null
|
|
102
|
+
})
|
|
92
103
|
|
|
93
104
|
createEffect(() => {
|
|
94
105
|
// Resolve reactive values
|
|
@@ -119,36 +130,44 @@ export function createHotkey(
|
|
|
119
130
|
: null
|
|
120
131
|
|
|
121
132
|
if (!resolvedTarget) {
|
|
133
|
+
if (registration?.isActive) {
|
|
134
|
+
registration.unregister()
|
|
135
|
+
registration = null
|
|
136
|
+
}
|
|
137
|
+
lastHotkeyString = null
|
|
138
|
+
lastTarget = null
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Extract options without target (target is handled separately)
|
|
143
|
+
const { target: _target, ...optionsWithoutTarget } = mergedOptions
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
registration?.isActive &&
|
|
147
|
+
lastHotkeyString === hotkeyString &&
|
|
148
|
+
lastTarget === resolvedTarget
|
|
149
|
+
) {
|
|
150
|
+
registration.callback = callback
|
|
151
|
+
registration.setOptions(optionsWithoutTarget)
|
|
122
152
|
return
|
|
123
153
|
}
|
|
124
154
|
|
|
125
|
-
// Unregister previous registration if it exists
|
|
126
155
|
if (registration?.isActive) {
|
|
127
156
|
registration.unregister()
|
|
128
157
|
registration = null
|
|
129
158
|
}
|
|
130
159
|
|
|
131
|
-
// Extract options without target (target is handled separately)
|
|
132
|
-
const { target: _target, ...optionsWithoutTarget } = mergedOptions
|
|
133
|
-
|
|
134
|
-
// Register the hotkey
|
|
135
160
|
registration = manager.register(hotkeyString, callback, {
|
|
136
161
|
...optionsWithoutTarget,
|
|
137
162
|
target: resolvedTarget,
|
|
138
163
|
})
|
|
139
164
|
|
|
140
|
-
// Update callback and options on every effect run
|
|
141
165
|
if (registration.isActive) {
|
|
142
166
|
registration.callback = callback
|
|
143
167
|
registration.setOptions(optionsWithoutTarget)
|
|
144
168
|
}
|
|
145
169
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (registration?.isActive) {
|
|
149
|
-
registration.unregister()
|
|
150
|
-
registration = null
|
|
151
|
-
}
|
|
152
|
-
})
|
|
170
|
+
lastHotkeyString = hotkeyString
|
|
171
|
+
lastTarget = resolvedTarget
|
|
153
172
|
})
|
|
154
173
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createEffect, onCleanup } from 'solid-js'
|
|
2
|
-
import { getSequenceManager } from '@tanstack/hotkeys'
|
|
2
|
+
import { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'
|
|
3
3
|
import { useDefaultHotkeysOptions } from './HotkeysProvider'
|
|
4
4
|
import type {
|
|
5
5
|
HotkeyCallback,
|
|
@@ -72,6 +72,17 @@ export function createHotkeySequence(
|
|
|
72
72
|
const manager = getSequenceManager()
|
|
73
73
|
|
|
74
74
|
let registration: SequenceRegistrationHandle | null = null
|
|
75
|
+
let lastSequenceKey: string | null = null
|
|
76
|
+
let lastTarget: HTMLElement | Document | Window | null = null
|
|
77
|
+
|
|
78
|
+
onCleanup(() => {
|
|
79
|
+
if (registration?.isActive) {
|
|
80
|
+
registration.unregister()
|
|
81
|
+
registration = null
|
|
82
|
+
}
|
|
83
|
+
lastSequenceKey = null
|
|
84
|
+
lastTarget = null
|
|
85
|
+
})
|
|
75
86
|
|
|
76
87
|
createEffect(() => {
|
|
77
88
|
// Resolve reactive values
|
|
@@ -87,10 +98,6 @@ export function createHotkeySequence(
|
|
|
87
98
|
// Extract options without target (target is handled separately)
|
|
88
99
|
const { target: _target, ...optionsWithoutTarget } = mergedOptions
|
|
89
100
|
|
|
90
|
-
if (resolvedSequence.length === 0) {
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
|
|
94
101
|
// Resolve target: when explicitly provided (even as null), use it and skip if null.
|
|
95
102
|
// When not provided, default to document. Matches createHotkey.
|
|
96
103
|
const resolvedTarget =
|
|
@@ -100,34 +107,44 @@ export function createHotkeySequence(
|
|
|
100
107
|
? document
|
|
101
108
|
: null
|
|
102
109
|
|
|
103
|
-
if (!resolvedTarget) {
|
|
110
|
+
if (resolvedSequence.length === 0 || !resolvedTarget) {
|
|
111
|
+
if (registration?.isActive) {
|
|
112
|
+
registration.unregister()
|
|
113
|
+
registration = null
|
|
114
|
+
}
|
|
115
|
+
lastSequenceKey = null
|
|
116
|
+
lastTarget = null
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const sequenceKey = formatHotkeySequence(resolvedSequence)
|
|
121
|
+
|
|
122
|
+
if (
|
|
123
|
+
registration?.isActive &&
|
|
124
|
+
lastSequenceKey === sequenceKey &&
|
|
125
|
+
lastTarget === resolvedTarget
|
|
126
|
+
) {
|
|
127
|
+
registration.callback = callback
|
|
128
|
+
registration.setOptions(optionsWithoutTarget)
|
|
104
129
|
return
|
|
105
130
|
}
|
|
106
131
|
|
|
107
|
-
// Unregister previous registration if it exists
|
|
108
132
|
if (registration?.isActive) {
|
|
109
133
|
registration.unregister()
|
|
110
134
|
registration = null
|
|
111
135
|
}
|
|
112
136
|
|
|
113
|
-
// Register the sequence
|
|
114
137
|
registration = manager.register(resolvedSequence, callback, {
|
|
115
138
|
...mergedOptions,
|
|
116
139
|
target: resolvedTarget,
|
|
117
140
|
})
|
|
118
141
|
|
|
119
|
-
// Sync callback and options on every effect run
|
|
120
142
|
if (registration.isActive) {
|
|
121
143
|
registration.callback = callback
|
|
122
144
|
registration.setOptions(optionsWithoutTarget)
|
|
123
145
|
}
|
|
124
146
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (registration?.isActive) {
|
|
128
|
-
registration.unregister()
|
|
129
|
-
registration = null
|
|
130
|
-
}
|
|
131
|
-
})
|
|
147
|
+
lastSequenceKey = sequenceKey
|
|
148
|
+
lastTarget = resolvedTarget
|
|
132
149
|
})
|
|
133
150
|
}
|