@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
package/src/parse.ts DELETED
@@ -1,328 +0,0 @@
1
- import {
2
- MODIFIER_ALIASES,
3
- MODIFIER_ORDER,
4
- detectPlatform,
5
- normalizeKeyName,
6
- resolveModifier,
7
- } from './constants'
8
- import type {
9
- CanonicalModifier,
10
- Hotkey,
11
- Key,
12
- ParsedHotkey,
13
- RawHotkey,
14
- RegisterableHotkey,
15
- } from './hotkey'
16
-
17
- /**
18
- * Parses a hotkey string into its component parts.
19
- *
20
- * @param hotkey - The hotkey string to parse (e.g., 'Mod+Shift+S')
21
- * @param platform - The target platform for resolving 'Mod' (defaults to auto-detection)
22
- * @returns A ParsedHotkey object with the key and modifier flags
23
- *
24
- * @example
25
- * ```ts
26
- * parseHotkey('Mod+S') // On Mac: { key: 'S', ctrl: false, shift: false, alt: false, meta: true, modifiers: ['Meta'] }
27
- * parseHotkey('Mod+S') // On Windows: { key: 'S', ctrl: true, shift: false, alt: false, meta: false, modifiers: ['Control'] }
28
- * parseHotkey('Control+Shift+A') // { key: 'A', ctrl: true, shift: true, alt: false, meta: false, modifiers: ['Control', 'Shift'] }
29
- * ```
30
- */
31
- export function parseHotkey(
32
- hotkey: Hotkey | (string & {}),
33
- platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
34
- ): ParsedHotkey {
35
- const parts = hotkey.split('+')
36
- const modifiers: Set<CanonicalModifier> = new Set()
37
- let key = ''
38
-
39
- for (let i = 0; i < parts.length; i++) {
40
- const part = parts[i]!.trim()
41
-
42
- if (i === parts.length - 1) {
43
- // Last part is always the key
44
- key = normalizeKeyName(part)
45
- } else {
46
- // All other parts are modifiers
47
- const alias =
48
- MODIFIER_ALIASES[part] ?? MODIFIER_ALIASES[part.toLowerCase()]
49
-
50
- if (alias) {
51
- const resolved = resolveModifier(alias, platform)
52
- modifiers.add(resolved)
53
- } else {
54
- // Unknown modifier, treat as part of the key if it's the only part
55
- // or ignore if there are more parts
56
- if (parts.length === 1) {
57
- key = normalizeKeyName(part)
58
- }
59
- }
60
- }
61
- }
62
-
63
- // If no key was found (empty string), use the last part as-is
64
- if (!key && parts.length > 0) {
65
- key = normalizeKeyName(parts[parts.length - 1]!.trim())
66
- }
67
-
68
- return {
69
- key,
70
- ctrl: modifiers.has('Control'),
71
- shift: modifiers.has('Shift'),
72
- alt: modifiers.has('Alt'),
73
- meta: modifiers.has('Meta'),
74
- modifiers: MODIFIER_ORDER.filter((m) => modifiers.has(m)),
75
- }
76
- }
77
-
78
- /**
79
- * Converts a RawHotkey object to a ParsedHotkey.
80
- * Optional modifier booleans default to false; modifiers array is derived from them.
81
- * When `mod` is true, it is resolved to Control or Meta based on platform.
82
- *
83
- * @param raw - The raw hotkey object
84
- * @param platform - The target platform for resolving 'Mod' (defaults to auto-detection)
85
- * @returns A ParsedHotkey suitable for matching and formatting
86
- *
87
- * @example
88
- * ```ts
89
- * rawHotkeyToParsedHotkey({ key: 'Escape' })
90
- * // { key: 'Escape', ctrl: false, shift: false, alt: false, meta: false, modifiers: [] }
91
- *
92
- * rawHotkeyToParsedHotkey({ key: 'S', mod: true }, 'mac')
93
- * // { key: 'S', ctrl: false, shift: false, alt: false, meta: true, modifiers: ['Meta'] }
94
- *
95
- * rawHotkeyToParsedHotkey({ key: 'S', mod: true, shift: true }, 'windows')
96
- * // { key: 'S', ctrl: true, shift: true, alt: false, meta: false, modifiers: ['Control', 'Shift'] }
97
- * ```
98
- */
99
- export function rawHotkeyToParsedHotkey(
100
- raw: RawHotkey,
101
- platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
102
- ): ParsedHotkey {
103
- let ctrl = raw.ctrl ?? false
104
- const shift = raw.shift ?? false
105
- const alt = raw.alt ?? false
106
- let meta = raw.meta ?? false
107
-
108
- if (raw.mod) {
109
- const resolved = resolveModifier('Mod', platform)
110
- if (resolved === 'Control') {
111
- ctrl = true
112
- } else {
113
- meta = true
114
- }
115
- }
116
-
117
- const modifiers: Array<CanonicalModifier> = MODIFIER_ORDER.filter((m) => {
118
- switch (m) {
119
- case 'Control':
120
- return ctrl
121
- case 'Shift':
122
- return shift
123
- case 'Alt':
124
- return alt
125
- case 'Meta':
126
- return meta
127
- default:
128
- return false
129
- }
130
- })
131
- return {
132
- key: raw.key,
133
- ctrl,
134
- shift,
135
- alt,
136
- meta,
137
- modifiers,
138
- }
139
- }
140
-
141
- /**
142
- * Serializes a parsed hotkey to the canonical string form used for registration
143
- * and storage: `Mod` first when the platform allows, then `Alt`, then `Shift`;
144
- * otherwise full `Control+Alt+Shift+Meta` order.
145
- */
146
- function normalizedHotkeyStringFromParsed(
147
- parsed: ParsedHotkey,
148
- platform: 'mac' | 'windows' | 'linux',
149
- ): Hotkey {
150
- const canUseMod =
151
- platform === 'mac'
152
- ? parsed.meta && !parsed.ctrl
153
- : parsed.ctrl && !parsed.meta
154
-
155
- const parts: Array<string> = []
156
-
157
- if (canUseMod) {
158
- parts.push('Mod')
159
- if (parsed.alt) {
160
- parts.push('Alt')
161
- }
162
- if (parsed.shift) {
163
- parts.push('Shift')
164
- }
165
- } else {
166
- for (const modifier of MODIFIER_ORDER) {
167
- if (parsed.modifiers.includes(modifier)) {
168
- parts.push(modifier)
169
- }
170
- }
171
- }
172
-
173
- parts.push(normalizeKeyName(parsed.key))
174
- return parts.join('+') as Hotkey
175
- }
176
-
177
- /**
178
- * Normalizes a hotkey string to its canonical form.
179
- *
180
- * - When `Mod` is allowed for the platform (Command on Mac without Control;
181
- * Control on Windows/Linux without Meta): emits `Mod`, then `Alt`, then `Shift`,
182
- * then the key (e.g. `Mod+Shift+E`, `Mod+S`).
183
- * - Otherwise: literal modifiers in `Control+Alt+Shift+Meta` order, then the key.
184
- * - Resolves aliases and normalizes key casing (e.g. `esc` → `Escape`, `a` → `A`).
185
- *
186
- * @param hotkey - The hotkey string to normalize
187
- * @param platform - The target platform for resolving `Mod` (defaults to auto-detection)
188
- * @returns The normalized hotkey string
189
- *
190
- * @example
191
- * ```ts
192
- * normalizeHotkey('shift+meta+e', 'mac') // 'Mod+Shift+E'
193
- * normalizeHotkey('ctrl+a', 'windows') // 'Mod+A'
194
- * normalizeHotkey('esc') // 'Escape'
195
- * ```
196
- */
197
- export function normalizeHotkey(
198
- hotkey: Key | (string & {}),
199
- platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
200
- ): Hotkey {
201
- return normalizedHotkeyStringFromParsed(
202
- parseHotkey(hotkey, platform),
203
- platform,
204
- )
205
- }
206
-
207
- /**
208
- * Same canonical string as {@link normalizeHotkey}, but from an already-parsed hotkey.
209
- */
210
- export function normalizeHotkeyFromParsed(
211
- parsed: ParsedHotkey,
212
- platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
213
- ): Hotkey {
214
- return normalizedHotkeyStringFromParsed(parsed, platform)
215
- }
216
-
217
- /**
218
- * Normalizes a string or {@link RawHotkey} object to the same canonical hotkey string.
219
- * Use this in framework adapters instead of branching on `formatHotkey(rawHotkeyToParsedHotkey(...))`.
220
- */
221
- export function normalizeRegisterableHotkey(
222
- hotkey: RegisterableHotkey,
223
- platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
224
- ): Hotkey {
225
- return typeof hotkey === 'string'
226
- ? normalizeHotkey(hotkey, platform)
227
- : normalizeHotkeyFromParsed(
228
- rawHotkeyToParsedHotkey(hotkey, platform),
229
- platform,
230
- )
231
- }
232
-
233
- /**
234
- * Checks if a string is a recognized modifier token (including aliases).
235
- *
236
- * For a `KeyboardEvent`, use `isModifier(normalizeKeyName(event.key))` so DOM
237
- * spellings like `OS` / `Win` match the same alias table.
238
- *
239
- * @param key - Key name or alias (e.g. from a hotkey string or `event.key`)
240
- * @returns True if the string is a recognized modifier
241
- */
242
- export function isModifierKey(
243
- key: Key | (string & {}),
244
- ): key is keyof typeof MODIFIER_ALIASES {
245
- return key in MODIFIER_ALIASES || key.toLowerCase() in MODIFIER_ALIASES
246
- }
247
-
248
- /**
249
- * Parses a KeyboardEvent into a ParsedHotkey object.
250
- *
251
- * This function extracts the key and modifier state from a keyboard event
252
- * and converts it into the same format used by `parseHotkey()`.
253
- *
254
- * @param event - The KeyboardEvent to parse
255
- * @param platform - The target platform for resolving modifiers (defaults to auto-detection)
256
- * @returns A ParsedHotkey object representing the keyboard event
257
- *
258
- * @example
259
- * ```ts
260
- * document.addEventListener('keydown', (event) => {
261
- * const parsed = parseKeyboardEvent(event)
262
- * console.log(parsed) // { key: 'S', ctrl: true, shift: false, ... }
263
- * })
264
- * ```
265
- */
266
- export function parseKeyboardEvent(event: KeyboardEvent): ParsedHotkey {
267
- const normalizedKey = normalizeKeyName(event.key)
268
-
269
- // Build modifiers array in canonical order
270
- const modifiers: Array<CanonicalModifier> = []
271
- if (event.ctrlKey) modifiers.push('Control')
272
- if (event.altKey) modifiers.push('Alt')
273
- if (event.shiftKey) modifiers.push('Shift')
274
- if (event.metaKey) modifiers.push('Meta')
275
-
276
- return {
277
- key: normalizedKey,
278
- ctrl: event.ctrlKey,
279
- shift: event.shiftKey,
280
- alt: event.altKey,
281
- meta: event.metaKey,
282
- modifiers,
283
- }
284
- }
285
-
286
- /**
287
- * Normalizes a keyboard event to the same canonical hotkey string as {@link normalizeHotkey}.
288
- *
289
- * @param event - The keyboard event (typically `keydown`)
290
- * @param platform - Target platform for `Mod` eligibility
291
- */
292
- export function normalizeHotkeyFromEvent(
293
- event: KeyboardEvent,
294
- platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
295
- ): Hotkey {
296
- return normalizedHotkeyStringFromParsed(parseKeyboardEvent(event), platform)
297
- }
298
-
299
- /**
300
- * Checks if a hotkey or ParsedHotkey contains at least one non-modifier key.
301
- *
302
- * This is useful for validating that a recorded hotkey is complete and not
303
- * just a combination of modifiers without an action key.
304
- *
305
- * @param hotkey - The hotkey string or ParsedHotkey to check
306
- * @param platform - The target platform for parsing (defaults to auto-detection)
307
- * @returns True if the hotkey contains at least one non-modifier key
308
- *
309
- * @example
310
- * ```ts
311
- * hasNonModifierKey('Control+Shift+S') // true
312
- * hasNonModifierKey('Control+Shift') // false (no action key)
313
- * hasNonModifierKey(parseHotkey('Mod+A')) // true
314
- * ```
315
- */
316
- export function hasNonModifierKey(
317
- hotkey: Hotkey | ParsedHotkey | (string & {}),
318
- platform: 'mac' | 'windows' | 'linux' = detectPlatform(),
319
- ): boolean {
320
- const parsed =
321
- typeof hotkey === 'string' ? parseHotkey(hotkey, platform) : hotkey
322
-
323
- // Check if the key part is actually a modifier
324
- const keyIsModifier = isModifierKey(parsed.key)
325
-
326
- // A valid hotkey must have a non-modifier key
327
- return !keyIsModifier && parsed.key.length > 0
328
- }
@@ -1,25 +0,0 @@
1
- import { normalizeKeyName } from './constants'
2
- import {
3
- hasNonModifierKey,
4
- isModifierKey,
5
- normalizeHotkeyFromEvent,
6
- } from './parse'
7
- import type { Hotkey } from './hotkey'
8
-
9
- /**
10
- * Parses a keydown event into a single normalized hotkey chord, or null if
11
- * the event should be ignored (modifier-only or invalid).
12
- */
13
- export function hotkeyChordFromKeydown(
14
- event: KeyboardEvent,
15
- platform: 'mac' | 'windows' | 'linux',
16
- ): Hotkey | null {
17
- if (isModifierKey(normalizeKeyName(event.key))) {
18
- return null
19
- }
20
- const finalHotkey = normalizeHotkeyFromEvent(event, platform)
21
- if (!hasNonModifierKey(finalHotkey, platform)) {
22
- return null
23
- }
24
- return finalHotkey
25
- }