@tanstack/svelte-hotkeys 0.11.0 → 0.12.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.
- package/dist/createHotkeyRecorder.svelte.js +22 -35
- package/dist/createHotkeySequenceRecorder.svelte.js +28 -41
- package/dist/getHeldKeyCodesMap.svelte.js +4 -13
- package/dist/getHeldKeys.svelte.js +4 -13
- package/dist/getHotkeyRegistrations.svelte.js +8 -17
- package/dist/getIsKeyHeld.svelte.js +6 -19
- package/package.json +12 -10
- package/src/HotkeysCtx.ts +0 -61
- package/src/HotkeysProvider.svelte +0 -12
- package/src/createHotkey.svelte.ts +0 -179
- package/src/createHotkeyRecorder.svelte.ts +0 -121
- package/src/createHotkeySequence.svelte.ts +0 -207
- package/src/createHotkeySequenceRecorder.svelte.ts +0 -97
- package/src/createHotkeySequences.svelte.ts +0 -274
- package/src/createHotkeys.svelte.ts +0 -276
- package/src/getHeldKeyCodesMap.svelte.ts +0 -44
- package/src/getHeldKeys.svelte.ts +0 -40
- package/src/getHotkeyHint.svelte.ts +0 -51
- package/src/getHotkeyRegistrations.svelte.ts +0 -60
- package/src/getIsKeyHeld.svelte.ts +0 -68
- package/src/index.ts +0 -22
- package/src/internal.svelte.ts +0 -26
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
detectPlatform,
|
|
3
|
-
getHotkeyManager,
|
|
4
|
-
normalizeRegisterableHotkey,
|
|
5
|
-
} from '@tanstack/hotkeys'
|
|
6
|
-
import { onDestroy } from 'svelte'
|
|
7
|
-
import { SvelteMap, SvelteSet } from 'svelte/reactivity'
|
|
8
|
-
import { getDefaultHotkeysOptions } from './HotkeysCtx'
|
|
9
|
-
import { resolveMaybeGetter } from './internal.svelte'
|
|
10
|
-
import type {
|
|
11
|
-
Hotkey,
|
|
12
|
-
HotkeyCallback,
|
|
13
|
-
HotkeyRegistrationHandle,
|
|
14
|
-
RegisterableHotkey,
|
|
15
|
-
} from '@tanstack/hotkeys'
|
|
16
|
-
import type { CreateHotkeyOptions } from './createHotkey.svelte'
|
|
17
|
-
import type { MaybeGetter } from './internal.svelte'
|
|
18
|
-
import type { Attachment } from 'svelte/attachments'
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A single hotkey definition for use with `createHotkeys`.
|
|
22
|
-
*/
|
|
23
|
-
export interface CreateHotkeyDefinition {
|
|
24
|
-
/** The hotkey string (e.g., 'Mod+S', 'Escape') or RawHotkey object */
|
|
25
|
-
hotkey: MaybeGetter<RegisterableHotkey>
|
|
26
|
-
/** The function to call when the hotkey is pressed */
|
|
27
|
-
callback: HotkeyCallback
|
|
28
|
-
/** Per-hotkey options (merged on top of commonOptions) */
|
|
29
|
-
options?: MaybeGetter<CreateHotkeyOptions>
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
type RegistrationRecord = {
|
|
33
|
-
handle: HotkeyRegistrationHandle
|
|
34
|
-
target: Document | HTMLElement | Window
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function cleanupRegistrations(
|
|
38
|
-
registrations:
|
|
39
|
-
| Map<string, RegistrationRecord>
|
|
40
|
-
| SvelteMap<string, RegistrationRecord>,
|
|
41
|
-
) {
|
|
42
|
-
for (const { handle } of registrations.values()) {
|
|
43
|
-
if (handle.isActive) {
|
|
44
|
-
handle.unregister()
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
registrations.clear()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Register multiple global hotkeys for the current component.
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* ```svelte
|
|
55
|
-
* <script lang="ts">
|
|
56
|
-
* import { createHotkeys } from '@tanstack/svelte-hotkeys'
|
|
57
|
-
*
|
|
58
|
-
* createHotkeys([
|
|
59
|
-
* { hotkey: 'Mod+S', callback: () => save() },
|
|
60
|
-
* { hotkey: 'Mod+Z', callback: () => undo() },
|
|
61
|
-
* { hotkey: 'Escape', callback: () => close() },
|
|
62
|
-
* ])
|
|
63
|
-
* </script>
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export function createHotkeys(
|
|
67
|
-
hotkeys: MaybeGetter<Array<CreateHotkeyDefinition>>,
|
|
68
|
-
commonOptions: MaybeGetter<CreateHotkeyOptions> = {},
|
|
69
|
-
): void {
|
|
70
|
-
const registrations = new SvelteMap<string, RegistrationRecord>()
|
|
71
|
-
|
|
72
|
-
onDestroy(() => {
|
|
73
|
-
cleanupRegistrations(registrations)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
$effect(() => {
|
|
77
|
-
if (typeof document === 'undefined') {
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const resolvedHotkeys = resolveMaybeGetter(hotkeys)
|
|
82
|
-
const resolvedCommonOptions = resolveMaybeGetter(commonOptions)
|
|
83
|
-
const nextKeys = new SvelteSet<string>()
|
|
84
|
-
const prepared: Array<{
|
|
85
|
-
registrationKey: string
|
|
86
|
-
def: CreateHotkeyDefinition
|
|
87
|
-
mergedOptions: CreateHotkeyOptions
|
|
88
|
-
hotkeyString: Hotkey
|
|
89
|
-
resolvedTarget: Document | HTMLElement | Window
|
|
90
|
-
}> = []
|
|
91
|
-
|
|
92
|
-
for (let i = 0; i < resolvedHotkeys.length; i++) {
|
|
93
|
-
const def = resolvedHotkeys[i]!
|
|
94
|
-
const resolvedHotkey = resolveMaybeGetter(def.hotkey)
|
|
95
|
-
const resolvedDefOptions = def.options
|
|
96
|
-
? resolveMaybeGetter(def.options)
|
|
97
|
-
: {}
|
|
98
|
-
|
|
99
|
-
const mergedOptions = {
|
|
100
|
-
...getDefaultHotkeysOptions().hotkey,
|
|
101
|
-
...resolvedCommonOptions,
|
|
102
|
-
...resolvedDefOptions,
|
|
103
|
-
} as CreateHotkeyOptions
|
|
104
|
-
|
|
105
|
-
const resolvedTarget =
|
|
106
|
-
mergedOptions.target ??
|
|
107
|
-
(typeof document !== 'undefined' ? document : null)
|
|
108
|
-
|
|
109
|
-
if (!resolvedTarget) {
|
|
110
|
-
continue
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const hotkeyString = normalizeRegisterableHotkey(
|
|
114
|
-
resolvedHotkey,
|
|
115
|
-
mergedOptions.platform ?? detectPlatform(),
|
|
116
|
-
)
|
|
117
|
-
const registrationKey = `${i}:${hotkeyString}`
|
|
118
|
-
nextKeys.add(registrationKey)
|
|
119
|
-
prepared.push({
|
|
120
|
-
registrationKey,
|
|
121
|
-
def,
|
|
122
|
-
mergedOptions,
|
|
123
|
-
hotkeyString,
|
|
124
|
-
resolvedTarget,
|
|
125
|
-
})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
for (const [key, record] of [...registrations.entries()]) {
|
|
129
|
-
if (!nextKeys.has(key)) {
|
|
130
|
-
if (record.handle.isActive) {
|
|
131
|
-
record.handle.unregister()
|
|
132
|
-
}
|
|
133
|
-
registrations.delete(key)
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
for (const p of prepared) {
|
|
138
|
-
const existing = registrations.get(p.registrationKey)
|
|
139
|
-
const { target: _target, ...optionsWithoutTarget } = p.mergedOptions
|
|
140
|
-
|
|
141
|
-
if (existing?.handle.isActive && existing.target === p.resolvedTarget) {
|
|
142
|
-
existing.handle.callback = p.def.callback
|
|
143
|
-
existing.handle.setOptions(optionsWithoutTarget)
|
|
144
|
-
continue
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (existing?.handle.isActive) {
|
|
148
|
-
existing.handle.unregister()
|
|
149
|
-
}
|
|
150
|
-
if (existing) {
|
|
151
|
-
registrations.delete(p.registrationKey)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const handle = getHotkeyManager().register(
|
|
155
|
-
p.hotkeyString,
|
|
156
|
-
p.def.callback,
|
|
157
|
-
{
|
|
158
|
-
...optionsWithoutTarget,
|
|
159
|
-
target: p.resolvedTarget,
|
|
160
|
-
},
|
|
161
|
-
)
|
|
162
|
-
registrations.set(p.registrationKey, {
|
|
163
|
-
handle,
|
|
164
|
-
target: p.resolvedTarget,
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Create an attachment for element-scoped multi-hotkey registration.
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* ```svelte
|
|
175
|
-
* <script lang="ts">
|
|
176
|
-
* import { createHotkeysAttachment } from '@tanstack/svelte-hotkeys'
|
|
177
|
-
*
|
|
178
|
-
* const editorKeys = createHotkeysAttachment([
|
|
179
|
-
* { hotkey: 'Mod+S', callback: () => save() },
|
|
180
|
-
* { hotkey: 'Mod+Z', callback: () => undo() },
|
|
181
|
-
* ])
|
|
182
|
-
* </script>
|
|
183
|
-
*
|
|
184
|
-
* <div tabindex="0" {@attach editorKeys}>
|
|
185
|
-
* Editor content
|
|
186
|
-
* </div>
|
|
187
|
-
* ```
|
|
188
|
-
*/
|
|
189
|
-
export function createHotkeysAttachment(
|
|
190
|
-
hotkeys: MaybeGetter<Array<CreateHotkeyDefinition>>,
|
|
191
|
-
commonOptions: MaybeGetter<CreateHotkeyOptions> = {},
|
|
192
|
-
): Attachment<HTMLElement> {
|
|
193
|
-
return (element) => {
|
|
194
|
-
const registrations = new SvelteMap<string, RegistrationRecord>()
|
|
195
|
-
|
|
196
|
-
$effect(() => {
|
|
197
|
-
const resolvedHotkeys = resolveMaybeGetter(hotkeys)
|
|
198
|
-
const resolvedCommonOptions = resolveMaybeGetter(commonOptions)
|
|
199
|
-
const nextKeys = new SvelteSet<string>()
|
|
200
|
-
const prepared: Array<{
|
|
201
|
-
registrationKey: string
|
|
202
|
-
def: CreateHotkeyDefinition
|
|
203
|
-
mergedOptions: CreateHotkeyOptions
|
|
204
|
-
hotkeyString: Hotkey
|
|
205
|
-
}> = []
|
|
206
|
-
|
|
207
|
-
for (let i = 0; i < resolvedHotkeys.length; i++) {
|
|
208
|
-
const def = resolvedHotkeys[i]!
|
|
209
|
-
const resolvedHotkey = resolveMaybeGetter(def.hotkey)
|
|
210
|
-
const resolvedDefOptions = def.options
|
|
211
|
-
? resolveMaybeGetter(def.options)
|
|
212
|
-
: {}
|
|
213
|
-
|
|
214
|
-
const mergedOptions = {
|
|
215
|
-
...getDefaultHotkeysOptions().hotkey,
|
|
216
|
-
...resolvedCommonOptions,
|
|
217
|
-
...resolvedDefOptions,
|
|
218
|
-
} as CreateHotkeyOptions
|
|
219
|
-
|
|
220
|
-
const hotkeyString = normalizeRegisterableHotkey(
|
|
221
|
-
resolvedHotkey,
|
|
222
|
-
mergedOptions.platform ?? detectPlatform(),
|
|
223
|
-
)
|
|
224
|
-
const registrationKey = `${i}:${hotkeyString}`
|
|
225
|
-
nextKeys.add(registrationKey)
|
|
226
|
-
prepared.push({
|
|
227
|
-
registrationKey,
|
|
228
|
-
def,
|
|
229
|
-
mergedOptions,
|
|
230
|
-
hotkeyString,
|
|
231
|
-
})
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
for (const [key, record] of [...registrations.entries()]) {
|
|
235
|
-
if (!nextKeys.has(key)) {
|
|
236
|
-
if (record.handle.isActive) {
|
|
237
|
-
record.handle.unregister()
|
|
238
|
-
}
|
|
239
|
-
registrations.delete(key)
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
for (const p of prepared) {
|
|
244
|
-
const existing = registrations.get(p.registrationKey)
|
|
245
|
-
const { target: _target, ...optionsWithoutTarget } = p.mergedOptions
|
|
246
|
-
|
|
247
|
-
if (existing?.handle.isActive) {
|
|
248
|
-
existing.handle.callback = p.def.callback
|
|
249
|
-
existing.handle.setOptions(optionsWithoutTarget)
|
|
250
|
-
continue
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (existing?.handle.isActive) {
|
|
254
|
-
existing.handle.unregister()
|
|
255
|
-
}
|
|
256
|
-
if (existing) {
|
|
257
|
-
registrations.delete(p.registrationKey)
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const handle = getHotkeyManager().register(
|
|
261
|
-
p.hotkeyString,
|
|
262
|
-
p.def.callback,
|
|
263
|
-
{
|
|
264
|
-
...optionsWithoutTarget,
|
|
265
|
-
target: element,
|
|
266
|
-
},
|
|
267
|
-
)
|
|
268
|
-
registrations.set(p.registrationKey, { handle, target: element })
|
|
269
|
-
}
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
return () => {
|
|
273
|
-
cleanupRegistrations(registrations)
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { getKeyStateTracker } from '@tanstack/hotkeys'
|
|
2
|
-
import { createStoreSubscriber } from './internal.svelte'
|
|
3
|
-
|
|
4
|
-
export interface SvelteHeldKeyCodesMap {
|
|
5
|
-
readonly codes: Record<string, string>
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
class HeldKeyCodesMapState implements SvelteHeldKeyCodesMap {
|
|
9
|
-
#tracker = getKeyStateTracker()
|
|
10
|
-
#subscribe = createStoreSubscriber(this.#tracker.store)
|
|
11
|
-
|
|
12
|
-
get codes(): Record<string, string> {
|
|
13
|
-
this.#subscribe()
|
|
14
|
-
return this.#tracker.store.state.heldCodes
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Svelte function that returns reactive access to the map of currently held key names
|
|
20
|
-
* to their physical `event.code` values.
|
|
21
|
-
*
|
|
22
|
-
* This is useful for debugging which physical key was pressed (e.g. distinguishing
|
|
23
|
-
* left vs right Shift via "ShiftLeft" / "ShiftRight").
|
|
24
|
-
*
|
|
25
|
-
* @returns Object with a reactive `codes` property
|
|
26
|
-
*
|
|
27
|
-
* ```svelte
|
|
28
|
-
* <script>
|
|
29
|
-
* import { getHeldKeyCodesMap } from '@tanstack/svelte-hotkeys'
|
|
30
|
-
* const heldKeyCodesMap = getHeldKeyCodesMap()
|
|
31
|
-
* </script>
|
|
32
|
-
*
|
|
33
|
-
* <div>
|
|
34
|
-
* {#each Object.entries(heldKeyCodesMap.codes) as [key, code]}
|
|
35
|
-
* <kbd>
|
|
36
|
-
* {key} <small>{code}</small>
|
|
37
|
-
* </kbd>
|
|
38
|
-
* {/each}
|
|
39
|
-
* </div>
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export function getHeldKeyCodesMap(): SvelteHeldKeyCodesMap {
|
|
43
|
-
return new HeldKeyCodesMapState()
|
|
44
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { getKeyStateTracker } from '@tanstack/hotkeys'
|
|
2
|
-
import { createStoreSubscriber } from './internal.svelte'
|
|
3
|
-
|
|
4
|
-
export interface SvelteHeldKeys {
|
|
5
|
-
readonly keys: Array<string>
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
class HeldKeysState implements SvelteHeldKeys {
|
|
9
|
-
#tracker = getKeyStateTracker()
|
|
10
|
-
#subscribe = createStoreSubscriber(this.#tracker.store)
|
|
11
|
-
|
|
12
|
-
get keys(): Array<string> {
|
|
13
|
-
this.#subscribe()
|
|
14
|
-
return this.#tracker.store.state.heldKeys
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Svelte function that returns reactive access to currently held keyboard keys.
|
|
20
|
-
*
|
|
21
|
-
* This function uses the global KeyStateTracker and updates whenever keys are pressed
|
|
22
|
-
* or released.
|
|
23
|
-
*
|
|
24
|
-
* @returns Object with a reactive `keys` property
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```svelte
|
|
28
|
-
* <script>
|
|
29
|
-
* import { getHeldKeys } from '@tanstack/svelte-hotkeys'
|
|
30
|
-
*
|
|
31
|
-
* const heldKeys = getHeldKeys()
|
|
32
|
-
* </script>
|
|
33
|
-
* <div>
|
|
34
|
-
* Currently pressed: {heldKeys.keys.join(' + ') || 'None'}
|
|
35
|
-
* </div>
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export function getHeldKeys(): SvelteHeldKeys {
|
|
39
|
-
return new HeldKeysState()
|
|
40
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { createSubscriber } from 'svelte/reactivity'
|
|
2
|
-
import { getKeyStateTracker, matchesHeldModifiers } from '@tanstack/hotkeys'
|
|
3
|
-
import { resolveMaybeGetter } from './internal.svelte'
|
|
4
|
-
import type { HeldModifierOptions, RegisterableHotkey } from '@tanstack/hotkeys'
|
|
5
|
-
import type { MaybeGetter } from './internal.svelte'
|
|
6
|
-
|
|
7
|
-
export interface SvelteHotkeyHint {
|
|
8
|
-
readonly visible: boolean
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Returns an object with a reactive `visible` getter indicating whether held modifiers reveal this shortcut.
|
|
13
|
-
* Pass getters to track changing bindings and options.
|
|
14
|
-
* Uses the nonempty-subset/AltGr rules of `matchesHeldModifiers`; `exact` requires
|
|
15
|
-
* every modifier. Combine with the action's enabled state before showing a badge.
|
|
16
|
-
* This helper does not register a shortcut or check whether its target is focused.
|
|
17
|
-
*/
|
|
18
|
-
export function getHotkeyHint(
|
|
19
|
-
hotkey: MaybeGetter<RegisterableHotkey>,
|
|
20
|
-
options: MaybeGetter<HeldModifierOptions> = {},
|
|
21
|
-
): SvelteHotkeyHint {
|
|
22
|
-
const tracker = getKeyStateTracker()
|
|
23
|
-
// Resolve current reactive arguments without caching a stale binding.
|
|
24
|
-
const read = () =>
|
|
25
|
-
matchesHeldModifiers(
|
|
26
|
-
resolveMaybeGetter(hotkey),
|
|
27
|
-
tracker.store.state.heldKeys,
|
|
28
|
-
resolveMaybeGetter(options),
|
|
29
|
-
)
|
|
30
|
-
let previous = false
|
|
31
|
-
// Notify Svelte only when visibility changes, not for every unrelated held key.
|
|
32
|
-
const subscribe = createSubscriber((update) => {
|
|
33
|
-
previous = read()
|
|
34
|
-
const subscription = tracker.store.subscribe(() => {
|
|
35
|
-
const next = read()
|
|
36
|
-
if (next !== previous) {
|
|
37
|
-
previous = next
|
|
38
|
-
update()
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
return () => subscription.unsubscribe()
|
|
42
|
-
})
|
|
43
|
-
return {
|
|
44
|
-
/** Reads visibility and subscribes the current reactive consumer when needed. */
|
|
45
|
-
get visible() {
|
|
46
|
-
subscribe()
|
|
47
|
-
previous = read()
|
|
48
|
-
return previous
|
|
49
|
-
},
|
|
50
|
-
}
|
|
51
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getHotkeyManager,
|
|
3
|
-
getSequenceManager,
|
|
4
|
-
toHotkeyRegistrationView,
|
|
5
|
-
} from '@tanstack/hotkeys'
|
|
6
|
-
import { createStoreSubscriber } from './internal.svelte'
|
|
7
|
-
import type {
|
|
8
|
-
HotkeyRegistrationView,
|
|
9
|
-
SequenceRegistrationView,
|
|
10
|
-
} from '@tanstack/hotkeys'
|
|
11
|
-
|
|
12
|
-
export interface SvelteHotkeyRegistrations {
|
|
13
|
-
readonly hotkeys: Array<HotkeyRegistrationView>
|
|
14
|
-
readonly sequences: Array<SequenceRegistrationView>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
class HotkeyRegistrationsState implements SvelteHotkeyRegistrations {
|
|
18
|
-
#hotkeyManager = getHotkeyManager()
|
|
19
|
-
#sequenceManager = getSequenceManager()
|
|
20
|
-
#subscribeHotkeys = createStoreSubscriber(this.#hotkeyManager.registrations)
|
|
21
|
-
#subscribeSequences = createStoreSubscriber(
|
|
22
|
-
this.#sequenceManager.registrations,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
get hotkeys(): Array<HotkeyRegistrationView> {
|
|
26
|
-
this.#subscribeHotkeys()
|
|
27
|
-
return Array.from(this.#hotkeyManager.registrations.state.values()).map(
|
|
28
|
-
toHotkeyRegistrationView,
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get sequences(): Array<SequenceRegistrationView> {
|
|
33
|
-
this.#subscribeSequences()
|
|
34
|
-
return Array.from(this.#sequenceManager.registrations.state.values())
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Svelte function that returns reactive access to all hotkey and sequence
|
|
40
|
-
* registrations from the singleton managers.
|
|
41
|
-
*
|
|
42
|
-
* This is a standalone function that does NOT require the HotkeysProvider.
|
|
43
|
-
*
|
|
44
|
-
* @returns Object with reactive `hotkeys` and `sequences` properties
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```svelte
|
|
48
|
-
* <script>
|
|
49
|
-
* import { getHotkeyRegistrations } from '@tanstack/svelte-hotkeys'
|
|
50
|
-
*
|
|
51
|
-
* const registrations = getHotkeyRegistrations()
|
|
52
|
-
* </script>
|
|
53
|
-
* {#each registrations.hotkeys as reg}
|
|
54
|
-
* <div>{reg.options.meta?.name} — {reg.triggerCount} triggers</div>
|
|
55
|
-
* {/each}
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
export function getHotkeyRegistrations(): SvelteHotkeyRegistrations {
|
|
59
|
-
return new HotkeyRegistrationsState()
|
|
60
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { getKeyStateTracker } from '@tanstack/hotkeys'
|
|
2
|
-
import { createStoreSubscriber } from './internal.svelte'
|
|
3
|
-
import type { IndividualKey } from '@tanstack/hotkeys'
|
|
4
|
-
|
|
5
|
-
export interface SvelteHeldKeyState {
|
|
6
|
-
readonly held: boolean
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
class HeldKeyState implements SvelteHeldKeyState {
|
|
10
|
-
#tracker = getKeyStateTracker()
|
|
11
|
-
#normalizedKey: string
|
|
12
|
-
#subscribe = createStoreSubscriber(this.#tracker.store)
|
|
13
|
-
|
|
14
|
-
constructor(key: IndividualKey) {
|
|
15
|
-
this.#normalizedKey = key.toLowerCase()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
get held(): boolean {
|
|
19
|
-
this.#subscribe()
|
|
20
|
-
return this.#tracker.store.state.heldKeys.some(
|
|
21
|
-
(heldKey) => heldKey.toLowerCase() === this.#normalizedKey,
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Svelte function that returns reactive access to whether a specific key is currently being held.
|
|
28
|
-
*
|
|
29
|
-
* This function uses the global KeyStateTracker and updates whenever keys are pressed
|
|
30
|
-
* or released.
|
|
31
|
-
*
|
|
32
|
-
* @param key - The key to check (e.g., 'Shift', 'Control', 'A')
|
|
33
|
-
* @returns Object with a reactive `held` property
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```svelte
|
|
37
|
-
* <script>
|
|
38
|
-
* import { getIsKeyHeld } from '@tanstack/svelte-hotkeys'
|
|
39
|
-
*
|
|
40
|
-
* const isShiftHeld = getIsKeyHeld('Shift')
|
|
41
|
-
* </script>
|
|
42
|
-
*
|
|
43
|
-
* <div>
|
|
44
|
-
* {isShiftHeld.held ? 'Shift is pressed!' : 'Press Shift'}
|
|
45
|
-
* </div>
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```svelte
|
|
50
|
-
* <script>
|
|
51
|
-
* import { getIsKeyHeld } from '@tanstack/svelte-hotkeys'
|
|
52
|
-
*
|
|
53
|
-
* const isCtrlHeld = getIsKeyHeld('Control')
|
|
54
|
-
* const isShiftHeld = getIsKeyHeld('Shift')
|
|
55
|
-
* const isAltHeld = getIsKeyHeld('Alt')
|
|
56
|
-
* </script>
|
|
57
|
-
*
|
|
58
|
-
* <div>
|
|
59
|
-
* <span style:opacity={isCtrlHeld.held ? 1 : 0.3}>Ctrl</span>
|
|
60
|
-
* <span style:opacity={isShiftHeld.held ? 1 : 0.3}>Shift</span>
|
|
61
|
-
* <span style:opacity={isAltHeld.held ? 1 : 0.3}>Alt</span>
|
|
62
|
-
* </div>
|
|
63
|
-
* ```
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
-
export function getIsKeyHeld(key: IndividualKey): SvelteHeldKeyState {
|
|
67
|
-
return new HeldKeyState(key)
|
|
68
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// Re-export everything from the core package
|
|
2
|
-
export * from '@tanstack/hotkeys'
|
|
3
|
-
|
|
4
|
-
export * from './createHotkey.svelte'
|
|
5
|
-
export * from './createHotkeys.svelte'
|
|
6
|
-
export * from './createHotkeySequence.svelte'
|
|
7
|
-
export * from './createHotkeySequences.svelte'
|
|
8
|
-
export * from './createHotkeyRecorder.svelte'
|
|
9
|
-
export * from './createHotkeySequenceRecorder.svelte'
|
|
10
|
-
export * from './getHeldKeys.svelte'
|
|
11
|
-
export * from './getHotkeyRegistrations.svelte'
|
|
12
|
-
export * from './getHeldKeyCodesMap.svelte'
|
|
13
|
-
export * from './getIsKeyHeld.svelte'
|
|
14
|
-
export { default as HotkeysProvider } from './HotkeysProvider.svelte'
|
|
15
|
-
export {
|
|
16
|
-
DEFAULT_OPTIONS,
|
|
17
|
-
getDefaultHotkeysOptions,
|
|
18
|
-
getHotkeysContext,
|
|
19
|
-
setHotkeysContext,
|
|
20
|
-
} from './HotkeysCtx'
|
|
21
|
-
export type { HotkeysProviderOptions, HotkeysProviderProps } from './HotkeysCtx'
|
|
22
|
-
export * from './getHotkeyHint.svelte'
|
package/src/internal.svelte.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createSubscriber } from 'svelte/reactivity'
|
|
2
|
-
|
|
3
|
-
export type MaybeGetter<T> = T | (() => T)
|
|
4
|
-
|
|
5
|
-
interface SubscribableStore<TState> {
|
|
6
|
-
state: TState
|
|
7
|
-
subscribe: (
|
|
8
|
-
listener: () => void,
|
|
9
|
-
) => (() => void) | { unsubscribe: () => void }
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function resolveMaybeGetter<T>(value: MaybeGetter<T>): T {
|
|
13
|
-
return typeof value === 'function' ? (value as () => T)() : value
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function createStoreSubscriber<TState>(
|
|
17
|
-
store: SubscribableStore<TState>,
|
|
18
|
-
): () => void {
|
|
19
|
-
return createSubscriber((update) => {
|
|
20
|
-
const subscription = store.subscribe(update)
|
|
21
|
-
|
|
22
|
-
return typeof subscription === 'function'
|
|
23
|
-
? subscription
|
|
24
|
-
: () => subscription.unsubscribe()
|
|
25
|
-
})
|
|
26
|
-
}
|