@tanstack/vue-hotkeys 0.11.0 → 0.12.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 (96) hide show
  1. package/dist/HotkeysProvider.d.ts +5 -9
  2. package/dist/HotkeysProvider.js +1 -2
  3. package/dist/HotkeysProviderContext.d.ts +5 -8
  4. package/dist/HotkeysProviderContext.js +1 -2
  5. package/dist/useHeldKeyCodes.d.ts +2 -5
  6. package/dist/useHeldKeyCodes.js +3 -3
  7. package/dist/useHeldKeys.d.ts +2 -5
  8. package/dist/useHeldKeys.js +3 -3
  9. package/dist/useHotkey.d.ts +3 -6
  10. package/dist/useHotkey.js +3 -3
  11. package/dist/useHotkeyHint.d.ts +2 -5
  12. package/dist/useHotkeyHint.js +1 -2
  13. package/dist/useHotkeyRecorder.d.ts +3 -6
  14. package/dist/useHotkeyRecorder.js +1 -2
  15. package/dist/useHotkeyRegistrations.d.ts +3 -6
  16. package/dist/useHotkeyRegistrations.js +1 -2
  17. package/dist/useHotkeySequence.d.ts +3 -6
  18. package/dist/useHotkeySequence.js +1 -2
  19. package/dist/useHotkeySequenceRecorder.d.ts +3 -6
  20. package/dist/useHotkeySequenceRecorder.js +1 -2
  21. package/dist/useHotkeySequences.d.ts +3 -6
  22. package/dist/useHotkeySequences.js +1 -2
  23. package/dist/useHotkeys.d.ts +3 -6
  24. package/dist/useHotkeys.js +3 -3
  25. package/dist/useKeyHold.d.ts +2 -5
  26. package/dist/useKeyHold.js +3 -3
  27. package/package.json +12 -17
  28. package/dist/HotkeysProvider.cjs +0 -31
  29. package/dist/HotkeysProvider.cjs.map +0 -1
  30. package/dist/HotkeysProvider.d.cts +0 -34
  31. package/dist/HotkeysProvider.js.map +0 -1
  32. package/dist/HotkeysProviderContext.cjs +0 -20
  33. package/dist/HotkeysProviderContext.cjs.map +0 -1
  34. package/dist/HotkeysProviderContext.d.cts +0 -20
  35. package/dist/HotkeysProviderContext.js.map +0 -1
  36. package/dist/index.cjs +0 -37
  37. package/dist/index.d.cts +0 -15
  38. package/dist/useHeldKeyCodes.cjs +0 -37
  39. package/dist/useHeldKeyCodes.cjs.map +0 -1
  40. package/dist/useHeldKeyCodes.d.cts +0 -33
  41. package/dist/useHeldKeyCodes.js.map +0 -1
  42. package/dist/useHeldKeys.cjs +0 -35
  43. package/dist/useHeldKeys.cjs.map +0 -1
  44. package/dist/useHeldKeys.d.cts +0 -31
  45. package/dist/useHeldKeys.js.map +0 -1
  46. package/dist/useHotkey.cjs +0 -140
  47. package/dist/useHotkey.cjs.map +0 -1
  48. package/dist/useHotkey.d.cts +0 -86
  49. package/dist/useHotkey.js.map +0 -1
  50. package/dist/useHotkeyHint.cjs +0 -20
  51. package/dist/useHotkeyHint.cjs.map +0 -1
  52. package/dist/useHotkeyHint.d.cts +0 -15
  53. package/dist/useHotkeyHint.js.map +0 -1
  54. package/dist/useHotkeyRecorder.cjs +0 -80
  55. package/dist/useHotkeyRecorder.cjs.map +0 -1
  56. package/dist/useHotkeyRecorder.d.cts +0 -61
  57. package/dist/useHotkeyRecorder.js.map +0 -1
  58. package/dist/useHotkeyRegistrations.cjs +0 -26
  59. package/dist/useHotkeyRegistrations.cjs.map +0 -1
  60. package/dist/useHotkeyRegistrations.d.cts +0 -27
  61. package/dist/useHotkeyRegistrations.js.map +0 -1
  62. package/dist/useHotkeySequence.cjs +0 -122
  63. package/dist/useHotkeySequence.cjs.map +0 -1
  64. package/dist/useHotkeySequence.d.cts +0 -68
  65. package/dist/useHotkeySequence.js.map +0 -1
  66. package/dist/useHotkeySequenceRecorder.cjs +0 -45
  67. package/dist/useHotkeySequenceRecorder.cjs.map +0 -1
  68. package/dist/useHotkeySequenceRecorder.d.cts +0 -20
  69. package/dist/useHotkeySequenceRecorder.js.map +0 -1
  70. package/dist/useHotkeySequences.cjs +0 -140
  71. package/dist/useHotkeySequences.cjs.map +0 -1
  72. package/dist/useHotkeySequences.d.cts +0 -64
  73. package/dist/useHotkeySequences.js.map +0 -1
  74. package/dist/useHotkeys.cjs +0 -139
  75. package/dist/useHotkeys.cjs.map +0 -1
  76. package/dist/useHotkeys.d.cts +0 -65
  77. package/dist/useHotkeys.js.map +0 -1
  78. package/dist/useKeyHold.cjs +0 -60
  79. package/dist/useKeyHold.cjs.map +0 -1
  80. package/dist/useKeyHold.d.cts +0 -52
  81. package/dist/useKeyHold.js.map +0 -1
  82. package/src/HotkeysProvider.tsx +0 -29
  83. package/src/HotkeysProviderContext.ts +0 -41
  84. package/src/index.ts +0 -19
  85. package/src/useHeldKeyCodes.ts +0 -34
  86. package/src/useHeldKeys.ts +0 -32
  87. package/src/useHotkey.ts +0 -213
  88. package/src/useHotkeyHint.ts +0 -25
  89. package/src/useHotkeyRecorder.ts +0 -112
  90. package/src/useHotkeyRegistrations.ts +0 -46
  91. package/src/useHotkeySequence.ts +0 -187
  92. package/src/useHotkeySequenceRecorder.ts +0 -75
  93. package/src/useHotkeySequences.ts +0 -221
  94. package/src/useHotkeys.ts +0 -221
  95. package/src/useKeyHold.ts +0 -65
  96. package/src/vue.d.ts +0 -6
