rx-hotkeys 2.6.1 → 3.1.1
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/README.md +254 -96
- package/dist/{hotkeys.d.ts → core/hotkeys.d.ts} +88 -37
- package/dist/core/hotkeys.d.ts.map +1 -0
- package/dist/{hotkeys.js → core/hotkeys.js} +229 -97
- package/dist/core/hotkeys.js.map +1 -0
- package/dist/{hotkeys.test.d.ts.map → core/hotkeys.test.d.ts.map} +1 -1
- package/dist/{hotkeys.test.js → core/hotkeys.test.js} +403 -238
- package/dist/core/hotkeys.test.js.map +1 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/{index.js → core/index.js} +1 -0
- package/dist/core/index.js.map +1 -0
- package/dist/{keys.d.ts → core/keys.d.ts} +6 -0
- package/dist/core/keys.d.ts.map +1 -0
- package/dist/{keys.js → core/keys.js} +22 -0
- package/dist/core/keys.js.map +1 -0
- package/dist/core/testutils.d.ts +17 -0
- package/dist/core/testutils.d.ts.map +1 -0
- package/dist/core/testutils.js +35 -0
- package/dist/core/testutils.js.map +1 -0
- package/dist/integrations/react/index.d.ts +3 -0
- package/dist/integrations/react/index.d.ts.map +1 -0
- package/dist/integrations/react/index.js +3 -0
- package/dist/integrations/react/index.js.map +1 -0
- package/dist/integrations/react/provider.d.ts +42 -0
- package/dist/integrations/react/provider.d.ts.map +1 -0
- package/dist/integrations/react/provider.js +134 -0
- package/dist/integrations/react/provider.js.map +1 -0
- package/dist/integrations/react/useEventCallback.d.ts +14 -0
- package/dist/integrations/react/useEventCallback.d.ts.map +1 -0
- package/dist/integrations/react/useEventCallback.js +32 -0
- package/dist/integrations/react/useEventCallback.js.map +1 -0
- package/dist/integrations/react/useHotkeys.d.ts +43 -0
- package/dist/integrations/react/useHotkeys.d.ts.map +1 -0
- package/dist/integrations/react/useHotkeys.js +76 -0
- package/dist/integrations/react/useHotkeys.js.map +1 -0
- package/dist/integrations/react/useIsomorphicLayoutEffect.d.ts +3 -0
- package/dist/integrations/react/useIsomorphicLayoutEffect.d.ts.map +1 -0
- package/dist/integrations/react/useIsomorphicLayoutEffect.js +3 -0
- package/dist/integrations/react/useIsomorphicLayoutEffect.js.map +1 -0
- package/package.json +19 -8
- package/dist/hotkeys.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/keys.d.ts.map +0 -1
- package/dist/testutils.d.ts +0 -14
- package/dist/testutils.d.ts.map +0 -1
- package/dist/testutils.js +0 -31
- package/dist/tt.d.ts +0 -125
- package/dist/tt.d.ts.map +0 -1
- package/dist/tt.js +0 -384
- package/dist/ttt.d.ts +0 -164
- package/dist/ttt.d.ts.map +0 -1
- package/dist/ttt.js +0 -439
- package/dist/tttt.d.ts +0 -67
- package/dist/tttt.d.ts.map +0 -1
- package/dist/tttt.js +0 -301
- /package/dist/{hotkeys.test.d.ts → core/hotkeys.test.d.ts} +0 -0
- /package/dist/{index.d.ts → core/index.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
# rx-hotkeys: Advanced Keyboard Shortcut Management
|
|
1
|
+
# rx-hotkeys: Advanced Keyboard Shortcut Management with RxJS
|
|
2
2
|
|
|
3
|
-
rx-hotkeys is a powerful and flexible TypeScript library for managing keyboard shortcuts in web applications. It leverages RxJS to handle keyboard events, allowing for the registration of simple key combinations (e.g., `Ctrl+S`)
|
|
3
|
+
rx-hotkeys is a powerful and flexible TypeScript library for managing keyboard shortcuts in web applications. It leverages the full power of RxJS to handle keyboard events, allowing for the registration of simple key combinations (e.g., `Ctrl+S`), complex key sequences (e.g., `g` -> `i` for "go to inbox"), and much more. It supports contexts for enabling/disabling shortcuts based on application state, element-scoped listeners, and provides a type-safe API for defining shortcuts.
|
|
4
4
|
|
|
5
|
-
## Features
|
|
5
|
+
## ✨ Features
|
|
6
6
|
|
|
7
|
-
* **
|
|
8
|
-
* **
|
|
9
|
-
* **
|
|
10
|
-
* **
|
|
11
|
-
*
|
|
12
|
-
* **
|
|
13
|
-
* **
|
|
14
|
-
* **
|
|
15
|
-
* **
|
|
16
|
-
* **
|
|
7
|
+
* **Official React Hooks**: Provides an official wrapper (`HotkeysProvider`, `useHotkeys`) for seamless, idiomatic integration with React.
|
|
8
|
+
* **Fully Observable API**: Returns an RxJS `Observable` for each shortcut, allowing for powerful stream manipulation like chaining, filtering, debouncing, and merging with other streams.
|
|
9
|
+
* **Flexible Shortcut Definitions**: Define shortcuts using simple, intuitive strings (e.g., `"ctrl+s"` or `"g -> i"`) in addition to the classic object-based configuration.
|
|
10
|
+
* **Element-Scoped Listeners**: Attach shortcuts to specific DOM elements, so they are only active within a certain component or area, not just on the global `document`.
|
|
11
|
+
* **`keyup` Event Support**: Trigger actions on key release (`keyup`) in addition to the default key press (`keydown`).
|
|
12
|
+
* **Key Combinations & Sequences**: Supports both simultaneous key presses (`Ctrl+S`) and ordered key sequences (`g` -> `c`).
|
|
13
|
+
* **Context Management**: Activate or deactivate groups of shortcuts based on the application's current state (e.g., "editor", "modal", "global").
|
|
14
|
+
* **Strict Global Shortcuts**: Option to register global shortcuts that *only* fire when no other context is active.
|
|
15
|
+
* **Type-Safe Key Definitions**: Uses an exported `Keys` object based on standard `KeyboardEvent.key` values for a superior developer experience and fewer errors.
|
|
16
|
+
* **Sequence Timeouts**: Optional timeout between key presses in a sequence to prevent accidental triggers.
|
|
17
|
+
* **Debug Mode**: Optional, detailed console logging for easier development and troubleshooting.
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
@@ -21,13 +22,47 @@ rx-hotkeys is a powerful and flexible TypeScript library for managing keyboard s
|
|
|
21
22
|
npm install rxjs rx-hotkeys
|
|
22
23
|
```
|
|
23
24
|
|
|
25
|
+
## ⚠️ Breaking Changes (v3.0+)
|
|
26
|
+
|
|
27
|
+
Starting with v3.0, the API has been significantly updated for a more powerful and idiomatic RxJS experience. This is a major breaking change.
|
|
28
|
+
|
|
29
|
+
* `addCombination` and `addSequence` no longer accept a `callback` property in their configuration.
|
|
30
|
+
* They now return an **`Observable<KeyboardEvent>`**.
|
|
31
|
+
* You **must** now call `.subscribe()` on the returned Observable to execute your action.
|
|
32
|
+
|
|
33
|
+
**Migration Example:**
|
|
34
|
+
|
|
35
|
+
**Old (v2.x):**
|
|
36
|
+
```typescript
|
|
37
|
+
// The old way
|
|
38
|
+
keyManager.addCombination({
|
|
39
|
+
id: "save",
|
|
40
|
+
keys: { key: Keys.S, ctrlKey: true },
|
|
41
|
+
callback: () => console.log("File saved!"),
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**New (v3.0+):**
|
|
46
|
+
```typescript
|
|
47
|
+
// The new, observable-based way
|
|
48
|
+
const save$ = keyManager.addCombination({
|
|
49
|
+
id: "save",
|
|
50
|
+
keys: { key: Keys.S, ctrlKey: true }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const subscription = save$.subscribe(() => console.log("File saved!"));
|
|
54
|
+
|
|
55
|
+
// Don't forget to unsubscribe when your component is destroyed!
|
|
56
|
+
// The stream will also complete automatically if the shortcut is removed or keyManager.destroy() is called.
|
|
57
|
+
// subscription.unsubscribe();
|
|
58
|
+
```
|
|
24
59
|
|
|
25
60
|
## Basic Usage
|
|
26
61
|
|
|
27
|
-
First, ensure you have the `
|
|
62
|
+
First, ensure you have the `Hotkeys` class and its helper `Keys` object imported:
|
|
28
63
|
|
|
29
64
|
```typescript
|
|
30
|
-
import { Hotkeys, Keys
|
|
65
|
+
import { Hotkeys, Keys } from "rx-hotkeys";
|
|
31
66
|
```
|
|
32
67
|
|
|
33
68
|
### 1. Initialize Hotkeys
|
|
@@ -37,54 +72,78 @@ Create an instance of the `Hotkeys` class. You can optionally provide an initial
|
|
|
37
72
|
```typescript
|
|
38
73
|
const keyManager = new Hotkeys(); // No initial context, debug mode off
|
|
39
74
|
|
|
40
|
-
//
|
|
41
|
-
// const keyManager = new Hotkeys(
|
|
75
|
+
// Or with an initial context and debug mode enabled:
|
|
76
|
+
// const keyManager = new Hotkeys("editor", true);
|
|
42
77
|
```
|
|
43
78
|
|
|
44
79
|
### 2. Add a Key Combination
|
|
45
80
|
|
|
46
|
-
Register a shortcut for a key combination, like Ctrl+S.
|
|
81
|
+
Register a shortcut for a key combination, like `Ctrl+S`, by subscribing to the returned Observable.
|
|
47
82
|
|
|
48
83
|
```typescript
|
|
49
|
-
const
|
|
84
|
+
const save$ = keyManager.addCombination({
|
|
50
85
|
id: "saveFile", // Unique ID for this shortcut
|
|
51
|
-
keys: { key: Keys.S, ctrlKey: true }, // Use Keys.S for
|
|
52
|
-
callback: () => {
|
|
53
|
-
console.log("Ctrl+S pressed: Save file action triggered!");
|
|
54
|
-
},
|
|
86
|
+
keys: { key: Keys.S, ctrlKey: true }, // Use Keys.S for "s" key
|
|
55
87
|
preventDefault: true, // Prevent browser's default save action
|
|
56
88
|
description: "Save the current file."
|
|
57
|
-
};
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const saveSubscription = save$.subscribe((event) => {
|
|
92
|
+
console.log("Ctrl+S pressed: Save file action triggered!", event);
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 3. Define Shortcuts with Strings (New)
|
|
58
97
|
|
|
59
|
-
|
|
98
|
+
You can also use more concise strings to define shortcuts.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Combination
|
|
102
|
+
const open$ = keyManager.addCombination({ id: "openFile", keys: "ctrl+o" });
|
|
103
|
+
open$.subscribe(() => console.log("Opening file..."));
|
|
104
|
+
|
|
105
|
+
// Sequence
|
|
106
|
+
const command$ = keyManager.addSequence({ id: "showCommandPalette", sequence: "cmd+k" }); // Note: "cmd+k" is a combination, not a sequence. Let's fix this example.
|
|
107
|
+
const command$ = keyManager.addSequence({ id: "goToInbox", sequence: "g -> i" });
|
|
108
|
+
command$.subscribe(() => console.log("Navigating to Inbox..."));
|
|
60
109
|
```
|
|
61
110
|
|
|
62
|
-
###
|
|
111
|
+
### 4. Add a Key Sequence
|
|
63
112
|
|
|
64
113
|
Register a shortcut for a sequence of keys, like the Konami code.
|
|
65
114
|
|
|
66
115
|
```typescript
|
|
67
|
-
const
|
|
116
|
+
const konami$ = keyManager.addSequence({
|
|
68
117
|
id: "konamiCode",
|
|
69
|
-
sequence:
|
|
70
|
-
Keys.ArrowUp, Keys.ArrowUp,
|
|
71
|
-
Keys.ArrowDown, Keys.ArrowDown,
|
|
72
|
-
Keys.ArrowLeft, Keys.ArrowRight,
|
|
73
|
-
Keys.ArrowLeft, Keys.ArrowRight,
|
|
74
|
-
Keys.B, Keys.A // 'B' and 'A' from Keys
|
|
75
|
-
],
|
|
76
|
-
callback: (event) => { // The last KeyboardEvent of the sequence is passed
|
|
77
|
-
console.log("Konami code entered!");
|
|
78
|
-
// event.preventDefault(); // Can also be done here if not set in config
|
|
79
|
-
},
|
|
118
|
+
sequence: "up -> up -> down -> down -> left -> right -> left -> right -> b -> a",
|
|
80
119
|
sequenceTimeoutMs: 3000, // User has 3 seconds between each key press
|
|
81
120
|
description: "Unlock special features."
|
|
82
|
-
};
|
|
121
|
+
});
|
|
83
122
|
|
|
84
|
-
|
|
123
|
+
konami$.subscribe((event) => { // The last KeyboardEvent of the sequence is emitted
|
|
124
|
+
console.log("Konami code entered!");
|
|
125
|
+
});
|
|
85
126
|
```
|
|
86
127
|
|
|
87
|
-
###
|
|
128
|
+
### 5. Advanced Usage: Scopes and `keyup`
|
|
129
|
+
|
|
130
|
+
You can scope a shortcut to a specific element and trigger it on `keyup`.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const myInputField = document.getElementById("my-input");
|
|
134
|
+
|
|
135
|
+
const submit$ = keyManager.addCombination({
|
|
136
|
+
id: "submitOnEnter",
|
|
137
|
+
keys: Keys.Enter,
|
|
138
|
+
target: myInputField, // Only active on this element
|
|
139
|
+
event: "keyup", // Trigger on key release
|
|
140
|
+
preventDefault: true
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
submit$.subscribe(() => console.log("Form submitted on Enter keyup!"));
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 6. Manage Contexts
|
|
88
147
|
|
|
89
148
|
Control which shortcuts are active by setting the context.
|
|
90
149
|
|
|
@@ -96,80 +155,151 @@ keyManager.setContext("editor"); // Activates "editor" shortcuts and global shor
|
|
|
96
155
|
keyManager.setContext(null);
|
|
97
156
|
```
|
|
98
157
|
|
|
99
|
-
|
|
158
|
+
### 7. Clean Up
|
|
159
|
+
|
|
160
|
+
When the Hotkeys instance is no longer needed (e.g., component unmount), call `destroy()` to clean up all internal streams and listeners, preventing memory leaks. This will also `complete` all active shortcut Observables.
|
|
100
161
|
|
|
101
|
-
|
|
162
|
+
```typescript
|
|
163
|
+
// In a component lifecycle cleanup method or similar:
|
|
164
|
+
keyManager.destroy();
|
|
165
|
+
```
|
|
102
166
|
|
|
103
|
-
|
|
167
|
+
---
|
|
104
168
|
|
|
105
|
-
|
|
106
|
-
// This shortcut for Ctrl+P will fire in the "editor" context, "modal" context, or any other,
|
|
107
|
-
// unless a specific "editor" shortcut for Ctrl+P exists.
|
|
108
|
-
keyManager.addCombination({ id: 'globalPrint', keys: { key: Keys.P, ctrlKey: true }, callback: myCallback });
|
|
109
|
-
```
|
|
110
|
-
* **Strict Global**: By passing `true` as the second argument to `addCombination` or `addSequence`, you can register a "strict" global shortcut. This shortcut will **only** fire when no context is active (`keyManager.getContext()` returns `null`).
|
|
169
|
+
## Usage with React
|
|
111
170
|
|
|
112
|
-
|
|
113
|
-
// This help shortcut for "?" will ONLY fire when no other context is active.
|
|
114
|
-
keyManager.addCombination({ id: 'strictHelp', keys: Keys.QuestionMark, callback: openHelpModal, strict: true });
|
|
115
|
-
```
|
|
171
|
+
The library provides a dedicated React wrapper for the best developer experience.
|
|
116
172
|
|
|
117
|
-
###
|
|
173
|
+
### Step 1: Wrap Your App with `HotkeysProvider`
|
|
118
174
|
|
|
119
|
-
|
|
175
|
+
First, import `HotkeysProvider` and wrap your root application component with it. This creates a single, shared instance of the hotkeys manager for your entire app.
|
|
120
176
|
|
|
121
|
-
```
|
|
122
|
-
// In
|
|
123
|
-
|
|
177
|
+
```jsx
|
|
178
|
+
// In your main App.js or index.js
|
|
179
|
+
import React from 'react';
|
|
180
|
+
import ReactDOM from 'react-dom/client';
|
|
181
|
+
import { HotkeysProvider } from 'rx-hotkeys/react';
|
|
182
|
+
import App from './App';
|
|
183
|
+
|
|
184
|
+
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
185
|
+
root.render(
|
|
186
|
+
<React.StrictMode>
|
|
187
|
+
<HotkeysProvider debugMode={true}>
|
|
188
|
+
<App />
|
|
189
|
+
</HotkeysProvider>
|
|
190
|
+
</React.StrictMode>
|
|
191
|
+
);
|
|
124
192
|
```
|
|
125
193
|
|
|
194
|
+
### Step 2: Use the `useHotkeys` Hook in Your Components
|
|
195
|
+
|
|
196
|
+
Now, you can use the `useHotkeys` and `useSequence` hooks anywhere in your component tree. The hook automatically handles registration, cleanup, and stale closures. You no longer need to provide a dependency array for your callback.
|
|
197
|
+
|
|
198
|
+
```jsx
|
|
199
|
+
// src/components/Counter.jsx
|
|
200
|
+
import React, { useState } from 'react';
|
|
201
|
+
import { useHotkeys, useSequence } from 'rx-hotkeys/react';
|
|
202
|
+
|
|
203
|
+
export function Counter() {
|
|
204
|
+
const [count, setCount] = useState(0);
|
|
205
|
+
|
|
206
|
+
// The callback can safely use the latest component state (like `count`)
|
|
207
|
+
// without you needing to worry about stale closures or dependency arrays.
|
|
208
|
+
const handleIncrement = () => {
|
|
209
|
+
console.log(`Incrementing from ${count}...`);
|
|
210
|
+
setCount(count + 1);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Register '+' key to increment.
|
|
214
|
+
useHotkeys('+', handleIncrement);
|
|
215
|
+
|
|
216
|
+
// Register 'c' key to increment, with options.
|
|
217
|
+
useHotkeys('c', handleIncrement, { preventDefault: true });
|
|
218
|
+
|
|
219
|
+
// Register a sequence to reset the counter.
|
|
220
|
+
useSequence('r -> e -> s -> e -> t', () => {
|
|
221
|
+
console.log('Resetting counter!');
|
|
222
|
+
setCount(0);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<div>
|
|
227
|
+
<h2>Count: {count}</h2>
|
|
228
|
+
<p>Press '+' or 'c' to increment. Type 'reset' to reset.</p>
|
|
229
|
+
</div>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Step 3: Manage Context with `useScopedHotkeysContext`
|
|
235
|
+
|
|
236
|
+
This hook allows a component (like a modal) to activate a specific context only while it is mounted.
|
|
237
|
+
|
|
238
|
+
```jsx
|
|
239
|
+
// src/components/MyModal.jsx
|
|
240
|
+
import { useHotkeys, useScopedHotkeysContext } from 'rx-hotkeys/react';
|
|
241
|
+
|
|
242
|
+
export function MyModal({ onClose }) {
|
|
243
|
+
// This activates the 'modal' context for all children of this component.
|
|
244
|
+
// When MyModal unmounts, this context is automatically removed from the stack.
|
|
245
|
+
useScopedHotkeysContext('modal');
|
|
246
|
+
|
|
247
|
+
// This hotkey will only be active when the 'modal' context is active.
|
|
248
|
+
useHotkeys('escape', onClose, { context: 'modal' });
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<div className="modal">
|
|
252
|
+
<p>This is a modal. Press ESC to close.</p>
|
|
253
|
+
{/* ... other modal content ... */}
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
126
260
|
|
|
127
261
|
## API Reference
|
|
128
262
|
|
|
129
263
|
### `Keys` Object & `StandardKey` Type
|
|
130
264
|
|
|
131
|
-
* `Keys`: An exported constant object containing standard KeyboardEvent.key string values (e.g., Keys.Enter
|
|
132
|
-
* `StandardKey`: A TypeScript type representing any valid key string from the Keys object.
|
|
265
|
+
* `Keys`: An exported constant object containing standard `KeyboardEvent.key` string values (e.g., `Keys.Enter`, `Keys.ArrowUp`, `Keys.A`). It's highly recommended to use these for type safety and to avoid typos.
|
|
266
|
+
* `StandardKey`: A TypeScript type representing any valid key string from the `Keys` object.
|
|
133
267
|
|
|
134
|
-
### `Hotkeys` Class
|
|
268
|
+
### `Hotkeys` Class (Core)
|
|
135
269
|
|
|
136
270
|
`constructor(initialContext?: string | null, debugMode?: boolean)`
|
|
137
271
|
|
|
138
272
|
Creates a new Hotkeys instance.
|
|
139
273
|
|
|
140
|
-
`addCombination(config: KeyCombinationConfig):
|
|
274
|
+
`addCombination(config: KeyCombinationConfig): Observable<KeyboardEvent>`
|
|
141
275
|
|
|
142
276
|
Registers a key combination shortcut.
|
|
277
|
+
* `config`: The `KeyCombinationConfig` object.
|
|
278
|
+
* Returns an `Observable<KeyboardEvent>` that emits when the shortcut is triggered.
|
|
143
279
|
|
|
144
|
-
|
|
145
|
-
* Returns the shortcut ID if successful, undefined otherwise.
|
|
146
|
-
|
|
147
|
-
`addSequence(config: KeySequenceConfig): string | undefined`
|
|
280
|
+
`addSequence(config: KeySequenceConfig): Observable<KeyboardEvent>`
|
|
148
281
|
|
|
149
282
|
Registers a key sequence shortcut.
|
|
150
|
-
|
|
151
|
-
* `
|
|
152
|
-
* Returns the shortcut ID if successful, undefined otherwise.
|
|
283
|
+
* `config`: The `KeySequenceConfig` object.
|
|
284
|
+
* Returns an `Observable<KeyboardEvent>` that emits the final `KeyboardEvent` when the sequence is completed.
|
|
153
285
|
|
|
154
286
|
`setContext(contextName: string | null): boolean`
|
|
155
287
|
|
|
156
|
-
Sets the active context. Only shortcuts matching this context or global shortcuts
|
|
288
|
+
Sets the active context. Only shortcuts matching this context or global shortcuts will trigger.
|
|
157
289
|
|
|
158
290
|
`getContext(): string | null`
|
|
159
291
|
|
|
160
|
-
Returns the current active context name, or null
|
|
292
|
+
Returns the current active context name, or `null`.
|
|
161
293
|
|
|
162
294
|
`remove(id: string): boolean`
|
|
163
295
|
|
|
164
|
-
Removes a registered shortcut by its ID.
|
|
165
|
-
|
|
166
|
-
* Returns true if found and removed, false otherwise.
|
|
296
|
+
Removes a registered shortcut by its ID. This will cause the corresponding Observable to complete.
|
|
297
|
+
* Returns `true` if found and removed, `false` otherwise.
|
|
167
298
|
|
|
168
299
|
`hasShortcut(id: string): boolean`
|
|
169
300
|
|
|
170
301
|
Checks if a shortcut with the given ID is registered.
|
|
171
|
-
|
|
172
|
-
* Returns true if it exists, false otherwise.
|
|
302
|
+
* Returns `true` if it exists, `false` otherwise.
|
|
173
303
|
|
|
174
304
|
`getActiveShortcuts(): { id: string; description?: string; context?: string | null; type: "combination" | "sequence" }[]`
|
|
175
305
|
|
|
@@ -183,34 +313,64 @@ Enables or disables console logging for debug purposes.
|
|
|
183
313
|
|
|
184
314
|
Cleans up all subscriptions and resources. Essential to call to prevent memory leaks.
|
|
185
315
|
|
|
316
|
+
### React Hooks (`rx-hotkeys/react`)
|
|
317
|
+
|
|
318
|
+
`HotkeysProvider({ children, initialContext?, debugMode? })`
|
|
319
|
+
|
|
320
|
+
A React component that provides the Hotkeys instance to its children.
|
|
321
|
+
|
|
322
|
+
`useHotkeys(keys, callback, options?)`
|
|
323
|
+
|
|
324
|
+
A React hook to register a key combination.
|
|
325
|
+
* `keys: string | string[]`: The shortcut definition (e.g., `'ctrl+s'`).
|
|
326
|
+
* `callback: (event: KeyboardEvent) => void`: The function to execute.
|
|
327
|
+
* `options?: HotkeyHookOptions`: Optional config for `preventDefault`, `context`, `target`, etc.
|
|
328
|
+
|
|
329
|
+
`useSequence(sequence, callback, options?)`
|
|
330
|
+
|
|
331
|
+
A React hook to register a key sequence.
|
|
332
|
+
* `sequence: string | string[]`: The sequence definition (e.g., `'g -> i'`).
|
|
333
|
+
* `callback: (event: KeyboardEvent) => void`: The function to execute.
|
|
334
|
+
* `options?: SequenceHookOptions`: Optional config for `preventDefault`, `context`, etc.
|
|
335
|
+
|
|
336
|
+
`useScopedHotkeysContext(context)`
|
|
337
|
+
|
|
338
|
+
A React hook to apply a specific context for the lifetime of the component.
|
|
339
|
+
|
|
186
340
|
### Configuration Interfaces
|
|
187
341
|
|
|
188
|
-
`KeyCombinationConfig`
|
|
342
|
+
#### `KeyCombinationConfig`
|
|
189
343
|
|
|
190
344
|
* `id: string` (required): Unique identifier for the shortcut.
|
|
191
|
-
* `keys:
|
|
192
|
-
* `callback: (event: KeyboardEvent) => void` (required): Function to execute when the shortcut is triggered. The triggering `KeyboardEvent` is passed as an argument.
|
|
345
|
+
* `keys: string | KeyCombinationTrigger | KeyCombinationTrigger[]` (required): Defines the key(s). Can be a string (`"ctrl+s"`), a shorthand `StandardKey` (`Keys.Escape`), an object (`{ key: Keys.S, ctrlKey: true }`), or an array of these.
|
|
193
346
|
* `context?: string | null`: Specifies the context in which this shortcut is active. If `null` or `undefined`, it's a global shortcut.
|
|
194
|
-
* `preventDefault?: boolean`: If true
|
|
347
|
+
* `preventDefault?: boolean`: If `true`, `event.preventDefault()` will be called when the shortcut triggers. Defaults to `false`.
|
|
195
348
|
* `description?: string`: An optional description for the shortcut (e.g., for help menus).
|
|
196
349
|
* `strict?: boolean` (optional): If `true` and the shortcut has no `context`, it will only fire when no other context is active. Defaults to `false`.
|
|
350
|
+
* `target?: HTMLElement` (optional): The DOM element to attach the listener to. Defaults to `document`.
|
|
351
|
+
* `event?: "keydown" | "keyup"` (optional): The keyboard event to listen for. Defaults to `"keydown"`.
|
|
352
|
+
* `callback?: (event: KeyboardEvent) => void` (**@deprecated**): This property is deprecated. Subscribe to the `Observable` returned by `addCombination` instead.
|
|
197
353
|
|
|
198
|
-
`KeySequenceConfig`
|
|
354
|
+
#### `KeySequenceConfig`
|
|
199
355
|
|
|
200
356
|
* `id: string` (required): Unique identifier.
|
|
201
|
-
* `sequence: StandardKey[]` (required): An array of `StandardKey` values (
|
|
202
|
-
* `callback: (event: KeyboardEvent) => void` (required): Function to execute. The last `KeyboardEvent` of the sequence is passed.
|
|
357
|
+
* `sequence: string | StandardKey[]` (required): An array of `StandardKey` values or a string representation (e.g., `"g -> i"`).
|
|
203
358
|
* `context?: string | null`: Context for activation.
|
|
204
|
-
* `preventDefault?: boolean`: If true
|
|
359
|
+
* `preventDefault?: boolean`: If `true`, `event.preventDefault()` is called for the last event in the sequence. Defaults to `false`.
|
|
205
360
|
* `description?: string`: Optional description.
|
|
206
|
-
* `sequenceTimeoutMs?: number`: Optional. Maximum time (in milliseconds) allowed between consecutive key presses in the sequence.
|
|
207
|
-
* `strict?: boolean` (optional): If `true` and the shortcut has no `context`, it will only fire when no other context is active.
|
|
361
|
+
* `sequenceTimeoutMs?: number`: Optional. Maximum time (in milliseconds) allowed between consecutive key presses in the sequence.
|
|
362
|
+
* `strict?: boolean` (optional): If `true` and the shortcut has no `context`, it will only fire when no other context is active.
|
|
363
|
+
* `target?: HTMLElement` (optional): The DOM element to attach the listener to. Defaults to `document`.
|
|
364
|
+
* `event?: "keydown" | "keyup"` (optional): The keyboard event to listen for. Defaults to `"keydown"`.
|
|
365
|
+
* `callback?: (event: KeyboardEvent) => void` (**@deprecated**): This property is deprecated. Subscribe to the `Observable` returned by `addSequence` instead.
|
|
208
366
|
|
|
367
|
+
## Key Matching & Normalization
|
|
209
368
|
|
|
210
|
-
|
|
369
|
+
* **Case Insensitivity**: The library automatically handles case for you. `keys: "a"` will match both "a" and "A" presses. `keys: "escape"` will match an event where `event.key` is `"Escape"`.
|
|
370
|
+
* **Aliases**: Common aliases are supported in string definitions, such as `cmd` for `Meta`, `option` for `Alt`, and `esc` for `Escape`.
|
|
371
|
+
* **Special Keys**: For full type-safety, it is recommended to use the exported `Keys` object (e.g., `Keys.Enter`, `Keys.ArrowUp`).
|
|
211
372
|
|
|
212
|
-
|
|
213
|
-
* **Special Keys** (e.g., `Keys.Enter`, `Keys.ArrowUp`, `Keys.Escape`): These are multi-character `event.key` values. The library matches these case-sensitively against the `event.key`. Using the `Keys` object ensures you provide the correct, standard case-sensitive string.
|
|
373
|
+
---
|
|
214
374
|
|
|
215
375
|
## Contributing
|
|
216
376
|
|
|
@@ -218,12 +378,10 @@ Contributions are welcome! Please feel free to submit issues, fork the repositor
|
|
|
218
378
|
|
|
219
379
|
## Development Setup
|
|
220
380
|
|
|
221
|
-
1.
|
|
222
|
-
2.
|
|
223
|
-
3.
|
|
381
|
+
1. Clone the repository.
|
|
382
|
+
2. Install dependencies: `npm install`.
|
|
383
|
+
3. Run tests: `npm test`.
|
|
224
384
|
|
|
225
|
-
|
|
385
|
+
## License
|
|
226
386
|
|
|
227
387
|
This project is licensed under the MIT License.
|
|
228
|
-
|
|
229
|
-
Powered by AI
|