@tanstack/hotkeys 0.8.0 → 0.10.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.
Files changed (109) hide show
  1. package/README.md +15 -1
  2. package/dist/{manager.utils.js → _event-target.js} +2 -41
  3. package/dist/_keyboard-event.js +75 -0
  4. package/dist/_match.js +48 -0
  5. package/dist/_named-keys.d.ts +6 -0
  6. package/dist/_named-keys.js +65 -0
  7. package/dist/_recorder-chord.js +42 -0
  8. package/dist/_recording-guard.js +55 -0
  9. package/dist/_registration.js +49 -0
  10. package/dist/conflicts.d.ts +36 -0
  11. package/dist/conflicts.js +54 -0
  12. package/dist/constants.d.ts +16 -144
  13. package/dist/constants.js +55 -172
  14. package/dist/display-labels.d.ts +90 -0
  15. package/dist/display-labels.js +112 -0
  16. package/dist/format.d.ts +48 -12
  17. package/dist/format.js +35 -39
  18. package/dist/hint.d.ts +20 -0
  19. package/dist/hint.js +23 -0
  20. package/dist/hotkey-manager.d.ts +14 -12
  21. package/dist/hotkey-manager.js +70 -21
  22. package/dist/hotkey-recorder.d.ts +8 -8
  23. package/dist/hotkey-recorder.js +74 -15
  24. package/dist/hotkey-sequence-recorder.d.ts +13 -9
  25. package/dist/hotkey-sequence-recorder.js +90 -28
  26. package/dist/{hotkey.d.ts → hotkey.types.d.ts} +58 -126
  27. package/dist/index.d.ts +14 -9
  28. package/dist/index.js +10 -6
  29. package/dist/key-state-tracker.d.ts +4 -7
  30. package/dist/key-state-tracker.js +30 -27
  31. package/dist/key.types.d.ts +79 -0
  32. package/dist/match.d.ts +24 -11
  33. package/dist/match.js +19 -30
  34. package/dist/parse.d.ts +18 -15
  35. package/dist/parse.js +39 -22
  36. package/dist/platform.d.ts +41 -0
  37. package/dist/platform.js +52 -0
  38. package/dist/recorder-options.d.ts +31 -0
  39. package/dist/sequence-manager.d.ts +27 -15
  40. package/dist/sequence-manager.js +61 -30
  41. package/dist/validate.d.ts +16 -8
  42. package/dist/validate.js +8 -13
  43. package/package.json +8 -13
  44. package/dist/constants.cjs +0 -535
  45. package/dist/constants.cjs.map +0 -1
  46. package/dist/constants.d.cts +0 -290
  47. package/dist/constants.js.map +0 -1
  48. package/dist/format.cjs +0 -91
  49. package/dist/format.cjs.map +0 -1
  50. package/dist/format.d.cts +0 -60
  51. package/dist/format.js.map +0 -1
  52. package/dist/hotkey-manager.cjs +0 -383
  53. package/dist/hotkey-manager.cjs.map +0 -1
  54. package/dist/hotkey-manager.d.cts +0 -230
  55. package/dist/hotkey-manager.js.map +0 -1
  56. package/dist/hotkey-recorder.cjs +0 -179
  57. package/dist/hotkey-recorder.cjs.map +0 -1
  58. package/dist/hotkey-recorder.d.cts +0 -116
  59. package/dist/hotkey-recorder.js.map +0 -1
  60. package/dist/hotkey-sequence-recorder.cjs +0 -192
  61. package/dist/hotkey-sequence-recorder.cjs.map +0 -1
  62. package/dist/hotkey-sequence-recorder.d.cts +0 -79
  63. package/dist/hotkey-sequence-recorder.js.map +0 -1
  64. package/dist/hotkey.d.cts +0 -301
  65. package/dist/index.cjs +0 -63
  66. package/dist/index.d.cts +0 -13
  67. package/dist/key-state-tracker.cjs +0 -197
  68. package/dist/key-state-tracker.cjs.map +0 -1
  69. package/dist/key-state-tracker.d.cts +0 -107
  70. package/dist/key-state-tracker.js.map +0 -1
  71. package/dist/manager.utils.cjs +0 -115
  72. package/dist/manager.utils.cjs.map +0 -1
  73. package/dist/manager.utils.d.cts +0 -13
  74. package/dist/manager.utils.d.ts +0 -13
  75. package/dist/manager.utils.js.map +0 -1
  76. package/dist/match.cjs +0 -153
  77. package/dist/match.cjs.map +0 -1
  78. package/dist/match.d.cts +0 -85
  79. package/dist/match.js.map +0 -1
  80. package/dist/parse.cjs +0 -228
  81. package/dist/parse.cjs.map +0 -1
  82. package/dist/parse.d.cts +0 -128
  83. package/dist/parse.js.map +0 -1
  84. package/dist/recorder-chord.cjs +0 -18
  85. package/dist/recorder-chord.cjs.map +0 -1
  86. package/dist/recorder-chord.js +0 -18
  87. package/dist/recorder-chord.js.map +0 -1
  88. package/dist/sequence-manager.cjs +0 -415
  89. package/dist/sequence-manager.cjs.map +0 -1
  90. package/dist/sequence-manager.d.cts +0 -157
  91. package/dist/sequence-manager.js.map +0 -1
  92. package/dist/validate.cjs +0 -116
  93. package/dist/validate.cjs.map +0 -1
  94. package/dist/validate.d.cts +0 -56
  95. package/dist/validate.js.map +0 -1
  96. package/src/constants.ts +0 -603
  97. package/src/format.ts +0 -142
  98. package/src/hotkey-manager.ts +0 -759
  99. package/src/hotkey-recorder.ts +0 -272
  100. package/src/hotkey-sequence-recorder.ts +0 -328
  101. package/src/hotkey.ts +0 -436
  102. package/src/index.ts +0 -11
  103. package/src/key-state-tracker.ts +0 -249
  104. package/src/manager.utils.ts +0 -231
  105. package/src/match.ts +0 -259
  106. package/src/parse.ts +0 -328
  107. package/src/recorder-chord.ts +0 -25
  108. package/src/sequence-manager.ts +0 -734
  109. package/src/validate.ts +0 -171