@@ -1,221 +0,0 @@
1
- import { onUnmounted, unref, watch } from 'vue'
2
- import { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'
3
- import { useDefaultHotkeysOptions } from './HotkeysProviderContext'
4
- import type { UseHotkeySequenceOptions } from './useHotkeySequence'
5
- import type {
6
- HotkeyCallback,
7
- HotkeySequence,
8
- SequenceRegistrationHandle,
9
- } from '@tanstack/hotkeys'
10
- import type { MaybeRefOrGetter } from 'vue'
11
-
12
- /**
13
- * A single sequence definition for use with `useHotkeySequences`.
14
- */
15
- export interface UseHotkeySequenceDefinition {
16
- /** Array of hotkey strings that form the sequence */
17
- sequence: MaybeRefOrGetter<HotkeySequence>
18
- /** The function to call when the sequence is completed */
19
- callback: HotkeyCallback
20
- /** Per-sequence options (merged on top of commonOptions) */
21
- options?: MaybeRefOrGetter<UseHotkeySequenceOptions>
22
- }
23
-
24
- /**
25
- * Vue composable for registering multiple keyboard shortcut sequences at once (Vim-style).
26
- *
27
- * Uses the singleton SequenceManager. Accepts a dynamic array of definitions, or a getter/ref
28
- * that returns one, so you can register variable-length lists safely.
29
- *
30
- * Options are merged in this order:
31
- * HotkeysProvider defaults < commonOptions < per-definition options
32
- *
33
- * Definitions with an empty `sequence` are skipped (no registration).
34
- *
35
- * @param definitions - Array of sequence definitions, or a getter/ref
36
- * @param commonOptions - Shared options applied to all sequences (overridden by per-definition options)
37
- *
38
- * @example
39
- * ```vue
40
- * <script setup>
41
- * import { useHotkeySequences } from '@tanstack/vue-hotkeys'
42
- *
43
- * useHotkeySequences([
44
- * { sequence: ['G', 'G'], callback: () => scrollToTop() },
45
- * { sequence: ['D', 'D'], callback: () => deleteLine() },
46
- * ])
47
- * </script>
48
- * ```
49
- *
50
- * @example
51
- * ```vue
52
- * <script setup>
53
- * import { computed } from 'vue'
54
- * import { useHotkeySequences } from '@tanstack/vue-hotkeys'
55
- *
56
- * const items = computed(() => [...])
57
- * useHotkeySequences(
58
- * () => items.value.map((item) => ({
59
- * sequence: item.chords,
60
- * callback: item.action,
61
- * options: { enabled: item.enabled },
62
- * })),
63
- * { preventDefault: true },
64
- * )
65
- * </script>
66
- * ```
67
- */
68
- export function useHotkeySequences(
69
- definitions: MaybeRefOrGetter<Array<UseHotkeySequenceDefinition>>,
70
- commonOptions: MaybeRefOrGetter<UseHotkeySequenceOptions> = {},
71
- ): void {
72
- type RegistrationRecord = {
73
- handle: SequenceRegistrationHandle
74
- target: Document | HTMLElement | Window
75
- }
76
-
77
- const defaultOptions = useDefaultHotkeysOptions()
78
- const manager = getSequenceManager()
79
-
80
- const registrations = new Map<string, RegistrationRecord>()
81
-
82
- const stopWatcher = watch(
83
- () => {
84
- const resolvedDefinitions = resolveMaybeRefOrGetter(definitions)
85
- const resolvedCommonOptions = resolveMaybeRefOrGetter(commonOptions)
86
-
87
- return resolvedDefinitions.map((def, i) => {
88
- const resolvedSequence = resolveMaybeRefOrGetter(def.sequence)
89
- const resolvedDefOptions = def.options
90
- ? resolveMaybeRefOrGetter(def.options)
91
- : {}
92
-
93
- const mergedOptions = {
94
- ...defaultOptions.hotkeySequence,
95
- ...resolvedCommonOptions,
96
- ...resolvedDefOptions,
97
- } as UseHotkeySequenceOptions
98
-
99
- const sequenceString = formatHotkeySequence(resolvedSequence)
100
-
101
- const resolvedEnabled =
102
- mergedOptions.enabled === undefined
103
- ? undefined
104
- : resolveMaybeRefOrGetter(mergedOptions.enabled)
105
- const resolvedTarget =
106
- mergedOptions.target === undefined
107
- ? undefined
108
- : resolveMaybeRefOrGetter(mergedOptions.target as any)
109
-
110
- return {
111
- index: i,
112
- resolvedSequence,
113
- sequenceString,
114
- callback: def.callback,
115
- mergedOptions,
116
- resolvedEnabled,
117
- resolvedTarget,
118
- }
119
- })
120
- },
121
- (resolved) => {
122
- const nextKeys = new Set<string>()
123
- const prepared: Array<{
124
- registrationKey: string
125
- entry: (typeof resolved)[number]
126
- finalTarget: Document | HTMLElement | Window
127
- }> = []
128
-
129
- for (const entry of resolved) {
130
- if (entry.resolvedSequence.length === 0) {
131
- continue
132
- }
133
-
134
- const finalTarget =
135
- entry.resolvedTarget ??
136
- (typeof document !== 'undefined' ? document : null)
137
-
138
- if (!finalTarget) {
139
- continue
140
- }
141
-
142
- const registrationKey = `${entry.index}:${entry.sequenceString}`
143
- nextKeys.add(registrationKey)
144
- prepared.push({ registrationKey, entry, finalTarget })
145
- }
146
-
147
- for (const [key, record] of [...registrations.entries()]) {
148
- if (!nextKeys.has(key)) {
149
- if (record.handle.isActive) {
150
- record.handle.unregister()
151
- }
152
- registrations.delete(key)
153
- }
154
- }
155
-
156
- for (const { registrationKey, entry, finalTarget } of prepared) {
157
- const existing = registrations.get(registrationKey)
158
- if (existing?.handle.isActive && existing.target === finalTarget) {
159
- existing.handle.callback = entry.callback
160
- const {
161
- target: _target,
162
- enabled: _enabled,
163
- ...restOptions
164
- } = entry.mergedOptions
165
- const optionsWithoutTarget = {
166
- ...restOptions,
167
- ...(entry.resolvedEnabled === undefined
168
- ? {}
169
- : { enabled: entry.resolvedEnabled }),
170
- }
171
- existing.handle.setOptions(optionsWithoutTarget)
172
- continue
173
- }
174
-
175
- if (existing) {
176
- if (existing.handle.isActive) {
177
- existing.handle.unregister()
178
- }
179
- registrations.delete(registrationKey)
180
- }
181
-
182
- const {
183
- target: _target,
184
- enabled: _enabled,
185
- ...restOptions
186
- } = entry.mergedOptions
187
- const optionsWithoutTarget = {
188
- ...restOptions,
189
- ...(entry.resolvedEnabled === undefined
190
- ? {}
191
- : { enabled: entry.resolvedEnabled }),
192
- }
193
-
194
- const handle = manager.register(
195
- entry.resolvedSequence,
196
- entry.callback,
197
- {
198
- ...optionsWithoutTarget,
199
- target: finalTarget,
200
- },
201
- )
202
- registrations.set(registrationKey, { handle, target: finalTarget })
203
- }
204
- },
205
- { immediate: true },
206
- )
207
-
208
- onUnmounted(() => {
209
- stopWatcher()
210
- for (const { handle } of registrations.values()) {
211
- if (handle.isActive) {
212
- handle.unregister()
213
- }
214
- }
215
- registrations.clear()
216
- })
217
- }
218
-
219
- function resolveMaybeRefOrGetter<T>(value: MaybeRefOrGetter<T>): T {
220
- return typeof value === 'function' ? (value as () => T)() : unref(value)
221
- }
package/src/useHotkeys.ts DELETED
@@ -1,221 +0,0 @@
1
- import { onUnmounted, unref, watch } from 'vue'
2
- import {
3
- detectPlatform,
4
- getHotkeyManager,
5
- normalizeRegisterableHotkey,
6
- } from '@tanstack/hotkeys'
7
- import { useDefaultHotkeysOptions } from './HotkeysProviderContext'
8
- import type { UseHotkeyOptions } from './useHotkey'
9
- import type {
10
- HotkeyCallback,
11
- HotkeyRegistrationHandle,
12
- RegisterableHotkey,
13
- } from '@tanstack/hotkeys'
14
- import type { MaybeRefOrGetter } from 'vue'
15
-
16
- /**
17
- * A single hotkey definition for use with `useHotkeys`.
18
- */
19
- export interface UseHotkeyDefinition {
20
- /** The hotkey string (e.g., 'Mod+S', 'Escape') or RawHotkey object */
21
- hotkey: MaybeRefOrGetter<RegisterableHotkey>
22
- /** The function to call when the hotkey is pressed */
23
- callback: HotkeyCallback
24
- /** Per-hotkey options (merged on top of commonOptions) */
25
- options?: MaybeRefOrGetter<UseHotkeyOptions>
26
- }
27
-
28
- /**
29
- * Vue composable for registering multiple keyboard hotkeys at once.
30
- *
31
- * Uses the singleton HotkeyManager for efficient event handling.
32
- * Accepts a dynamic array of hotkey definitions, making it safe to use
33
- * with variable-length lists.
34
- *
35
- * Options are merged in this order:
36
- * HotkeysProvider defaults < commonOptions < per-definition options
37
- *
38
- * @param hotkeys - Array of hotkey definitions to register, or a getter/ref
39
- * @param commonOptions - Shared options applied to all hotkeys (overridden by per-definition options)
40
- *
41
- * @example
42
- * ```vue
43
- * <script setup>
44
- * import { useHotkeys } from '@tanstack/vue-hotkeys'
45
- *
46
- * useHotkeys([
47
- * { hotkey: 'Mod+S', callback: () => save() },
48
- * { hotkey: 'Mod+Z', callback: () => undo() },
49
- * { hotkey: 'Escape', callback: () => close() },
50
- * ])
51
- * </script>
52
- * ```
53
- *
54
- * @example
55
- * ```vue
56
- * <script setup>
57
- * import { computed } from 'vue'
58
- * import { useHotkeys } from '@tanstack/vue-hotkeys'
59
- *
60
- * const items = computed(() => [...])
61
- * // Dynamic hotkeys from reactive data
62
- * useHotkeys(
63
- * () => items.value.map((item) => ({
64
- * hotkey: item.shortcut,
65
- * callback: item.action,
66
- * options: { enabled: item.enabled },
67
- * })),
68
- * { preventDefault: true },
69
- * )
70
- * </script>
71
- * ```
72
- */
73
- export function useHotkeys(
74
- hotkeys: MaybeRefOrGetter<Array<UseHotkeyDefinition>>,
75
- commonOptions: MaybeRefOrGetter<UseHotkeyOptions> = {},
76
- ): void {
77
- type RegistrationRecord = {
78
- handle: HotkeyRegistrationHandle
79
- target: Document | HTMLElement | Window
80
- }
81
-
82
- const defaultOptions = useDefaultHotkeysOptions()
83
- const manager = getHotkeyManager()
84
-
85
- const registrations = new Map<string, RegistrationRecord>()
86
-
87
- const stopWatcher = watch(
88
- () => {
89
- const resolvedHotkeys = resolveMaybeRefOrGetter(hotkeys)
90
- const resolvedCommonOptions = resolveMaybeRefOrGetter(commonOptions)
91
-
92
- return resolvedHotkeys.map((def, i) => {
93
- const resolvedHotkey = resolveMaybeRefOrGetter(def.hotkey)
94
- const resolvedDefOptions = def.options
95
- ? resolveMaybeRefOrGetter(def.options)
96
- : {}
97
-
98
- const mergedOptions = {
99
- ...defaultOptions.hotkey,
100
- ...resolvedCommonOptions,
101
- ...resolvedDefOptions,
102
- } as UseHotkeyOptions
103
-
104
- const platform = mergedOptions.platform ?? detectPlatform()
105
- const hotkeyString = normalizeRegisterableHotkey(
106
- resolvedHotkey,
107
- platform,
108
- )
109
-
110
- const resolvedEnabled =
111
- mergedOptions.enabled === undefined
112
- ? undefined
113
- : resolveMaybeRefOrGetter(mergedOptions.enabled)
114
- const resolvedTarget =
115
- mergedOptions.target === undefined
116
- ? undefined
117
- : resolveMaybeRefOrGetter(mergedOptions.target as any)
118
-
119
- return {
120
- index: i,
121
- hotkeyString,
122
- callback: def.callback,
123
- mergedOptions,
124
- resolvedEnabled,
125
- resolvedTarget,
126
- }
127
- })
128
- },
129
- (resolved) => {
130
- const nextKeys = new Set<string>()
131
- const prepared: Array<{
132
- registrationKey: string
133
- entry: (typeof resolved)[number]
134
- finalTarget: Document | HTMLElement | Window
135
- }> = []
136
-
137
- for (const entry of resolved) {
138
- const finalTarget =
139
- entry.resolvedTarget ??
140
- (typeof document !== 'undefined' ? document : null)
141
-
142
- if (!finalTarget) {
143
- continue
144
- }
145
-
146
- const registrationKey = `${entry.index}:${entry.hotkeyString}`
147
- nextKeys.add(registrationKey)
148
- prepared.push({ registrationKey, entry, finalTarget })
149
- }
150
-
151
- for (const [key, record] of [...registrations.entries()]) {
152
- if (!nextKeys.has(key)) {
153
- if (record.handle.isActive) {
154
- record.handle.unregister()
155
- }
156
- registrations.delete(key)
157
- }
158
- }
159
-
160
- for (const { registrationKey, entry, finalTarget } of prepared) {
161
- const existing = registrations.get(registrationKey)
162
- if (existing?.handle.isActive && existing.target === finalTarget) {
163
- existing.handle.callback = entry.callback
164
- const {
165
- target: _target,
166
- enabled: _enabled,
167
- ...restOptions
168
- } = entry.mergedOptions
169
- const optionsWithoutTarget = {
170
- ...restOptions,
171
- ...(entry.resolvedEnabled === undefined
172
- ? {}
173
- : { enabled: entry.resolvedEnabled }),
174
- }
175
- existing.handle.setOptions(optionsWithoutTarget)
176
- continue
177
- }
178
-
179
- if (existing) {
180
- if (existing.handle.isActive) {
181
- existing.handle.unregister()
182
- }
183
- registrations.delete(registrationKey)
184
- }
185
-
186
- const {
187
- target: _target,
188
- enabled: _enabled,
189
- ...restOptions
190
- } = entry.mergedOptions
191
- const optionsWithoutTarget = {
192
- ...restOptions,
193
- ...(entry.resolvedEnabled === undefined
194
- ? {}
195
- : { enabled: entry.resolvedEnabled }),
196
- }
197
-
198
- const handle = manager.register(entry.hotkeyString, entry.callback, {
199
- ...optionsWithoutTarget,
200
- target: finalTarget,
201
- })
202
- registrations.set(registrationKey, { handle, target: finalTarget })
203
- }
204
- },
205
- { immediate: true },
206
- )
207
-
208
- onUnmounted(() => {
209
- stopWatcher()
210
- for (const { handle } of registrations.values()) {
211
- if (handle.isActive) {
212
- handle.unregister()
213
- }
214
- }
215
- registrations.clear()
216
- })
217
- }
218
-
219
- function resolveMaybeRefOrGetter<T>(value: MaybeRefOrGetter<T>): T {
220
- return typeof value === 'function' ? (value as () => T)() : unref(value)
221
- }
package/src/useKeyHold.ts DELETED
@@ -1,65 +0,0 @@
1
- import { useSelector } from '@tanstack/vue-store'
2
- import { getKeyStateTracker } from '@tanstack/hotkeys'
3
- import { unref } from 'vue'
4
- import type { MaybeRefOrGetter, Ref } from 'vue'
5
- import type { IndividualKey } from '@tanstack/hotkeys'
6
-
7
- /**
8
- * Vue composable that returns a reactive ref indicating whether a specific key is currently being held.
9
- *
10
- * This composable uses `useSelector` from `@tanstack/vue-store` to subscribe
11
- * to the global KeyStateTracker and uses a selector to determine if
12
- * the specified key is held.
13
- *
14
- * @param key - The key to check (e.g., 'Shift', 'Control', 'A')
15
- * @returns Reactive ref that is true if the key is currently held down
16
- *
17
- * @example
18
- * ```vue
19
- * <script setup>
20
- * import { useKeyHold } from '@tanstack/vue-hotkeys'
21
- *
22
- * const isShiftHeld = useKeyHold('Shift')
23
- * </script>
24
- *
25
- * <template>
26
- * <div :style="{ opacity: isShiftHeld ? 1 : 0.5 }">
27
- * {{ isShiftHeld ? 'Shift is pressed!' : 'Press Shift' }}
28
- * </div>
29
- * </template>
30
- * ```
31
- *
32
- * @example
33
- * ```vue
34
- * <script setup>
35
- * import { useKeyHold } from '@tanstack/vue-hotkeys'
36
- *
37
- * const ctrl = useKeyHold('Control')
38
- * const shift = useKeyHold('Shift')
39
- * const alt = useKeyHold('Alt')
40
- * </script>
41
- *
42
- * <template>
43
- * <div>
44
- * <span :style="{ opacity: ctrl ? 1 : 0.3 }">Ctrl</span>
45
- * <span :style="{ opacity: shift ? 1 : 0.3 }">Shift</span>
46
- * <span :style="{ opacity: alt ? 1 : 0.3 }">Alt</span>
47
- * </div>
48
- * </template>
49
- * ```
50
- */
51
- export function useKeyHold(key: MaybeRefOrGetter<IndividualKey>): Ref<boolean> {
52
- const tracker = getKeyStateTracker()
53
-
54
- const isHeld = useSelector(tracker.store, (state) => {
55
- const keyValue = unref(key)
56
- const normalizedKey = (
57
- typeof keyValue === 'string' ? keyValue : String(keyValue)
58
- ).toLowerCase()
59
- return state.heldKeys.some(
60
- (heldKey) => heldKey.toLowerCase() === normalizedKey,
61
- )
62
- })
63
-
64
- return isHeld as Ref<boolean>
65
- }
package/src/vue.d.ts DELETED
@@ -1,6 +0,0 @@
1
- declare module '*.vue' {
2
- import type { DefineComponent } from 'vue'
3
-
4
- const component: DefineComponent<{}, {}, any>
5
- export default component
6
- }