@tanstack/hotkeys 0.11.0 → 0.12.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/adapter.d.ts +108 -19
- package/dist/adapter.js +90 -65
- package/dist/app-hotkeys.d.ts +239 -0
- package/dist/app-hotkeys.js +295 -0
- package/dist/conflicts.d.ts +5 -9
- package/dist/conflicts.js +6 -11
- package/dist/format.d.ts +19 -24
- package/dist/format.js +19 -30
- package/dist/hint.d.ts +1 -0
- package/dist/hint.js +5 -2
- package/dist/hotkey-manager.d.ts +110 -59
- package/dist/hotkey-manager.js +254 -151
- package/dist/hotkey-recorder.d.ts +66 -42
- package/dist/hotkey-recorder.js +148 -107
- package/dist/hotkey.types.d.ts +26 -12
- package/dist/index.d.ts +10 -11
- package/dist/index.js +5 -6
- package/dist/match.d.ts +38 -5
- package/dist/match.js +72 -4
- package/dist/parse.d.ts +20 -8
- package/dist/parse.js +15 -5
- package/dist/recorder-options.d.ts +6 -3
- package/dist/validate.d.ts +10 -4
- package/dist/validate.js +26 -4
- package/package.json +1 -1
- package/dist/hotkey-sequence-recorder.d.ts +0 -84
- package/dist/hotkey-sequence-recorder.js +0 -259
- package/dist/sequence-manager.d.ts +0 -169
- package/dist/sequence-manager.js +0 -443
package/dist/hotkey-manager.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { ConflictBehavior,
|
|
1
|
+
import { ConflictBehavior, HotkeyCallback, HotkeyChord, HotkeyMeta, HotkeySequence, ParsedHotkey, RegisterableHotkey, RegisterableHotkeyChord } from "./hotkey.types.js";
|
|
2
|
+
import { AppHotkeysStore } from "./app-hotkeys.js";
|
|
2
3
|
import { Store } from "@tanstack/store";
|
|
3
4
|
//#region src/hotkey-manager.d.ts
|
|
5
|
+
/** An element, document, or window that hotkeys can listen on. */
|
|
6
|
+
export type Target = HTMLElement | Document | Window;
|
|
4
7
|
/**
|
|
5
|
-
* Options
|
|
8
|
+
* Options shared by chords and sequences.
|
|
6
9
|
*/
|
|
7
10
|
export interface HotkeyOptions {
|
|
8
11
|
/** Behavior when this hotkey conflicts with an existing registration on the same target. Defaults to 'warn' */
|
|
@@ -15,71 +18,103 @@ export interface HotkeyOptions {
|
|
|
15
18
|
enabled?: boolean;
|
|
16
19
|
/** The event type to listen for. Defaults to 'keydown' */
|
|
17
20
|
eventType?: 'keydown' | 'keyup';
|
|
18
|
-
/** Whether to ignore hotkeys when keyboard events originate from input-like elements (text inputs, textarea, select, contenteditable — button-type inputs like type=button/submit/reset are not ignored). Defaults based on hotkey: true for single keys and Shift/Alt combos; false for Ctrl/Meta shortcuts and Escape */
|
|
21
|
+
/** Whether to ignore hotkeys when keyboard events originate from input-like elements (text inputs, textarea, select, contenteditable — button-type inputs like type=button/submit/reset are not ignored). Defaults based on the hotkey (the first step of a sequence): true for single keys and Shift/Alt combos; false for Ctrl/Meta shortcuts and Escape */
|
|
19
22
|
ignoreInputs?: boolean;
|
|
20
23
|
/** The target platform for resolving 'Mod' */
|
|
21
24
|
platform?: 'mac' | 'windows' | 'linux';
|
|
22
25
|
/** Prevent the default browser action when the hotkey matches. Defaults to true */
|
|
23
26
|
preventDefault?: boolean;
|
|
24
|
-
/** If true, only trigger once until all keys are released. Default: false */
|
|
25
|
-
requireReset?: boolean;
|
|
26
27
|
/** Stop event propagation when the hotkey matches. Defaults to true */
|
|
27
28
|
stopPropagation?: boolean;
|
|
28
29
|
/** The DOM element to attach the event listener to. Defaults to document. */
|
|
29
|
-
target?:
|
|
30
|
+
target?: Target | null;
|
|
30
31
|
/** Optional metadata (name, description, custom fields via declaration merging) */
|
|
31
32
|
meta?: HotkeyMeta;
|
|
33
|
+
/** Id of the app hotkey this registration implements. Adapters set this when registering an app hotkey from `defineAppHotkeys`. */
|
|
34
|
+
appHotkeyId?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Options for a single chord such as `'Mod+S'`. */
|
|
37
|
+
export interface HotkeyChordOptions extends HotkeyOptions {
|
|
38
|
+
/** If true, only trigger once until all keys are released. Default: false */
|
|
39
|
+
requireReset?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** Options for a sequence such as `['G', 'G']`. */
|
|
42
|
+
export interface HotkeySequenceOptions extends HotkeyOptions {
|
|
43
|
+
/** Maximum time between steps in milliseconds. Default: 1000 */
|
|
44
|
+
timeout?: number;
|
|
32
45
|
}
|
|
33
46
|
/**
|
|
34
|
-
*
|
|
47
|
+
* The options type for a hotkey: chord options for chords (including one-step
|
|
48
|
+
* tuples), sequence options for sequences.
|
|
35
49
|
*/
|
|
36
|
-
export
|
|
50
|
+
export type HotkeyOptionsFor<T extends RegisterableHotkey> = [T] extends [never] ? HotkeyChordOptions & HotkeySequenceOptions : T extends readonly [RegisterableHotkeyChord] ? HotkeyChordOptions : T extends HotkeySequence ? HotkeySequenceOptions : HotkeyChordOptions;
|
|
51
|
+
interface RegistrationBase<TOptions extends HotkeyOptions> {
|
|
52
|
+
/** Unique identifier for this registration */
|
|
53
|
+
id: string;
|
|
37
54
|
/** The callback to invoke */
|
|
38
55
|
callback: HotkeyCallback;
|
|
39
|
-
/**
|
|
56
|
+
/** Resolved options for this registration */
|
|
57
|
+
options: TOptions;
|
|
58
|
+
/** The resolved target element for this registration */
|
|
59
|
+
target: Target;
|
|
60
|
+
/** How many times this registration's callback has been triggered */
|
|
61
|
+
triggerCount: number;
|
|
62
|
+
/** Whether this registration has fired (and, for requireReset chords, needs a reset) */
|
|
40
63
|
hasFired: boolean;
|
|
64
|
+
}
|
|
65
|
+
/** A registered chord in the HotkeyManager. */
|
|
66
|
+
export interface HotkeyChordRegistration extends RegistrationBase<HotkeyChordOptions> {
|
|
67
|
+
kind: 'chord';
|
|
68
|
+
hotkey: HotkeyChord;
|
|
69
|
+
parsedHotkey: ParsedHotkey;
|
|
41
70
|
/** The concrete key/code that activated a requireReset registration. */
|
|
42
71
|
activeMatch?: {
|
|
43
72
|
key: string;
|
|
44
73
|
code: string;
|
|
45
74
|
};
|
|
46
|
-
/** The original hotkey string */
|
|
47
|
-
hotkey: Hotkey;
|
|
48
|
-
/** Unique identifier for this registration */
|
|
49
|
-
id: string;
|
|
50
|
-
/** Options for this registration */
|
|
51
|
-
options: HotkeyOptions;
|
|
52
|
-
/** The parsed hotkey */
|
|
53
|
-
parsedHotkey: ParsedHotkey;
|
|
54
|
-
/** The resolved target element for this registration */
|
|
55
|
-
target: HTMLElement | Document | Window;
|
|
56
|
-
/** How many times this registration's callback has been triggered */
|
|
57
|
-
triggerCount: number;
|
|
58
75
|
}
|
|
59
|
-
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
/**
|
|
76
|
+
/** A registered sequence in the HotkeyManager. */
|
|
77
|
+
export interface HotkeySequenceRegistration extends RegistrationBase<HotkeySequenceOptions> {
|
|
78
|
+
kind: 'sequence';
|
|
79
|
+
hotkey: HotkeySequence;
|
|
80
|
+
parsedSequence: Array<ParsedHotkey>;
|
|
81
|
+
/** Steps matched in the current attempt */
|
|
82
|
+
currentIndex: number;
|
|
83
|
+
/** `Date.now()` when the last step in the current attempt matched */
|
|
84
|
+
lastKeyTime: number;
|
|
85
|
+
}
|
|
86
|
+
/** A registered hotkey in the HotkeyManager. */
|
|
87
|
+
export type HotkeyRegistration = HotkeyChordRegistration | HotkeySequenceRegistration;
|
|
88
|
+
interface RegistrationViewBase {
|
|
67
89
|
id: string;
|
|
68
|
-
|
|
69
|
-
options: HotkeyOptions;
|
|
70
|
-
/** The parsed hotkey */
|
|
71
|
-
parsedHotkey: ParsedHotkey;
|
|
72
|
-
/** The resolved target element for this registration */
|
|
73
|
-
target: HTMLElement | Document | Window;
|
|
74
|
-
/** How many times this registration's callback has been triggered */
|
|
90
|
+
target: Target;
|
|
75
91
|
triggerCount: number;
|
|
76
|
-
/** Whether this registration has fired and needs reset (for requireReset) */
|
|
77
92
|
hasFired: boolean;
|
|
78
93
|
}
|
|
94
|
+
/** Public view of a chord registration, without its callback. */
|
|
95
|
+
export interface HotkeyChordRegistrationView extends RegistrationViewBase {
|
|
96
|
+
kind: 'chord';
|
|
97
|
+
hotkey: HotkeyChord;
|
|
98
|
+
parsedHotkey: ParsedHotkey;
|
|
99
|
+
options: HotkeyChordOptions;
|
|
100
|
+
}
|
|
101
|
+
/** Public view of a sequence registration, without its callback. */
|
|
102
|
+
export interface HotkeySequenceRegistrationView extends RegistrationViewBase {
|
|
103
|
+
kind: 'sequence';
|
|
104
|
+
hotkey: HotkeySequence;
|
|
105
|
+
parsedSequence: Array<ParsedHotkey>;
|
|
106
|
+
options: HotkeySequenceOptions;
|
|
107
|
+
/** Steps matched in the current attempt (0 when idle or just completed). */
|
|
108
|
+
matchedStepCount: number;
|
|
109
|
+
/** `Date.now()` when the last step in the current attempt matched; 0 if none. */
|
|
110
|
+
partialMatchLastKeyTime: number;
|
|
111
|
+
}
|
|
79
112
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
113
|
+
* Public view of a hotkey registration for display and introspection.
|
|
114
|
+
* Narrow with `kind` to read chord- or sequence-specific fields.
|
|
82
115
|
*/
|
|
116
|
+
export type HotkeyRegistrationView = HotkeyChordRegistrationView | HotkeySequenceRegistrationView;
|
|
117
|
+
/** Creates a public view from an internal registration, stripping the callback. */
|
|
83
118
|
export declare function toHotkeyRegistrationView(reg: HotkeyRegistration): HotkeyRegistrationView;
|
|
84
119
|
/**
|
|
85
120
|
* A handle returned from HotkeyManager.register() that allows updating
|
|
@@ -95,16 +130,11 @@ export declare function toHotkeyRegistrationView(reg: HotkeyRegistration): Hotke
|
|
|
95
130
|
* // Update options without re-registering
|
|
96
131
|
* handle.setOptions({ enabled: false })
|
|
97
132
|
*
|
|
98
|
-
* // Check if still active
|
|
99
|
-
* if (handle.isActive) {
|
|
100
|
-
* // ...
|
|
101
|
-
* }
|
|
102
|
-
*
|
|
103
133
|
* // Unregister when done
|
|
104
134
|
* handle.unregister()
|
|
105
135
|
* ```
|
|
106
136
|
*/
|
|
107
|
-
export interface HotkeyRegistrationHandle {
|
|
137
|
+
export interface HotkeyRegistrationHandle<TOptions extends HotkeyOptions = HotkeyChordOptions | HotkeySequenceOptions> {
|
|
108
138
|
/**
|
|
109
139
|
* The callback function. Can be set directly to update without re-registering.
|
|
110
140
|
* This avoids stale closures when the callback references React state.
|
|
@@ -118,33 +148,40 @@ export interface HotkeyRegistrationHandle {
|
|
|
118
148
|
* Update options (merged with existing options).
|
|
119
149
|
* Useful for updating `enabled`, `preventDefault`, etc. without re-registering.
|
|
120
150
|
*/
|
|
121
|
-
setOptions: (options: Partial<
|
|
151
|
+
setOptions: (options: Partial<TOptions>) => void;
|
|
122
152
|
/** Unregister this hotkey */
|
|
123
153
|
unregister: () => void;
|
|
124
154
|
}
|
|
125
155
|
/**
|
|
126
|
-
* Singleton manager for hotkey registrations.
|
|
156
|
+
* Singleton manager for hotkey registrations, including sequences.
|
|
127
157
|
*
|
|
128
|
-
* This class provides a centralized way to register and manage keyboard
|
|
129
|
-
* It
|
|
130
|
-
* are registered.
|
|
158
|
+
* This class provides a centralized way to register and manage keyboard
|
|
159
|
+
* hotkeys. It attaches one keydown and one keyup listener per target,
|
|
160
|
+
* regardless of how many hotkeys are registered.
|
|
161
|
+
*
|
|
162
|
+
* Sequences (Vim-style hotkeys such as `['G', 'G']`) match when every step is
|
|
163
|
+
* pressed within the timeout. Modifier-only events (Shift, Control, Alt, or
|
|
164
|
+
* Meta alone) neither advance nor reset a sequence, so chained modifier chords
|
|
165
|
+
* such as `['Shift+R', 'Shift+T']` work.
|
|
131
166
|
*
|
|
132
167
|
* @example
|
|
133
168
|
* ```ts
|
|
134
169
|
* const manager = HotkeyManager.getInstance()
|
|
135
170
|
*
|
|
136
|
-
* const
|
|
171
|
+
* const save = manager.register('Mod+S', (event, context) => {
|
|
137
172
|
* console.log('Save triggered!')
|
|
138
173
|
* })
|
|
174
|
+
* const top = manager.register(['G', 'G'], () => scrollToTop(), { timeout: 500 })
|
|
139
175
|
*
|
|
140
176
|
* // Later, to unregister:
|
|
141
|
-
* unregister()
|
|
177
|
+
* save.unregister()
|
|
178
|
+
* top.unregister()
|
|
142
179
|
* ```
|
|
143
180
|
*/
|
|
144
181
|
export declare class HotkeyManager {
|
|
145
182
|
#private;
|
|
146
183
|
/**
|
|
147
|
-
* The TanStack Store containing all hotkey registrations.
|
|
184
|
+
* The TanStack Store containing all hotkey registrations, chords and sequences.
|
|
148
185
|
* Use this to subscribe to registration changes or access current registrations.
|
|
149
186
|
*
|
|
150
187
|
* @example
|
|
@@ -163,6 +200,11 @@ export declare class HotkeyManager {
|
|
|
163
200
|
* ```
|
|
164
201
|
*/
|
|
165
202
|
readonly registrations: Store<Map<string, HotkeyRegistration>>;
|
|
203
|
+
/**
|
|
204
|
+
* The app hotkeys store published by a framework provider, so tools such as
|
|
205
|
+
* devtools can list declared hotkeys that are not registered.
|
|
206
|
+
*/
|
|
207
|
+
readonly appHotkeys: Store<AppHotkeysStore | null>;
|
|
166
208
|
private constructor();
|
|
167
209
|
/**
|
|
168
210
|
* Gets the singleton instance of HotkeyManager.
|
|
@@ -175,10 +217,14 @@ export declare class HotkeyManager {
|
|
|
175
217
|
/**
|
|
176
218
|
* Registers a hotkey handler and returns a handle for updating the registration.
|
|
177
219
|
*
|
|
220
|
+
* Pass a chord (`'Mod+S'` or a RawHotkey object) or a sequence (`['G', 'G']`).
|
|
221
|
+
* A one-step sequence registers as its chord. Chords accept `requireReset`;
|
|
222
|
+
* sequences accept `timeout`.
|
|
223
|
+
*
|
|
178
224
|
* The returned handle allows updating the callback and options without
|
|
179
225
|
* re-registering, which is useful for avoiding stale closures in React.
|
|
180
226
|
*
|
|
181
|
-
* @param hotkey -
|
|
227
|
+
* @param hotkey - A chord string, RawHotkey object, or sequence
|
|
182
228
|
* @param callback - The function to call when the hotkey is pressed
|
|
183
229
|
* @param options - Options for the hotkey behavior
|
|
184
230
|
* @returns A handle for managing the registration
|
|
@@ -197,27 +243,32 @@ export declare class HotkeyManager {
|
|
|
197
243
|
* handle.unregister()
|
|
198
244
|
* ```
|
|
199
245
|
*/
|
|
200
|
-
register(hotkey:
|
|
246
|
+
register<T extends RegisterableHotkey>(hotkey: T, callback: HotkeyCallback, options?: HotkeyOptionsFor<T>): HotkeyRegistrationHandle<HotkeyOptionsFor<T>>;
|
|
247
|
+
/**
|
|
248
|
+
* Resets the progress of every in-progress sequence.
|
|
249
|
+
*/
|
|
250
|
+
resetSequenceProgress(): void;
|
|
201
251
|
/**
|
|
202
252
|
* Triggers a registration's callback programmatically from devtools.
|
|
203
|
-
* Creates a synthetic KeyboardEvent
|
|
253
|
+
* Creates a synthetic KeyboardEvent from the chord (or a sequence's last step)
|
|
254
|
+
* and invokes the callback.
|
|
204
255
|
*
|
|
205
256
|
* @param id - The registration ID to trigger
|
|
206
257
|
* @returns True if the registration was found and triggered
|
|
207
258
|
*/
|
|
208
259
|
triggerRegistration(id: string): boolean;
|
|
209
260
|
/**
|
|
210
|
-
* Gets the number of registered hotkeys.
|
|
261
|
+
* Gets the number of registered hotkeys, chords and sequences.
|
|
211
262
|
*/
|
|
212
263
|
getRegistrationCount(): number;
|
|
213
264
|
/**
|
|
214
265
|
* Checks if a specific hotkey is registered.
|
|
215
266
|
*
|
|
216
|
-
* @param hotkey - The
|
|
267
|
+
* @param hotkey - The chord or sequence to check
|
|
217
268
|
* @param target - Optional target element to match (if provided, both hotkey and target must match)
|
|
218
269
|
* @returns True if a matching registration exists
|
|
219
270
|
*/
|
|
220
|
-
isRegistered(hotkey:
|
|
271
|
+
isRegistered(hotkey: RegisterableHotkey, target?: Target): boolean;
|
|
221
272
|
/**
|
|
222
273
|
* Destroys the manager and removes all listeners.
|
|
223
274
|
*/
|