@@ -1,66 +1,8 @@
1
- //#region src/hotkey.d.ts
2
- /**
3
- * All supported modifier key names, including aliases.
4
- * - Control/Ctrl: The Control key
5
- * - Shift: The Shift key
6
- * - Alt/Option: The Alt key (Option on macOS)
7
- * - Command/Cmd: The Command key (macOS only)
8
- * - CommandOrControl/Mod: Command on macOS, Control on other platforms
9
- */
10
- type Modifier = 'Control' | 'Ctrl' | 'Shift' | 'Alt' | 'Option' | 'Command' | 'Cmd' | 'CommandOrControl' | 'Mod';
11
- /**
12
- * Canonical modifier names that map to KeyboardEvent properties.
13
- */
14
- type CanonicalModifier = 'Control' | 'Shift' | 'Alt' | 'Meta';
15
- /**
16
- * Letter keys A-Z (case-insensitive in matching).
17
- */
18
- type LetterKey = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
19
- /**
20
- * Number keys 0-9.
21
- */
22
- type NumberKey = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
23
- /**
24
- * Function keys F1-F12.
25
- */
26
- type FunctionKey = 'F1' | 'F2' | 'F3' | 'F4' | 'F5' | 'F6' | 'F7' | 'F8' | 'F9' | 'F10' | 'F11' | 'F12';
27
- /**
28
- * Navigation keys for cursor movement.
29
- */
30
- type NavigationKey = 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'Home' | 'End' | 'PageUp' | 'PageDown';
31
- /**
32
- * Editing and special keys.
33
- */
34
- type EditingKey = 'Enter' | 'Escape' | 'Space' | 'Tab' | 'Backspace' | 'Delete';
35
- /**
36
- * Punctuation keys commonly used in keyboard shortcuts.
37
- * These are the literal characters as they appear in KeyboardEvent.key
38
- * (layout-dependent, typically US keyboard layout).
39
- */
40
- type PunctuationKey = '/' | '[' | ']' | '\\' | '=' | '-' | ',' | '.' | ';' | '`';
41
- /**
42
- * Keys that don't change their value when Shift is pressed.
43
- * These keys produce the same `KeyboardEvent.key` value whether Shift is held or not.
44
- *
45
- * Excludes NumberKey (Shift+1 produces '!' on US layout) and PunctuationKey
46
- * (Shift+',' produces '<' on US layout).
47
- *
48
- * Used in hotkey type definitions to prevent layout-dependent issues when Shift
49
- * is part of the modifier combination.
50
- */
51
- type NonPunctuationKey = LetterKey | NumberKey | EditingKey | NavigationKey | FunctionKey;
52
- /**
53
- * All supported non-modifier keys.
54
- */
55
- type Key = NonPunctuationKey | PunctuationKey;
56
- /**
57
- * Includes both modifier keys and regular keys.
58
- */
59
- type IndividualKey = CanonicalModifier | Key;
1
+ import { CanonicalModifier, Key, LogicalKey } from "./key.types.js";
2
+ //#region src/hotkey.types.d.ts
60
3
  /**
61
4
  * Single modifier + key combinations.
62
5
  * Uses canonical modifiers (4) + Mod (1) = 5 modifiers.
63
- * Shift combinations exclude PunctuationKey to avoid layout-dependent issues.
64
6
  *
65
7
  * The `Mod` modifier is platform-adaptive:
66
8
  * - **macOS**: Resolves to `Meta` (Command key ⌘)
@@ -69,10 +11,9 @@ type IndividualKey = CanonicalModifier | Key;
69
11
  * This enables cross-platform hotkey definitions that automatically adapt to the platform.
70
12
  * For example, `Mod+S` becomes `Command+S` on Mac and `Ctrl+S` on Windows/Linux.
71
13
  */
72
- type SingleModifierHotkey = `Control+${Key}` | `Alt+${Key}` | `Shift+${NonPunctuationKey}` | `Meta+${Key}` | `Mod+${Key}`;
14
+ export type SingleModifierHotkey = `Control+${Key}` | `Alt+${Key}` | `Shift+${Key}` | `Meta+${Key}` | `Mod+${Key}`;
73
15
  /**
74
16
  * Two modifier + key combinations.
75
- * Shift combinations exclude Numbers and PunctuationKeys to avoid layout-dependent issues.
76
17
  *
77
18
  * **Platform-adaptive `Mod` combinations:**
78
19
  * - `Mod+Alt` and `Mod+Shift` are included (safe on all platforms)
@@ -80,10 +21,9 @@ type SingleModifierHotkey = `Control+${Key}` | `Alt+${Key}` | `Shift+${NonPunctu
80
21
  * - `Mod+Control` duplicates `Control` on Windows/Linux (Mod = Control)
81
22
  * - `Mod+Meta` duplicates `Meta` on macOS (Mod = Meta)
82
23
  */
83
- type TwoModifierHotkey = `Control+Alt+${Key}` | `Control+Shift+${NonPunctuationKey}` | `Control+Meta+${Key}` | `Alt+Shift+${NonPunctuationKey}` | `Alt+Meta+${Key}` | `Shift+Meta+${NonPunctuationKey}` | `Mod+Alt+${Key}` | `Mod+Shift+${NonPunctuationKey}`;
24
+ export type TwoModifierHotkey = `Control+Alt+${Key}` | `Control+Shift+${Key}` | `Control+Meta+${Key}` | `Alt+Shift+${Key}` | `Alt+Meta+${Key}` | `Shift+Meta+${Key}` | `Mod+Alt+${Key}` | `Mod+Shift+${Key}`;
84
25
  /**
85
26
  * Three modifier + key combinations.
86
- * Shift combinations exclude Numbers and PunctuationKeys to avoid layout-dependent issues.
87
27
  *
88
28
  * **Platform-adaptive `Mod` combinations:**
89
29
  * - `Mod+Alt+Shift` is included (safe on all platforms)
@@ -91,10 +31,9 @@ type TwoModifierHotkey = `Control+Alt+${Key}` | `Control+Shift+${NonPunctuationK
91
31
  * - `Mod+Control+Shift` duplicates `Control` on Windows/Linux (Mod = Control)
92
32
  * - `Mod+Shift+Meta` duplicates `Meta` on macOS (Mod = Meta)
93
33
  */
94
- type ThreeModifierHotkey = `Control+Alt+Shift+${NonPunctuationKey}` | `Control+Alt+Meta+${Key}` | `Control+Shift+Meta+${NonPunctuationKey}` | `Alt+Shift+Meta+${NonPunctuationKey}` | `Mod+Alt+Shift+${NonPunctuationKey}`;
34
+ export type ThreeModifierHotkey = `Control+Alt+Shift+${Key}` | `Control+Alt+Meta+${Key}` | `Control+Shift+Meta+${Key}` | `Alt+Shift+Meta+${Key}` | `Mod+Alt+Shift+${Key}`;
95
35
  /**
96
36
  * Four modifier + key combinations.
97
- * Shift combinations exclude Numbers and PunctuationKeys to avoid layout-dependent issues.
98
37
  *
99
38
  * Only the canonical `Control+Alt+Shift+Meta` combination is included.
100
39
  *
@@ -105,7 +44,7 @@ type ThreeModifierHotkey = `Control+Alt+Shift+${NonPunctuationKey}` | `Control+A
105
44
  * - `Mod+Control+Alt+Shift` → duplicates `Control` on Windows/Linux
106
45
  * - `Mod+Alt+Shift+Meta` → duplicates `Meta` on macOS
107
46
  */
