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.
Files changed (57) hide show
  1. package/README.md +254 -96
  2. package/dist/{hotkeys.d.ts → core/hotkeys.d.ts} +88 -37
  3. package/dist/core/hotkeys.d.ts.map +1 -0
  4. package/dist/{hotkeys.js → core/hotkeys.js} +229 -97
  5. package/dist/core/hotkeys.js.map +1 -0
  6. package/dist/{hotkeys.test.d.ts.map → core/hotkeys.test.d.ts.map} +1 -1
  7. package/dist/{hotkeys.test.js → core/hotkeys.test.js} +403 -238
  8. package/dist/core/hotkeys.test.js.map +1 -0
  9. package/dist/core/index.d.ts.map +1 -0
  10. package/dist/{index.js → core/index.js} +1 -0
  11. package/dist/core/index.js.map +1 -0
  12. package/dist/{keys.d.ts → core/keys.d.ts} +6 -0
  13. package/dist/core/keys.d.ts.map +1 -0
  14. package/dist/{keys.js → core/keys.js} +22 -0
  15. package/dist/core/keys.js.map +1 -0
  16. package/dist/core/testutils.d.ts +17 -0
  17. package/dist/core/testutils.d.ts.map +1 -0
  18. package/dist/core/testutils.js +35 -0
  19. package/dist/core/testutils.js.map +1 -0
  20. package/dist/integrations/react/index.d.ts +3 -0
  21. package/dist/integrations/react/index.d.ts.map +1 -0
  22. package/dist/integrations/react/index.js +3 -0
  23. package/dist/integrations/react/index.js.map +1 -0
  24. package/dist/integrations/react/provider.d.ts +42 -0
  25. package/dist/integrations/react/provider.d.ts.map +1 -0
  26. package/dist/integrations/react/provider.js +134 -0
  27. package/dist/integrations/react/provider.js.map +1 -0
  28. package/dist/integrations/react/useEventCallback.d.ts +14 -0
  29. package/dist/integrations/react/useEventCallback.d.ts.map +1 -0
  30. package/dist/integrations/react/useEventCallback.js +32 -0
  31. package/dist/integrations/react/useEventCallback.js.map +1 -0
  32. package/dist/integrations/react/useHotkeys.d.ts +43 -0
  33. package/dist/integrations/react/useHotkeys.d.ts.map +1 -0
  34. package/dist/integrations/react/useHotkeys.js +76 -0
  35. package/dist/integrations/react/useHotkeys.js.map +1 -0
  36. package/dist/integrations/react/useIsomorphicLayoutEffect.d.ts +3 -0
  37. package/dist/integrations/react/useIsomorphicLayoutEffect.d.ts.map +1 -0
  38. package/dist/integrations/react/useIsomorphicLayoutEffect.js +3 -0
  39. package/dist/integrations/react/useIsomorphicLayoutEffect.js.map +1 -0
  40. package/package.json +19 -8
  41. package/dist/hotkeys.d.ts.map +0 -1
  42. package/dist/index.d.ts.map +0 -1
  43. package/dist/keys.d.ts.map +0 -1
  44. package/dist/testutils.d.ts +0 -14
  45. package/dist/testutils.d.ts.map +0 -1
  46. package/dist/testutils.js +0 -31
  47. package/dist/tt.d.ts +0 -125
  48. package/dist/tt.d.ts.map +0 -1
  49. package/dist/tt.js +0 -384
  50. package/dist/ttt.d.ts +0 -164
  51. package/dist/ttt.d.ts.map +0 -1
  52. package/dist/ttt.js +0 -439
  53. package/dist/tttt.d.ts +0 -67
  54. package/dist/tttt.d.ts.map +0 -1
  55. package/dist/tttt.js +0 -301
  56. /package/dist/{hotkeys.test.d.ts → core/hotkeys.test.d.ts} +0 -0
  57. /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 using rxjs
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`) and complex key sequences (e.g., `g` -> `i` for "go to inbox"). It supports contexts for enabling/disabling shortcuts based on application state, and provides a type-safe way to define keys using standard `KeyboardEvent.key` values.
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
- * **Key Combinations:** Define shortcuts that trigger when a specific key and modifier keys (Ctrl, Alt, Shift, Meta) are pressed simultaneously.
8
- * **Key Sequences:** Define shortcuts that trigger when a series of keys are pressed in a specific order.
9
- * **Sequence Timeouts:** Optional timeout between key presses in a sequence to prevent accidental triggers or indefinite waiting.
10
- * **Context Management:** Activate or deactivate groups of shortcuts based on the application's current state (e.g., "editor", "modal", "global").
11
- * **Strict Global Shortcuts:** Option to register global shortcuts that *only* fire when no other context is active, preventing them from triggering unintentionally.
12
- * **Type-Safe Key Definitions:** Uses an exported `Keys` object based on standard `KeyboardEvent.key` values for improved developer experience and fewer errors.
13
- * **RxJS Powered:** Built on RxJS for robust and efficient event handling.
14
- * **Prevent Default:** Option to prevent the default browser action for a triggered shortcut.
15
- * **Debug Mode:** Optional logging for easier development and troubleshooting.
16
- * **Clean API:** Simple and intuitive methods for adding, removing, and managing shortcuts.
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 `rx-hotkeys` library and its helper Keys imported:
62
+ First, ensure you have the `Hotkeys` class and its helper `Keys` object imported:
28
63
 
29
64
  ```typescript
