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
@@ -1,4 +1,4 @@
1
- import { Subscription, Observable } from "rxjs";
1
+ import { Observable, Subject } from "rxjs";
2
2
  import { type StandardKey } from "./keys.js";
3
3
  export declare enum ShortcutTypes {
4
4
  Combination = "combination",
@@ -6,7 +6,10 @@ export declare enum ShortcutTypes {
6
6
  }
7
7
  interface ShortcutConfigBase {
8
8
  id: string;
9
- callback: (event: KeyboardEvent) => void;
9
+ /**
10
+ * @deprecated The callback property is deprecated. `addCombination` and `addSequence` now return an Observable. Please subscribe to it instead.
11
+ */
12
+ callback?: (event: KeyboardEvent) => void;
10
13
  context?: string | null;
11
14
  preventDefault?: boolean;
12
15
  description?: string;
@@ -19,6 +22,20 @@ interface ShortcutConfigBase {
19
22
  * @default false
20
23
  */
21
24
  strict?: boolean;
25
+ /**
26
+ * The DOM element to which the event listener for this shortcut will be attached.
27
+ * If not provided, the listener will be attached to the `document`.
28
+ * Useful for creating shortcuts that are only active within a specific component or area.
29
+ * @default document
30
+ */
31
+ target?: HTMLElement;
32
+ /**
33
+ * The type of keyboard event to listen for.
34
+ * Use "keydown" for actions that should happen immediately upon pressing a key.
35
+ * Use "keyup" for actions that should happen upon releasing a key.
36
+ * @default "keydown"
37
+ */
38
+ event?: "keydown" | "keyup";
22
39
  }
23
40
  /**
24
41
  * Defines a single key trigger, which can be a StandardKey (for simple presses like "Escape")
@@ -44,32 +61,34 @@ type KeyCombinationTrigger = {
44
61
  export interface KeyCombinationConfig extends ShortcutConfigBase {
45
62
  /**
46
63
  * Defines the key or key combination(s) that trigger the shortcut.
47
- * Can be a single trigger or an array of triggers.
48
- * Each trigger can be an object specifying the main `key` (from `StandardKey`) and optional
64
+ * Can be a single trigger, an array of triggers, or a string representation.
65
+ *
66
+ * **Object/Array:** Each trigger can be an object specifying the main `key` (from `StandardKey`) and optional
49
67
  * modifiers (`ctrlKey`, `altKey`, `shiftKey`, `metaKey`).
50
68
  * Example: `{ key: Keys.S, ctrlKey: true }` for Ctrl+S.
51
69
  *
52
- * Alternatively, for a simple key press without any modifiers, a trigger can be
53
- * a `StandardKey` directly.
54
- * Example: `Keys.Escape` for the Escape key. When using this shorthand,
55
- * it implies that no modifier keys (Ctrl, Alt, Shift, Meta) should be active.
70
+ * **Shorthand:** For a simple key press without modifiers, a trigger can be a `StandardKey` directly.
71
+ * Example: `Keys.Escape` for the Escape key.
72
+ *
73
+ * **String:** A human-readable string like `"ctrl+s"` or `"shift+alt+k"`. Modifiers are joined by `+`.
74
+ * Example: `"meta+k"`, `"ctrl+shift+?"`
56
75
  *
57
76
  * To define multiple triggers for the same action:
58
77
  * Example: `keys: [Keys.Enter, { key: Keys.Space, ctrlKey: true }]`
59
78
  */
60
- keys: KeyCombinationTrigger | KeyCombinationTrigger[];
79
+ keys: KeyCombinationTrigger | KeyCombinationTrigger[] | string;
61
80
  }
62
81
  export interface KeySequenceConfig extends ShortcutConfigBase {
63
82
  /**
64
- * An array of keys that form the sequence.
65
- * Each key in the sequence MUST be a value from the exported `Keys` object
66
- * (e.g., `Keys.ArrowUp`, `Keys.G`, `Keys.Digit1`).
67
- * The library handles case-insensitivity for single character keys automatically
68
- * when comparing with the actual browser event's `event.key`.
69
- * Refer to: https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values
70
- * Example: [Keys.Control, Keys.Alt, Keys.Delete] or [Keys.G, Keys.I]
83
+ * An array of keys or a string defining the sequence.
84
+ *
85
+ * **Array:** Each key in the sequence MUST be a value from `Keys`.
86
+ * Example: `[Keys.G, Keys.I]`
87
+ *
88
+ * **String:** A string where keys are separated by `->`.
89
+ * Example: `"g -> i"`, `"up -> up -> down -> down"`
71
90
  */
72
- sequence: StandardKey[];
91
+ sequence: StandardKey[] | string;
73
92
  /**
74
93
  * Optional: Timeout in milliseconds between consecutive key presses in the sequence.
75
94
  * If the time between two keys in the sequence exceeds this value, the sequence attempt is reset.
@@ -81,7 +100,7 @@ type ShortcutConfig = KeyCombinationConfig | KeySequenceConfig;
81
100
  export interface ActiveShortcut {
82
101
  id: string;
83
102
  config: ShortcutConfig;
84
- subscription: Subscription;
103
+ terminator$: Subject<void>;
85
104
  }
86
105
  /**
87
106
  * Manages keyboard shortcuts for web applications.
@@ -90,8 +109,10 @@ export interface ActiveShortcut {
90
109
  */
91
110
  export declare class Hotkeys {
92
111
  private static readonly KEYDOWN_EVENT;
112
+ private static readonly KEYUP_EVENT;
93
113
  private static readonly LOG_PREFIX;
94
- private keydown$;
114
+ private keydownStreams;
115
+ private keyupStreams;
95
116
  private activeContext$;
96
117
  private activeShortcuts;
97
118
  private debugMode;
@@ -102,6 +123,13 @@ export declare class Hotkeys {
102
123
  * @throws Error if not in a browser environment (i.e., `document` or `performance` is undefined).
103
124
  */
104
125
  constructor(initialContext?: string | null, debugMode?: boolean);
126
+ /**
127
+ * Gets or creates a shared event stream for a given event type and target.
128
+ * @param eventType The type of event ("keydown" or "keyup").
129
+ * @param target The DOM element to attach the listener to.
130
+ * @returns A shared Observable for the specified event.
131
+ */
132
+ private _getEventStream;
105
133
  /**
106
134
  * Sets the active context for shortcuts.
107
135
  * Only shortcuts matching this context (or shortcuts with no specific context defined)
@@ -172,57 +200,80 @@ export declare class Hotkeys {
172
200
  * @returns An object containing configuredMainKey and modifier states, or null if parsing fails.
173
201
  */
174
202
  private _parseKeyTrigger;
203
+ private _parseCombinationString;
204
+ private _parseSequenceString;
175
205
  /**
176
- * Registers a key combination shortcut (e.g., Ctrl+S, Shift+Enter, or a single key like Escape).
177
- * The callback is triggered when the specified key and modifier keys (if any) are pressed.
206
+ * Registers a key combination shortcut (e.g., Ctrl+S, Shift+Enter, or a single key like Escape)
207
+ * and returns an Observable that emits the `KeyboardEvent` when the combination is triggered.
178
208
  * @param config - Configuration object for the key combination.
179
209
  * See {@link KeyCombinationConfig} for details.
180
- * The `key` property (or the direct `StandardKey` if using shorthand) must be a value from the `Keys` object.
181
- * @returns The ID of the registered shortcut if successful, or `undefined` if the configuration is invalid.
182
- * A warning is logged to the console if the configuration is invalid or if a shortcut with the same ID is overwritten.
210
+ * @returns An `Observable<KeyboardEvent>` that you can subscribe to. The stream will be automatically
211
+ * completed if the shortcut is removed via `remove(id)` or `destroy()`, or if it's overwritten.
212
+ * If the configuration is invalid, an empty Observable is returned and a warning is logged.
183
213
  * @example
184
214
  * ```typescript
185
215
  * import { Keys } from "./keys";
186
216
  * // For Ctrl+S
187
- * keyManager.addCombination({
217
+ * const save$ = keyManager.addCombination({
188
218
  * id: "saveFile",
189
219
  * keys: { key: Keys.S, ctrlKey: true },
190
- * callback: () => console.log("File saved!"),
191
220
  * context: "editor"
192
221
  * });
222
+ * save$.subscribe(event => console.log("File saved!", event));
223
+ *
224
+ * // For Ctrl+S using a string
225
+ * const save$ = keyManager.addCombination({ id: "saveFile", keys: "ctrl+s" });
226
+ * save$.subscribe(event => console.log("File saved!", event));
227
+ *
193
228
  * // For just the Escape key, or Ctrl+Space
194
- * keyManager.addCombination({
229
+ * const close$ = keyManager.addCombination({
195
230
  * id: "closeModal",
196
231
  * keys: [Keys.Escape, {key: Keys.Space, ctrlKey: true}],
197
- * callback: () => console.log("Modal closed!")
198
232
  * });
233
+ * close$.subscribe(() => console.log("Modal closed!"));
234
+ *
235
+ * // For the Escape key on a specific element
236
+ * const myModal = document.getElementById("my-modal");
237
+ * const close$ = keyManager.addCombination({ id: "closeModal", keys: Keys.Escape, target: myModal });
238
+ * close$.subscribe(() => console.log("Modal closed!"));
199
239
  * ```
200
240
  */
201
- addCombination(config: KeyCombinationConfig): string | undefined;
241
+ addCombination(config: KeyCombinationConfig): Observable<KeyboardEvent>;
202
242
  /**
203
- * Registers a key sequence shortcut (e.g., g -> i, or ArrowUp -> ArrowUp -> ArrowDown).
204
- * The callback is triggered when the specified keys are pressed in order.
243
+ * Registers a key sequence shortcut (e.g., g -> i, or ArrowUp -> ArrowUp -> ArrowDown)
244
+ * and returns an Observable that emits the final `KeyboardEvent` of the sequence when it's completed.
205
245
  * An optional timeout can be specified for the time allowed between key presses in the sequence.
206
246
  * @param config - Configuration object for the key sequence.
207
247
  * See {@link KeySequenceConfig} for details.
208
248
  * Each key in the `sequence` array must be a value from the `Keys` object.
209
- * @returns The ID of the registered shortcut if successful, or `undefined` if the configuration is invalid (e.g., empty sequence or invalid keys).
210
- * A warning is logged to the console if the configuration is invalid or if a shortcut with the same ID is overwritten.
249
+ * Or using string for `sequence`.
250
+ * @returns An `Observable<KeyboardEvent>` that you can subscribe to. The stream will be automatically
251
+ * completed if the shortcut is removed via `remove(id)` or `destroy()`, or if it's overwritten.
252
+ * If the configuration is invalid, an empty Observable is returned and a warning is logged.
211
253
  * @example
212
254
  * ```typescript
213
255
  * import { Keys } from "./keys";
214
- * keyManager.addSequence({
256
+ * const konami$ = keyManager.addSequence({
215
257
  * id: "konamiCode",
216
258
  * sequence: [Keys.ArrowUp, Keys.ArrowUp, Keys.ArrowDown, Keys.ArrowDown, Keys.A, Keys.B],
217
- * callback: () => console.log("Konami!"),
218
259
  * sequenceTimeoutMs: 2000 // 2 seconds between keys
219
260
  * });
261
+ * konami$.subscribe(event => console.log("Konami!", event));
262
+ * ```
263
+ * ```typescript
264
+ * // Using a string for the sequence
265
+ * const konami$ = keyManager.addSequence({
266
+ * id: "konamiCode",
267
+ * sequence: "up -> up -> down -> down -> a -> b",
268
+ * sequenceTimeoutMs: 2000
269
+ * });
270
+ * konami$.subscribe(event => console.log("Konami!", event));
220
271
  * ```
221
272
  */
222
- addSequence(config: KeySequenceConfig): string | undefined;
273
+ addSequence(config: KeySequenceConfig): Observable<KeyboardEvent>;
223
274
  /**
224
275
  * Removes a registered shortcut by its ID.
225
- * This will unsubscribe from the underlying keyboard event stream for that shortcut.
276
+ * This will complete the corresponding Observable stream for any subscribers.
226
277
  * @param id - The unique ID of the shortcut to remove.
227
278
  * @returns True if the shortcut was found and removed, false otherwise.
228
279
  * A warning is logged to the console if no shortcut with the given ID is found.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotkeys.d.ts","sourceRoot":"","sources":["../../src/core/hotkeys.ts"],"names":[],"mappings":"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"}