108
- type FourModifierHotkey = `Control+Alt+Shift+Meta+${NonPunctuationKey}`;
47
+ export type FourModifierHotkey = `Control+Alt+Shift+Meta+${Key}`;
109
48
  /**
110
49
  * A type-safe hotkey string.
111
50
  *
@@ -158,39 +97,36 @@ type FourModifierHotkey = `Control+Alt+Shift+Meta+${NonPunctuationKey}`;
158
97
  * const windowsOnly: Hotkey = 'Control+S' // Ctrl+S on Windows/Linux only
159
98
  * ```
160
99
  */
161
- type Hotkey = Key | SingleModifierHotkey | TwoModifierHotkey | ThreeModifierHotkey | FourModifierHotkey;
162
- /**
163
- * A parsed representation of a hotkey string.
164
- *
165
- * This interface provides a flexible fallback when the `Hotkey` type doesn't
166
- * fit your use case. You can pass a `ParsedHotkey` directly to hotkey functions
167
- * instead of a hotkey string, allowing for more dynamic or complex scenarios
168
- * that aren't covered by the type-safe `Hotkey` union.
169
- *
170
- * @example
171
- * ```ts
172
- * // Type-safe hotkey string
173
- * useHotkey('Mod+S', handler)
174
- *
175
- * // Fallback: parsed hotkey for dynamic scenarios
176
- * const parsed = parseHotkey(userInput)
177
- * useHotkey(parsed, handler) // Works even if userInput isn't in Hotkey type
178
- * ```
179
- */
180
- interface ParsedHotkey {
181
- /** The non-modifier key (e.g., 'S', 'Escape', 'F1', '/', '['). Can be any string for flexibility. */
182
- key: Key | (string & {});
183
- /** Whether the Control key is required */
100
+ export type Hotkey = Key | SingleModifierHotkey | TwoModifierHotkey | ThreeModifierHotkey | FourModifierHotkey;
101
+ /** Resolved modifier flags shared by both parsed binding variants. */
102
+ export interface ParsedModifiers {
103
+ /** Whether Control is required. */
184
104
  ctrl: boolean;
185
- /** Whether the Shift key is required */
105
+ /** Whether Shift is required. */
186
106
  shift: boolean;
187
- /** Whether the Alt key is required */
107
+ /** Whether Alt is required. */
188
108
  alt: boolean;
189
- /** Whether the Meta (Command) key is required */
109
+ /** Whether Meta (Command) is required. */
190
110
  meta: boolean;
191
- /** List of canonical modifier names that are required, in canonical order */
111
+ /** Required modifiers in canonical order. */
192
112
  modifiers: Array<CanonicalModifier>;
193
113
  }
114
+ /**
115
+ * A parsed binding matches either a logical key or a physical code, never both.
116
+ * Check `code !== undefined` to narrow to a physical binding. Its logical
117
+ * character is unknown without a keyboard event and is not stored in `key`.
118
+ *
119
+ * @example
120
+ * parseHotkey('Alt+S') // { key: 'S', alt: true, ... }
121
+ * parseHotkey('Alt+[KeyS]') // { code: 'KeyS', alt: true, ... } — no key property
122
+ */
123
+ export type ParsedHotkey = ParsedModifiers & ({
124
+ key: LogicalKey | (string & {});
125
+ code?: never;
126
+ } | {
127
+ code: string;
128
+ key?: never;
129
+ });
194
130
  /**
195
131
  * A raw hotkey object for programmatic registration.
196
132
  *
@@ -209,11 +145,13 @@ interface ParsedHotkey {
209
145
  * useHotkey({ key: 'Escape' }, handler) // Escape (no modifiers)
210
146
  * useHotkey({ key: 'A', shift: true, meta: true }, handler) // Shift+Meta+A
211
147
  * useHotkey({ key: 'S', mod: true, shift: true }, handler) // Mod+Shift+S
148
+ * useHotkey({ code: 'KeyW', mod: true }, handler) // Physical Mod+KeyW
149
+ * useHotkey({ code: 'NumpadAdd', mod: true }, handler) // Physical numpad plus
212
150
  * ```
213
151
  */
214
- interface RawHotkey {
152
+ /** Modifier flags shared by logical-key and physical-code registrations. */
153
+ export interface RawModifiers {
215
154
  /** The non-modifier key (e.g., 'S', 'Escape', 'F1'). */
216
- key: Key | (string & {});
217
155
  /** Platform-adaptive modifier: Command on macOS, Control on Windows/Linux. Defaults to false. */
218
156
  mod?: boolean;
219
157
  /** Whether the Control key is required. Defaults to false. */
@@ -225,37 +163,22 @@ interface RawHotkey {
225
163
  /** Whether the Meta (Command) key is required. Defaults to false. */
226
164
  meta?: boolean;
227
165
  }
166
+ export type RawHotkey = ({
167
+ key: LogicalKey | (string & {});
168
+ code?: never;
169
+ } & RawModifiers) | ({
170
+ code: string;
171
+ key?: never;
172
+ } & RawModifiers);
228
173
  /**
229
174
  * A hotkey that can be passed to `HotkeyManager.register()` and `useHotkey()`.
230
175
  * Either a type-safe string (`Hotkey`) or a raw object (`RawHotkey`).
231
176
  */
232
- type RegisterableHotkey = Hotkey | RawHotkey;
233
- /**
234
- * Options for formatting hotkeys for display.
235
- */
236
- interface FormatDisplayOptions {
237
- /** The target platform. Defaults to auto-detection. */
238
- platform?: 'mac' | 'windows' | 'linux';
239
- /** Whether to use symbols for the display. Defaults to true. */
240
- useSymbols?: boolean;
241
- /** Override the separator between display tokens. Defaults to platform-specific formatting when null/undefined. */
242
- separatorToken?: string | null;
243
- }
244
- /**
245
- * Result of validating a hotkey string.
246
- */
247
- interface ValidationResult {
248
- /** Whether the hotkey is valid (can still have warnings) */
249
- valid: boolean;
250
- /** Warning messages about potential issues */
251
- warnings: Array<string>;
252
- /** Error messages about invalid syntax */
253
- errors: Array<string>;
254
- }
177
+ export type RegisterableHotkey = Hotkey | RawHotkey;
255
178
  /**
256
179
  * Context passed to hotkey callbacks along with the keyboard event.
257
180
  */
258
- interface HotkeyCallbackContext {
181
+ export interface HotkeyCallbackContext {
259
182
  /** The original hotkey string that was registered */
260
183
  hotkey: Hotkey;
261
184
  /** The parsed representation of the hotkey */
@@ -275,10 +198,10 @@ interface HotkeyCallbackContext {
275
198
  * }
276
199
  * ```
277
200
  */
278
- type HotkeyCallback = (event: KeyboardEvent, context: HotkeyCallbackContext) => void;
201
+ export type HotkeyCallback = (event: KeyboardEvent, context: HotkeyCallbackContext) => void;
279
202
  /**
280
203
  * Metadata for hotkey and sequence registrations.
281
- * Includes `name` and `description` by default. Extend via declaration merging:
204
+ * Includes `name`, `description`, and `group` by default. Extend via declaration merging:
282
205
  *
283
206
  * @example
284
207
  * ```ts
@@ -290,12 +213,21 @@ type HotkeyCallback = (event: KeyboardEvent, context: HotkeyCallbackContext) =>
290
213
  * }
291
214
  * ```
292
215
  */
293
- interface HotkeyMeta {
216
+ export interface HotkeyMeta {
294
217
  /** Human-readable name for this hotkey (e.g., "Save Document") */
295
218
  name?: string;
296
219
  /** Description of what this hotkey does */
297
220
  description?: string;
221
+ /** Optional display group. Does not affect matching or scope. */
222
+ group?: string;
298
223
  }
299
- //#endregion
300
- export { CanonicalModifier, EditingKey, FormatDisplayOptions, FunctionKey, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyMeta, IndividualKey, Key, LetterKey, Modifier, NavigationKey, NumberKey, ParsedHotkey, PunctuationKey, RawHotkey, RegisterableHotkey, ValidationResult };
301
- //# sourceMappingURL=hotkey.d.ts.map
224
+ /**
225
+ * Behavior when registering a hotkey/sequence that conflicts with an existing registration.
226
+ *
227
+ * - `'warn'` - Log a warning to the console but allow both registrations (default)
228
+ * - `'error'` - Throw an error and prevent the new registration
229
+ * - `'replace'` - Unregister the existing registration and register the new one
230
+ * - `'allow'` - Allow multiple registrations without warning
231
+ */
232
+ export type ConflictBehavior = 'warn' | 'error' | 'replace' | 'allow';
233
+ //#endregion
package/dist/index.d.ts CHANGED
@@ -1,13 +1,18 @@
1
- import { CanonicalModifier, EditingKey, FormatDisplayOptions, FunctionKey, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyMeta, IndividualKey, Key, LetterKey, Modifier, NavigationKey, NumberKey, ParsedHotkey, PunctuationKey, RawHotkey, RegisterableHotkey, ValidationResult } from "./hotkey.js";
2
- import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, KEY_DISPLAY_SYMBOLS, LETTER_KEYS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS, detectPlatform, isSingleLetterKey, normalizeKeyName, resolveModifier } from "./constants.js";
3
- import { formatForDisplay, formatHotkey, formatHotkeySequence, formatWithLabels } from "./format.js";
4
- import { ConflictBehavior } from "./manager.utils.js";
1
+ import { CanonicalModifier, EditingKey, FunctionKey, IndividualKey, Key, LetterKey, LogicalKey, Modifier, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PhysicalKey, PhysicalKeyCode, PunctuationKey } from "./key.types.js";
2
+ import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, LETTER_KEYS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, isSingleLetterKey, normalizeKeyName } from "./constants.js";
3
+ import { KEY_DISPLAY_SYMBOLS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS } from "./display-labels.js";
4
+ import { detectPlatform, resolveModifier } from "./platform.js";
5
+ import { ConflictBehavior, FourModifierHotkey, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyMeta, ParsedHotkey, ParsedModifiers, RawHotkey, RawModifiers, RegisterableHotkey, SingleModifierHotkey, ThreeModifierHotkey, TwoModifierHotkey } from "./hotkey.types.js";
6
+ import { DisplayHotkey, FormatDisplayOptions, formatForDisplay, formatHotkey, formatHotkeySequence, formatWithLabels } from "./format.js";
7
+ import { hasNonModifierKey, isModifierKey, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, rawHotkeyToParsedHotkey } from "./parse.js";
8
+ import { ValidationResult, assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
9
+ import { CreateHotkeyHandlerOptions, KeyboardEventMatch, MultiHotkeyHandler, areHotkeysEqual, createHotkeyHandler, createMultiHotkeyHandler, matchesKeyboardEvent } from "./match.js";
10
+ import { HeldModifierOptions, matchesHeldModifiers } from "./hint.js";
5
11
  import { HotkeyManager, HotkeyOptions, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
12
+ import { DEFAULT_SEQUENCE_TIMEOUT, HotkeySequence, SequenceManager, SequenceOptions, SequenceRegistration, SequenceRegistrationHandle, SequenceRegistrationView, Target, createSequenceMatcher, getSequenceManager } from "./sequence-manager.js";
13
+ import { HotkeyConflict, HotkeyConflictOptions, findHotkeyConflicts } from "./conflicts.js";
6
14
  import { KeyStateTracker, KeyStateTrackerState, getKeyStateTracker } from "./key-state-tracker.js";
7
- import { CreateHotkeyHandlerOptions, createHotkeyHandler, createMultiHotkeyHandler, matchesKeyboardEvent } from "./match.js";
8
- import { hasNonModifierKey, isModifierKey, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, rawHotkeyToParsedHotkey } from "./parse.js";
15
+ import { HotkeyRecorderValidationContext, HotkeySequenceRecorderValidationContext, RecorderKeyMode, RecorderOptions, RecorderRejection } from "./recorder-options.js";
9
16
  import { HotkeyRecorder, HotkeyRecorderOptions, HotkeyRecorderState } from "./hotkey-recorder.js";
10
- import { DEFAULT_SEQUENCE_TIMEOUT, HotkeySequence, SequenceManager, SequenceOptions, SequenceRegistrationHandle, SequenceRegistrationView, createSequenceMatcher, getSequenceManager } from "./sequence-manager.js";
11
17
  import { HotkeySequenceRecorder, HotkeySequenceRecorderCommitKeys, HotkeySequenceRecorderOptions, HotkeySequenceRecorderState } from "./hotkey-sequence-recorder.js";
12
- import { assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
13
- export { ALL_KEYS, CanonicalModifier, ConflictBehavior, CreateHotkeyHandlerOptions, DEFAULT_SEQUENCE_TIMEOUT, EDITING_KEYS, EditingKey, FUNCTION_KEYS, FormatDisplayOptions, FunctionKey, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyManager, HotkeyMeta, HotkeyOptions, HotkeyRecorder, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeySequence, HotkeySequenceRecorder, HotkeySequenceRecorderCommitKeys, HotkeySequenceRecorderOptions, HotkeySequenceRecorderState, IndividualKey, KEY_DISPLAY_SYMBOLS, Key, KeyStateTracker, KeyStateTrackerState, LETTER_KEYS, LINUX_MODIFIER_LABELS, LetterKey, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, Modifier, NAVIGATION_KEYS, NUMBER_KEYS, NavigationKey, NumberKey, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, ParsedHotkey, PunctuationKey, RawHotkey, RegisterableHotkey, SequenceManager, SequenceOptions, SequenceRegistrationHandle, SequenceRegistrationView, ValidationResult, WINDOWS_MODIFIER_LABELS, assertValidHotkey, checkHotkey, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, detectPlatform, formatForDisplay, formatHotkey, formatHotkeySequence, formatWithLabels, getHotkeyManager, getKeyStateTracker, getSequenceManager, hasNonModifierKey, isModifierKey, isSingleLetterKey, matchesKeyboardEvent, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeKeyName, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, rawHotkeyToParsedHotkey, resolveModifier, toHotkeyRegistrationView, validateHotkey };
18
+ export { ALL_KEYS, CanonicalModifier, ConflictBehavior, CreateHotkeyHandlerOptions, DEFAULT_SEQUENCE_TIMEOUT, DisplayHotkey, EDITING_KEYS, EditingKey, FUNCTION_KEYS, FormatDisplayOptions, FourModifierHotkey, FunctionKey, HeldModifierOptions, Hotkey, HotkeyCallback, HotkeyCallbackContext, HotkeyConflict, HotkeyConflictOptions, HotkeyManager, HotkeyMeta, HotkeyOptions, HotkeyRecorder, HotkeyRecorderOptions, HotkeyRecorderState, HotkeyRecorderValidationContext, HotkeyRegistration, HotkeyRegistrationHandle, HotkeyRegistrationView, HotkeySequence, HotkeySequenceRecorder, HotkeySequenceRecorderCommitKeys, HotkeySequenceRecorderOptions, HotkeySequenceRecorderState, HotkeySequenceRecorderValidationContext, IndividualKey, KEY_DISPLAY_SYMBOLS, Key, KeyStateTracker, KeyStateTrackerState, KeyboardEventMatch, LETTER_KEYS, LINUX_MODIFIER_LABELS, LetterKey, LogicalKey, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, Modifier, MultiHotkeyHandler, NAVIGATION_KEYS, NUMBER_KEYS, NamedKey, NavigationKey, NonPunctuationKey, NormalizedKeyboardEvent, NumberKey, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, ParsedHotkey, ParsedModifiers, PhysicalKey, PhysicalKeyCode, PunctuationKey, RawHotkey, RawModifiers, RecorderKeyMode, RecorderOptions, RecorderRejection, RegisterableHotkey, SequenceManager, SequenceOptions, SequenceRegistration, SequenceRegistrationHandle, SequenceRegistrationView, SingleModifierHotkey, Target, ThreeModifierHotkey, TwoModifierHotkey, ValidationResult, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, formatHotkeySequence, formatWithLabels, getHotkeyManager, getKeyStateTracker, getSequenceManager, hasNonModifierKey, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeKeyName, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, rawHotkeyToParsedHotkey, resolveModifier, toHotkeyRegistrationView, validateHotkey };
package/dist/index.js CHANGED
@@ -1,12 +1,16 @@
1
- import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, KEY_DISPLAY_SYMBOLS, LETTER_KEYS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS, detectPlatform, isSingleLetterKey, normalizeKeyName, resolveModifier } from "./constants.js";
2
- import { hasNonModifierKey, isModifierKey, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, rawHotkeyToParsedHotkey } from "./parse.js";
1
+ import { ALL_KEYS, EDITING_KEYS, FUNCTION_KEYS, LETTER_KEYS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, isSingleLetterKey, normalizeKeyName } from "./constants.js";
2
+ import { KEY_DISPLAY_SYMBOLS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, PUNCTUATION_KEY_DISPLAY_LABELS, WINDOWS_MODIFIER_LABELS } from "./display-labels.js";
3
+ import { detectPlatform, resolveModifier } from "./platform.js";
4
+ import { hasNonModifierKey, isModifierKey, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, rawHotkeyToParsedHotkey } from "./parse.js";
3
5
  import { formatForDisplay, formatHotkey, formatHotkeySequence, formatWithLabels } from "./format.js";
4
- import { createHotkeyHandler, createMultiHotkeyHandler, matchesKeyboardEvent } from "./match.js";
6
+ import { assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
7
+ import { areHotkeysEqual, createHotkeyHandler, createMultiHotkeyHandler, matchesKeyboardEvent } from "./match.js";
8
+ import { matchesHeldModifiers } from "./hint.js";
5
9
  import { HotkeyManager, getHotkeyManager, toHotkeyRegistrationView } from "./hotkey-manager.js";
10
+ import { DEFAULT_SEQUENCE_TIMEOUT, SequenceManager, createSequenceMatcher, getSequenceManager } from "./sequence-manager.js";
11
+ import { findHotkeyConflicts } from "./conflicts.js";
6
12
  import { KeyStateTracker, getKeyStateTracker } from "./key-state-tracker.js";
7
13
  import { HotkeyRecorder } from "./hotkey-recorder.js";
8
14
  import { HotkeySequenceRecorder } from "./hotkey-sequence-recorder.js";
9
- import { DEFAULT_SEQUENCE_TIMEOUT, SequenceManager, createSequenceMatcher, getSequenceManager } from "./sequence-manager.js";
10
- import { assertValidHotkey, checkHotkey, validateHotkey } from "./validate.js";
11
15
 
12
- export { ALL_KEYS, DEFAULT_SEQUENCE_TIMEOUT, EDITING_KEYS, FUNCTION_KEYS, HotkeyManager, HotkeyRecorder, HotkeySequenceRecorder, KEY_DISPLAY_SYMBOLS, KeyStateTracker, LETTER_KEYS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, SequenceManager, WINDOWS_MODIFIER_LABELS, assertValidHotkey, checkHotkey, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, detectPlatform, formatForDisplay, formatHotkey, formatHotkeySequence, formatWithLabels, getHotkeyManager, getKeyStateTracker, getSequenceManager, hasNonModifierKey, isModifierKey, isSingleLetterKey, matchesKeyboardEvent, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeKeyName, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, rawHotkeyToParsedHotkey, resolveModifier, toHotkeyRegistrationView, validateHotkey };
16
+ export { ALL_KEYS, DEFAULT_SEQUENCE_TIMEOUT, EDITING_KEYS, FUNCTION_KEYS, HotkeyManager, HotkeyRecorder, HotkeySequenceRecorder, KEY_DISPLAY_SYMBOLS, KeyStateTracker, LETTER_KEYS, LINUX_MODIFIER_LABELS, MAC_MODIFIER_LABELS, MAC_MODIFIER_SYMBOLS, MODIFIER_ALIASES, MODIFIER_KEYS, MODIFIER_ORDER, NAVIGATION_KEYS, NUMBER_KEYS, PUNCTUATION_CODE_MAP, PUNCTUATION_KEYS, PUNCTUATION_KEY_DISPLAY_LABELS, SequenceManager, WINDOWS_MODIFIER_LABELS, areHotkeysEqual, assertValidHotkey, checkHotkey, createHotkeyHandler, createMultiHotkeyHandler, createSequenceMatcher, detectPlatform, findHotkeyConflicts, formatForDisplay, formatHotkey, formatHotkeySequence, formatWithLabels, getHotkeyManager, getKeyStateTracker, getSequenceManager, hasNonModifierKey, isModifierKey, isSingleLetterKey, matchesHeldModifiers, matchesKeyboardEvent, normalizeHotkey, normalizeHotkeyFromEvent, normalizeHotkeyFromParsed, normalizeKeyName, normalizeRegisterableHotkey, parseHotkey, parseKeyboardEvent, parseRegisterableHotkey, rawHotkeyToParsedHotkey, resolveModifier, toHotkeyRegistrationView, validateHotkey };
@@ -1,10 +1,9 @@
1
1
  import { Store } from "@tanstack/store";
2
-
3
2
  //#region src/key-state-tracker.d.ts
4
3
  /**
5
4
  * State interface for the KeyStateTracker.
6
5
  */
7
- interface KeyStateTrackerState {
6
+ export interface KeyStateTrackerState {
8
7
  /**
9
8
  * Array of currently held key names (normalized, e.g. "Control", "A").
10
9
  */
@@ -49,7 +48,7 @@ interface KeyStateTrackerState {
49
48
  * unsubscribe()
50
49
  * ```
51
50
  */
52
- declare class KeyStateTracker {
51
+ export declare class KeyStateTracker {
53
52
  #private;
54
53
  /**
55
54
  * The TanStack Store instance containing the tracker state.
@@ -101,7 +100,5 @@ declare class KeyStateTracker {
101
100
  * Gets the singleton KeyStateTracker instance.
102
101
  * Convenience function for accessing the tracker.
103
102
  */
104
- declare function getKeyStateTracker(): KeyStateTracker;
105
- //#endregion
106
- export { KeyStateTracker, KeyStateTrackerState, getKeyStateTracker };
107
- //# sourceMappingURL=key-state-tracker.d.ts.map
103
+ export declare function getKeyStateTracker(): KeyStateTracker;
104
+ //#endregion
@@ -47,13 +47,16 @@ function getDefaultKeyStateTrackerState() {
47
47
  */
48
48
  var KeyStateTracker = class KeyStateTracker {
49
49
  static #instance = null;
50
- #heldKeysSet = /* @__PURE__ */ new Set();
51
- #heldCodesMap = /* @__PURE__ */ new Map();
50
+ /**
51
+ * The TanStack Store instance containing the tracker state.
52
+ * Use this to subscribe to state changes or access current state.
53
+ */
54
+ store = new Store(getDefaultKeyStateTrackerState());
55
+ #heldEntries = /* @__PURE__ */ new Map();
52
56
  #keydownListener = null;
53
57
  #keyupListener = null;
54
58
  #blurListener = null;
55
59
  constructor() {
56
- this.store = new Store(getDefaultKeyStateTrackerState());
57
60
  this.#setupListeners();
58
61
  }
59
62
  /**
@@ -79,44 +82,46 @@ var KeyStateTracker = class KeyStateTracker {
79
82
  if (typeof document === "undefined") return;
80
83
  this.#keydownListener = (event) => {
81
84
  const key = normalizeKeyName(event.key);
82
- if (!this.#heldKeysSet.has(key)) {
83
- this.#heldKeysSet.add(key);
84
- this.#heldCodesMap.set(key, event.code);
85
+ const identity = event.code || `key:${key}`;
86
+ if (!this.#heldEntries.has(identity)) {
87
+ this.#heldEntries.set(identity, {
88
+ key,
89
+ code: event.code
90
+ });
85
91
  this.#syncState();
86
92
  }
87
93
  };
88
94
  this.#keyupListener = (event) => {
89
95
  const key = normalizeKeyName(event.key);
90
- if (this.#heldKeysSet.has(key)) {
91
- this.#heldKeysSet.delete(key);
92
- this.#heldCodesMap.delete(key);
96
+ const identity = event.code || `key:${key}`;
97
+ this.#heldEntries.delete(identity);
98
+ if (!event.code) {
99
+ for (const [entryIdentity, entry] of this.#heldEntries) if (entry.key === key) this.#heldEntries.delete(entryIdentity);
93
100
  }
94
101
  if (MODIFIER_KEYS.has(key)) {
95
- for (const heldKey of this.#heldKeysSet) if (!MODIFIER_KEYS.has(heldKey)) {
96
- this.#heldKeysSet.delete(heldKey);
97
- this.#heldCodesMap.delete(heldKey);
98
- }
102
+ for (const [entryIdentity, entry] of this.#heldEntries) if (!MODIFIER_KEYS.has(entry.key)) this.#heldEntries.delete(entryIdentity);
99
103
  }
100
104
  this.#syncState();
101
105
  };
102
106
  this.#blurListener = () => {
103
- if (this.#heldKeysSet.size > 0) {
104
- this.#heldKeysSet.clear();
105
- this.#heldCodesMap.clear();
107
+ if (this.#heldEntries.size > 0) {
108
+ this.#heldEntries.clear();
106
109
  this.#syncState();
107
110
  }
108
111
  };
109
- document.addEventListener("keydown", this.#keydownListener);
110
- document.addEventListener("keyup", this.#keyupListener);
112
+ document.addEventListener("keydown", this.#keydownListener, true);
113
+ document.addEventListener("keyup", this.#keyupListener, true);
111
114
  window.addEventListener("blur", this.#blurListener);
112
115
  }
113
116
  /**
114
117
  * Syncs the internal Set to the Store state.
115
118
  */
116
119
  #syncState() {
120
+ const heldKeys = Array.from(new Set(Array.from(this.#heldEntries.values(), (entry) => entry.key)));
121
+ const heldCodes = Object.fromEntries(Array.from(this.#heldEntries.values(), (entry) => [entry.key, entry.code]));
117
122
  this.store.setState(() => ({
118
- heldKeys: Array.from(this.#heldKeysSet),
119
- heldCodes: Object.fromEntries(this.#heldCodesMap)
123
+ heldKeys,
124
+ heldCodes
120
125
  }));
121
126
  }
122
127
  /**
@@ -125,11 +130,11 @@ var KeyStateTracker = class KeyStateTracker {
125
130
  #removeListeners() {
126
131
  if (typeof document === "undefined") return;
127
132
  if (this.#keydownListener) {
128
- document.removeEventListener("keydown", this.#keydownListener);
133
+ document.removeEventListener("keydown", this.#keydownListener, true);
129
134
  this.#keydownListener = null;
130
135
  }
131
136
  if (this.#keyupListener) {
132
- document.removeEventListener("keyup", this.#keyupListener);
137
+ document.removeEventListener("keyup", this.#keyupListener, true);
133
138
  this.#keyupListener = null;
134
139
  }
135
140
  if (this.#blurListener) {
@@ -153,7 +158,7 @@ var KeyStateTracker = class KeyStateTracker {
153
158
  */
154
159
  isKeyHeld(key) {
155
160
  const normalizedKey = normalizeKeyName(key);
156
- return this.#heldKeysSet.has(normalizedKey);
161
+ return Array.from(this.#heldEntries.values()).some((entry) => entry.key === normalizedKey);
157
162
  }
158
163
  /**
159
164
  * Checks if any of the given keys are currently held.
@@ -178,8 +183,7 @@ var KeyStateTracker = class KeyStateTracker {
178
183
  */
179
184
  destroy() {
180
185
  this.#removeListeners();
181
- this.#heldKeysSet.clear();
182
- this.#heldCodesMap.clear();
186
+ this.#heldEntries.clear();
183
187
  this.store.setState(() => getDefaultKeyStateTrackerState());
184
188
  }
185
189
  };
@@ -192,5 +196,4 @@ function getKeyStateTracker() {
192
196
  }
193
197
 
194
198
  //#endregion
195
- export { KeyStateTracker, getKeyStateTracker };
196
- //# sourceMappingURL=key-state-tracker.js.map
199
+ export { KeyStateTracker, getKeyStateTracker };
@@ -0,0 +1,79 @@
1
+ import { LOGICAL_ONLY_NAMED_KEYS, SHARED_NAMED_KEYS } from "./_named-keys.js";
2
+ //#region src/key.types.d.ts
3
+ /**
4
+ * All supported modifier key names, including aliases.
5
+ * - Control/Ctrl: The Control key
6
+ * - Shift: The Shift key
7
+ * - Alt/Option: The Alt key (Option on macOS)
8
+ * - Command/Cmd: The Command key (macOS only)
9
+ * - CommandOrControl/Mod: Command on macOS, Control on other platforms
10
+ */
11
+ export type Modifier = 'Control' | 'Ctrl' | 'Shift' | 'Alt' | 'Option' | 'Command' | 'Cmd' | 'CommandOrControl' | 'Mod';
12
+ /**
13
+ * Canonical modifier names that map to KeyboardEvent properties.
14
+ */
15
+ export type CanonicalModifier = 'Control' | 'Shift' | 'Alt' | 'Meta';
16
+ /**
17
+ * Letter keys A-Z (case-insensitive in matching).
18
+ */
19
+ export type LetterKey = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
20
+ /**
21
+ * Number keys 0-9.
22
+ */
23
+ export type NumberKey = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
24
+ /**
25
+ * Function keys F1-F24, supported as both logical keys and physical codes.
26
+ */
27
+ export type FunctionKey = 'F1' | 'F2' | 'F3' | 'F4' | 'F5' | 'F6' | 'F7' | 'F8' | 'F9' | 'F10' | 'F11' | 'F12' | 'F13' | 'F14' | 'F15' | 'F16' | 'F17' | 'F18' | 'F19' | 'F20' | 'F21' | 'F22' | 'F23' | 'F24';
28
+ /**
29
+ * Navigation keys for cursor movement.
30
+ */
31
+ export type NavigationKey = 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'Home' | 'End' | 'PageUp' | 'PageDown';
32
+ /**
33
+ * Editing and special keys.
34
+ */
35
+ export type EditingKey = 'Enter' | 'Escape' | 'Space' | 'Tab' | 'Backspace' | 'Delete';
36
+ /**
37
+ * Printable punctuation glyphs used in keyboard shortcuts. Matching uses the
38
+ * final KeyboardEvent.key glyph, independent of which layout produced it.
39
+ */
40
+ export type PunctuationKey = '/' | '[' | ']' | '\\' | '=' | '-' | ',' | '.' | ';' | '`' | "'" | '+' | '?' | '!' | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '(' | ')' | '_' | '{' | '}' | '|' | ':' | '"' | '<' | '>' | '~';
41
+ /** Additional named logical keys, including media, browser, lock, and input-mode keys. */
42
+ export type NamedKey = (typeof SHARED_NAMED_KEYS)[number] | (typeof LOGICAL_ONLY_NAMED_KEYS)[number];
43
+ /** Supported logical key names other than printable punctuation. */
44
+ export type NonPunctuationKey = LetterKey | NumberKey | EditingKey | NavigationKey | FunctionKey | NamedKey;
45
+ /**
46
+ * Supported physical KeyboardEvent.code names, independent of keyboard layout.
47
+ * Letter, digit, numpad, and sided modifier names use finite template unions.
48
+ * `Unidentified` is excluded because it cannot identify a physical key.
49
+ *
50
+ * @see https://www.w3.org/TR/uievents-code/
51
+ */
52
+ export type PhysicalKeyCode = `Key${LetterKey}` | `Digit${NumberKey}` | `Numpad${NumberKey}` | `${'Alt' | 'Control' | 'Meta' | 'Shift'}${'Left' | 'Right'}` | EditingKey | NavigationKey | FunctionKey | (typeof SHARED_NAMED_KEYS)[number] | 'Backquote' | 'Backslash' | 'BracketLeft' | 'BracketRight' | 'Comma' | 'Equal' | 'IntlBackslash' | 'IntlRo' | 'IntlYen' | 'Minus' | 'Period' | 'Quote' | 'Semicolon' | 'Slash' | `Lang${1 | 2 | 3 | 4 | 5}` | `Numpad${'Add' | 'Backspace' | 'Clear' | 'ClearEntry' | 'Comma' | 'Decimal' | 'Divide' | 'Enter' | 'Equal' | 'Hash' | 'MemoryAdd' | 'MemoryClear' | 'MemoryRecall' | 'MemoryStore' | 'MemorySubtract' | 'Multiply' | 'ParenLeft' | 'ParenRight' | 'Star' | 'Subtract'}` | 'LaunchApp1' | 'LaunchApp2' | 'MediaSelect' | 'Sleep' | 'Turbo' | 'Abort' | 'Resume' | 'Suspend';
53
+ /**
54
+ * An explicit physical key token. All codes use brackets, including names such
55
+ * as `[Enter]` that also exist as logical keys. Invalid code names are rejected
56
+ * by TypeScript, and supported names are available in autocomplete.
57
+ */
58
+ export type PhysicalKey = `[${PhysicalKeyCode}]`;
59
+ /** Supported logical key names, excluding bracketed physical-code syntax. */
60
+ export type LogicalKey = NonPunctuationKey | PunctuationKey;
61
+ /** All supported logical keys and bracketed physical key tokens. */
62
+ export type Key = LogicalKey | PhysicalKey;
63
+ /**
64
+ * Includes both modifier keys and regular keys.
65
+ */
66
+ export type IndividualKey = CanonicalModifier | Key;
67
+ /** Keyboard event properties normalized for internal matching and recording. */
68
+ export interface NormalizedKeyboardEvent {
69
+ key: string;
70
+ code: string;
71
+ ctrl: boolean;
72
+ shift: boolean;
73
+ alt: boolean;
74
+ meta: boolean;
75
+ altGraph: boolean;
76
+ location: number;
77
+ isComposing: boolean;
78
+ }
79
+ //#endregion
package/dist/match.d.ts CHANGED
@@ -1,10 +1,19 @@
1
- import { Hotkey, HotkeyCallback, ParsedHotkey } from "./hotkey.js";
2
-
1
+ import { Hotkey, HotkeyCallback, ParsedHotkey, RegisterableHotkey } from "./hotkey.types.js";
3
2
  //#region src/match.d.ts
3
+ export interface KeyboardEventMatch {
4
+ matched: boolean;
5
+ score: 0 | 1 | 2 | 3;
6
+ source?: 'key' | 'code' | 'fallback';
7
+ identity?: {
8
+ key: string;
9
+ code: string;
10
+ };
11
+ }
4
12
  /**
5
13
  * Checks if a KeyboardEvent matches a hotkey.
6
14
  *
7
- * Uses the `key` property from KeyboardEvent for matching, with a fallback to `code`
15
+ * Physical bindings such as `Mod+[KeyS]` match `event.code` exactly.
16
+ * Logical bindings use `event.key`, with a fallback to `code`
8
17
  * for letter keys, digit keys (0-9), and punctuation keys when `key` produces special
9
18
  * characters (e.g., macOS Option+letter, Shift+number, or Option+punctuation).
10
19
  * Letter keys are matched case-insensitively.
@@ -29,11 +38,11 @@ import { Hotkey, HotkeyCallback, ParsedHotkey } from "./hotkey.js";
29
38
  * })
30
39
  * ```
31
40
  */
32
- declare function matchesKeyboardEvent(event: KeyboardEvent, hotkey: Hotkey | ParsedHotkey, platform?: 'mac' | 'windows' | 'linux'): boolean;
41
+ export declare function matchesKeyboardEvent(event: KeyboardEvent, hotkey: Hotkey | ParsedHotkey, platform?: 'mac' | 'windows' | 'linux'): boolean;
33
42
  /**
34
43
  * Options for creating a hotkey handler.
35
44
  */
36
- interface CreateHotkeyHandlerOptions {
45
+ export interface CreateHotkeyHandlerOptions {
37
46
  /** Prevent the default browser action when the hotkey matches. Defaults to true */
38
47
  preventDefault?: boolean;
39
48
  /** Stop event propagation when the hotkey matches. Defaults to true */
@@ -59,8 +68,8 @@ interface CreateHotkeyHandlerOptions {
59
68
  * document.addEventListener('keydown', handler)
60
69
  * ```
61
70
  */
62
- declare function createHotkeyHandler(hotkey: Hotkey | ParsedHotkey, callback: HotkeyCallback, options?: CreateHotkeyHandlerOptions): (event: KeyboardEvent) => void;
63
- type MultiHotkeyHandler = { [K in Hotkey]?: HotkeyCallback };
71
+ export declare function createHotkeyHandler(hotkey: Hotkey | ParsedHotkey, callback: HotkeyCallback, options?: CreateHotkeyHandlerOptions): (event: KeyboardEvent) => void;
72
+ export type MultiHotkeyHandler = { [K in Hotkey]?: HotkeyCallback; };
64
73
  /**
65
74
  * Creates a handler that matches multiple hotkeys.
66
75
  *
@@ -79,7 +88,11 @@ type MultiHotkeyHandler = { [K in Hotkey]?: HotkeyCallback };
79
88
  * document.addEventListener('keydown', handler)
80
89
  * ```
81
90
  */
82
- declare function createMultiHotkeyHandler(handlers: MultiHotkeyHandler, options?: CreateHotkeyHandlerOptions): (event: KeyboardEvent) => void;
83
- //#endregion
84
- export { CreateHotkeyHandlerOptions, createHotkeyHandler, createMultiHotkeyHandler, matchesKeyboardEvent };
85
- //# sourceMappingURL=match.d.ts.map
91
+ export declare function createMultiHotkeyHandler(handlers: MultiHotkeyHandler, options?: CreateHotkeyHandlerOptions): (event: KeyboardEvent) => void;
92
+ /**
93
+ * Compares normalized binding identity, including all four modifiers.
94
+ * Aliases resolve on the supplied platform. A physical code and a logical key
95
+ * remain distinct even when one keyboard event could match both.
96
+ */
97
+ export declare function areHotkeysEqual(left: RegisterableHotkey, right: RegisterableHotkey, platform?: "mac" | "windows" | "linux"): boolean;
98
+ //#endregion