30
- import { Hotkeys, Keys, KeyCombinationConfig, KeySequenceConfig } from 'rx-hotkeys';
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
- // With an initial context and debug mode enabled:
41
- // const keyManager = new Hotkeys('editor', true);
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 saveConfig: KeyCombinationConfig = {
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 's' key
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
- keyManager.addCombination(saveConfig);
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
- ### 3. Add a Key Sequence
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 konamiConfig: KeySequenceConfig = {
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
- keyManager.addSequence(konamiConfig);
123
+ konami$.subscribe((event) => { // The last KeyboardEvent of the sequence is emitted
124
+ console.log("Konami code entered!");
125
+ });
85
126
  ```
86
127
 
87
- ### 4. Manage Contexts
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
- #### Global vs. Strict Global Shortcuts
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
- Global shortcuts (those without a `context` property) have two behaviors:
162
+ ```typescript
163
+ // In a component lifecycle cleanup method or similar:
164
+ keyManager.destroy();
165
+ ```
102
166
 
103
- * **Default Global**: By default, a global shortcut will fire in *any* context, unless a more specific shortcut for the same key combination exists for that context.
167
+ ---
104
168
 
105
- ```typescript
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
- ```typescript
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
- ### 5. Clean Up
173
+ ### Step 1: Wrap Your App with `HotkeysProvider`
118
174
 
119
- When the Hotkeys instance is no longer needed (e.g., component unmount), call `destroy()` to clean up subscriptions and prevent memory leaks.
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
- ```typescript
122
- // In a component lifecycle cleanup method or similar:
123
- keyManager.destroy();
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, Keys.ArrowUp, Keys.A). It's highly recommended to use these when defining key in `KeyCombinationConfig` or keys in the sequence array of `KeySequenceConfig`.
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): string | undefined`
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
- * `config`: The KeyCombinationConfig object.
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
- * `config`: The KeySequenceConfig object.
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 (no context) will trigger.
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: { key: StandardKey; ctrlKey?: boolean; altKey?: boolean; shiftKey?: boolean; metaKey?: boolean; } | StandardKey | Array<{ key: StandardKey; ctrlKey?: boolean; altKey?: boolean; shiftKey?: boolean; metaKey?: boolean; } | StandardKey>` (required): Defines the main key (from Keys) and optional modifier 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, `event.preventDefault()` will be called when the shortcut triggers. Defaults to `false`.
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 (from `Keys`) representing the key sequence.
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, `event.preventDefault()` is called for the last event in the sequence. Defaults to `false`.
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. If exceeded, the sequence resets. If `0` or `undefined`, no inter-key timeout is applied (uses simpler buffer-based matching).
207
- * `strict?: boolean` (optional): If `true` and the shortcut has no `context`, it will only fire when no other context is active. Defaults to `false`.
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
- ## Key Matching Logic
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
- * **Single Character Keys** (e.g., `Keys.A`, `Keys.Digit7`): When you configure a shortcut with a single character key from `Keys`, the library matches it case-insensitively against the `event.key` from the browser. For example, if you configure `Keys.A`, it will trigger for both "a" and "A" key presses (assuming Shift isn't a required modifier).
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. Clone the repository.
222
- 2. Install dependencies: `npm install`.
223
- 3. Run tests: `npm test`.
381
+ 1. Clone the repository.
382
+ 2. Install dependencies: `npm install`.
383
+ 3. Run tests: `npm test`.
224
384
 
225
- # License
385
+ ## License
226
386
 
227
387
  This project is licensed under the MIT License.
228
-
229
- Powered by AI