@tanstack/svelte-hotkeys 0.10.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/README.md +15 -1
- package/dist/createHotkeyRecorder.svelte.js +22 -32
- package/dist/createHotkeySequenceRecorder.svelte.js +28 -37
- package/dist/getHeldKeyCodesMap.svelte.js +4 -13
- package/dist/getHeldKeys.svelte.js +4 -13
- package/dist/getHotkeyHint.svelte.d.ts +13 -0
- package/dist/getHotkeyHint.svelte.js +36 -0
- package/dist/getHotkeyRegistrations.svelte.js +8 -17
- package/dist/getIsKeyHeld.svelte.js +6 -19
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- 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 -118
- package/src/createHotkeySequence.svelte.ts +0 -207
- package/src/createHotkeySequenceRecorder.svelte.ts +0 -93
- 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/getHotkeyRegistrations.svelte.ts +0 -60
- package/src/getIsKeyHeld.svelte.ts +0 -68
- package/src/index.ts +0 -21
- package/src/internal.svelte.ts +0 -26
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
detectPlatform,
|
|
3
|
-
getHotkeyManager,
|
|
4
|
-
normalizeRegisterableHotkey,
|
|
5
|
-
} from '@tanstack/hotkeys'
|
|
6
|
-
import { onDestroy } from 'svelte'
|
|
7
|
-
import { getDefaultHotkeysOptions } from './HotkeysCtx'
|
|
8
|
-
import { resolveMaybeGetter } from './internal.svelte'
|
|
9
|
-
import type {
|
|
10
|
-
Hotkey,
|
|
11
|
-
HotkeyCallback,
|
|
12
|
-
HotkeyOptions,
|
|
13
|
-
HotkeyRegistrationHandle,
|
|
14
|
-
RegisterableHotkey,
|
|
15
|
-
} from '@tanstack/hotkeys'
|
|
16
|
-
import type { MaybeGetter } from './internal.svelte'
|
|
17
|
-
import type { Attachment } from 'svelte/attachments'
|
|
18
|
-
|
|
19
|
-
export interface CreateHotkeyOptions extends Omit<HotkeyOptions, 'target'> {
|
|
20
|
-
target?: Document | Window // not html elements, use attachment instead
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function registerHotkey(
|
|
24
|
-
target: HTMLElement | Document | Window,
|
|
25
|
-
hotkey: RegisterableHotkey,
|
|
26
|
-
callback: HotkeyCallback,
|
|
27
|
-
mergedOptions: CreateHotkeyOptions,
|
|
28
|
-
) {
|
|
29
|
-
return getHotkeyManager().register(
|
|
30
|
-
normalizeRegisterableHotkey(
|
|
31
|
-
hotkey,
|
|
32
|
-
mergedOptions.platform ?? detectPlatform(),
|
|
33
|
-
),
|
|
34
|
-
callback,
|
|
35
|
-
{
|
|
36
|
-
...mergedOptions,
|
|
37
|
-
target,
|
|
38
|
-
},
|
|
39
|
-
)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Register a global hotkey for the current component.
|
|
44
|
-
*
|
|
45
|
-
* @example
|
|
46
|
-
* ```svelte
|
|
47
|
-
* <script lang="ts">
|
|
48
|
-
* import { createHotkey } from '@tanstack/svelte-hotkeys'
|
|
49
|
-
*
|
|
50
|
-
* createHotkey('Mod+S', () => {
|
|
51
|
-
* console.log('Mod+S pressed')
|
|
52
|
-
* })
|
|
53
|
-
* </script>
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
export function createHotkey(
|
|
57
|
-
hotkey: MaybeGetter<RegisterableHotkey>,
|
|
58
|
-
callback: HotkeyCallback,
|
|
59
|
-
options: MaybeGetter<CreateHotkeyOptions> = {},
|
|
60
|
-
): void {
|
|
61
|
-
let registration: HotkeyRegistrationHandle | null = null
|
|
62
|
-
let lastHotkeyStr: Hotkey | null = null
|
|
63
|
-
|
|
64
|
-
$effect(() => {
|
|
65
|
-
if (typeof document === 'undefined') {
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const resolvedHotkey = resolveMaybeGetter(hotkey)
|
|
70
|
-
const resolvedOptions = resolveMaybeGetter(options)
|
|
71
|
-
const mergedOptions = {
|
|
72
|
-
...getDefaultHotkeysOptions().hotkey,
|
|
73
|
-
...resolvedOptions,
|
|
74
|
-
} as CreateHotkeyOptions
|
|
75
|
-
|
|
76
|
-
const hotkeyStr = normalizeRegisterableHotkey(
|
|
77
|
-
resolvedHotkey,
|
|
78
|
-
mergedOptions.platform ?? detectPlatform(),
|
|
79
|
-
)
|
|
80
|
-
const { target: _t, ...optionsWithoutTarget } = mergedOptions
|
|
81
|
-
|
|
82
|
-
if (registration?.isActive && lastHotkeyStr === hotkeyStr) {
|
|
83
|
-
registration.callback = callback
|
|
84
|
-
registration.setOptions(optionsWithoutTarget)
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (registration?.isActive) {
|
|
89
|
-
registration.unregister()
|
|
90
|
-
registration = null
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
registration = registerHotkey(
|
|
94
|
-
document,
|
|
95
|
-
resolvedHotkey,
|
|
96
|
-
callback,
|
|
97
|
-
mergedOptions,
|
|
98
|
-
)
|
|
99
|
-
lastHotkeyStr = hotkeyStr
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
onDestroy(() => {
|
|
103
|
-
if (registration?.isActive) {
|
|
104
|
-
registration.unregister()
|
|
105
|
-
registration = null
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Create an attachment for element-scoped hotkeys.
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```svelte
|
|
115
|
-
* <script lang="ts">
|
|
116
|
-
* import { createHotkeyAttachment } from '@tanstack/svelte-hotkeys'
|
|
117
|
-
*
|
|
118
|
-
* let count = $state(0)
|
|
119
|
-
* const saveHotkey = createHotkeyAttachment('Mod+S', () => {
|
|
120
|
-
* count++
|
|
121
|
-
* })
|
|
122
|
-
*
|
|
123
|
-
* </script>
|
|
124
|
-
*
|
|
125
|
-
* <div tabindex="0" {@attach saveHotkey}>
|
|
126
|
-
* Count: {count}
|
|
127
|
-
* </div>
|
|
128
|
-
* ```
|
|
129
|
-
*/
|
|
130
|
-
export function createHotkeyAttachment(
|
|
131
|
-
hotkey: MaybeGetter<RegisterableHotkey>,
|
|
132
|
-
callback: HotkeyCallback,
|
|
133
|
-
options: MaybeGetter<CreateHotkeyOptions> = {},
|
|
134
|
-
): Attachment<HTMLElement> {
|
|
135
|
-
return (element) => {
|
|
136
|
-
let registration: HotkeyRegistrationHandle | null = null
|
|
137
|
-
let lastHotkeyStr: Hotkey | null = null
|
|
138
|
-
|
|
139
|
-
$effect(() => {
|
|
140
|
-
const resolvedHotkey = resolveMaybeGetter(hotkey)
|
|
141
|
-
const resolvedOptions = resolveMaybeGetter(options)
|
|
142
|
-
const mergedOptions = {
|
|
143
|
-
...getDefaultHotkeysOptions().hotkey,
|
|
144
|
-
...resolvedOptions,
|
|
145
|
-
} as CreateHotkeyOptions
|
|
146
|
-
|
|
147
|
-
const hotkeyStr = normalizeRegisterableHotkey(
|
|
148
|
-
resolvedHotkey,
|
|
149
|
-
mergedOptions.platform ?? detectPlatform(),
|
|
150
|
-
)
|
|
151
|
-
const { target: _t, ...optionsWithoutTarget } = mergedOptions
|
|
152
|
-
|
|
153
|
-
if (registration?.isActive && lastHotkeyStr === hotkeyStr) {
|
|
154
|
-
registration.callback = callback
|
|
155
|
-
registration.setOptions(optionsWithoutTarget)
|
|
156
|
-
return
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (registration?.isActive) {
|
|
160
|
-
registration.unregister()
|
|
161
|
-
registration = null
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
registration = registerHotkey(
|
|
165
|
-
element,
|
|
166
|
-
resolvedHotkey,
|
|
167
|
-
callback,
|
|
168
|
-
mergedOptions,
|
|
169
|
-
)
|
|
170
|
-
lastHotkeyStr = hotkeyStr
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
return () => {
|
|
174
|
-
if (registration?.isActive) {
|
|
175
|
-
registration.unregister()
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { HotkeyRecorder } from '@tanstack/hotkeys'
|
|
2
|
-
import { onDestroy } from 'svelte'
|
|
3
|
-
import { getDefaultHotkeysOptions } from './HotkeysCtx'
|
|
4
|
-
import { createStoreSubscriber, resolveMaybeGetter } from './internal.svelte'
|
|
5
|
-
import type { Hotkey, HotkeyRecorderOptions } from '@tanstack/hotkeys'
|
|
6
|
-
import type { MaybeGetter } from './internal.svelte'
|
|
7
|
-
|
|
8
|
-
export interface SvelteHotkeyRecorder {
|
|
9
|
-
/** Whether recording is currently active */
|
|
10
|
-
readonly isRecording: boolean
|
|
11
|
-
/** The currently recorded hotkey (for live preview) */
|
|
12
|
-
readonly recordedHotkey: Hotkey | null
|
|
13
|
-
/** Start recording a new hotkey */
|
|
14
|
-
startRecording: () => void
|
|
15
|
-
/** Stop recording (same as cancel) */
|
|
16
|
-
stopRecording: () => void
|
|
17
|
-
/** Cancel recording without saving */
|
|
18
|
-
cancelRecording: () => void
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Svelte function for recording keyboard shortcuts.
|
|
23
|
-
*
|
|
24
|
-
* This function provides a thin wrapper around the framework-agnostic `HotkeyRecorder`
|
|
25
|
-
* class, managing all the complexity of capturing keyboard events, converting them
|
|
26
|
-
* to hotkey strings, and handling edge cases like Escape to cancel or Backspace/Delete
|
|
27
|
-
* to clear.
|
|
28
|
-
*
|
|
29
|
-
* @param options - Configuration options for the recorder
|
|
30
|
-
* @returns An object with recording state and control functions
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```svelte
|
|
34
|
-
* <script>
|
|
35
|
-
* import { createHotkeyRecorder } from '@tanstack/svelte-hotkeys'
|
|
36
|
-
*
|
|
37
|
-
* const recorder = createHotkeyRecorder({
|
|
38
|
-
* onRecord: (hotkey) => {
|
|
39
|
-
* console.log('Recorded:', hotkey) // e.g., "Mod+Shift S"
|
|
40
|
-
* },
|
|
41
|
-
* onCancel: () => {
|
|
42
|
-
* console.log('Recording cancelled')
|
|
43
|
-
* },
|
|
44
|
-
* })
|
|
45
|
-
* </script>
|
|
46
|
-
*
|
|
47
|
-
* <div>
|
|
48
|
-
* <button onclick={recorder.startRecording}>
|
|
49
|
-
* {recorder.isRecording ? 'Recording...' : 'Edit Shortcut'}
|
|
50
|
-
* </button>
|
|
51
|
-
* {#if recorder.recordedHotkey}
|
|
52
|
-
* <div>Recording: {recorder.recordedHotkey}</div>
|
|
53
|
-
* {/if}
|
|
54
|
-
* </div>
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
class SvelteHotkeyRecorderState implements SvelteHotkeyRecorder {
|
|
59
|
-
#recorder: HotkeyRecorder
|
|
60
|
-
#subscribe: () => void
|
|
61
|
-
|
|
62
|
-
constructor(options: HotkeyRecorderOptions) {
|
|
63
|
-
this.#recorder = new HotkeyRecorder(options)
|
|
64
|
-
this.#subscribe = createStoreSubscriber(this.#recorder.store)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
get isRecording(): boolean {
|
|
68
|
-
this.#subscribe()
|
|
69
|
-
return this.#recorder.store.state.isRecording
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get recordedHotkey(): Hotkey | null {
|
|
73
|
-
this.#subscribe()
|
|
74
|
-
return this.#recorder.store.state.recordedHotkey
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
setOptions(options: HotkeyRecorderOptions): void {
|
|
78
|
-
this.#recorder.setOptions(options)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
startRecording(): void {
|
|
82
|
-
this.#recorder.start()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
stopRecording(): void {
|
|
86
|
-
this.#recorder.stop()
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
cancelRecording(): void {
|
|
90
|
-
this.#recorder.cancel()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
destroy(): void {
|
|
94
|
-
this.#recorder.destroy()
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function createHotkeyRecorder(
|
|
99
|
-
options: MaybeGetter<HotkeyRecorderOptions>,
|
|
100
|
-
): SvelteHotkeyRecorder {
|
|
101
|
-
const recorder = new SvelteHotkeyRecorderState({
|
|
102
|
-
...getDefaultHotkeysOptions().hotkeyRecorder,
|
|
103
|
-
...resolveMaybeGetter(options),
|
|
104
|
-
} as HotkeyRecorderOptions)
|
|
105
|
-
|
|
106
|
-
$effect(() => {
|
|
107
|
-
recorder.setOptions({
|
|
108
|
-
...getDefaultHotkeysOptions().hotkeyRecorder,
|
|
109
|
-
...resolveMaybeGetter(options),
|
|
110
|
-
} as HotkeyRecorderOptions)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
onDestroy(() => {
|
|
114
|
-
recorder.destroy()
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
return recorder
|
|
118
|
-
}
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { formatHotkeySequence, getSequenceManager } from '@tanstack/hotkeys'
|
|
2
|
-
import { onDestroy } from 'svelte'
|
|
3
|
-
import { getDefaultHotkeysOptions } from './HotkeysCtx'
|
|
4
|
-
import { resolveMaybeGetter } from './internal.svelte'
|
|
5
|
-
import type {
|
|
6
|
-
HotkeyCallback,
|
|
7
|
-
HotkeySequence,
|
|
8
|
-
SequenceOptions,
|
|
9
|
-
SequenceRegistrationHandle,
|
|
10
|
-
} from '@tanstack/hotkeys'
|
|
11
|
-
import type { MaybeGetter } from './internal.svelte'
|
|
12
|
-
import type { Attachment } from 'svelte/attachments'
|
|
13
|
-
|
|
14
|
-
export interface CreateHotkeySequenceOptions extends Omit<
|
|
15
|
-
SequenceOptions,
|
|
16
|
-
'target'
|
|
17
|
-
> {
|
|
18
|
-
target?: Document | Window // not html elements, use attachment instead
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function registerHotkeySequence(
|
|
22
|
-
target: HTMLElement | Document | Window,
|
|
23
|
-
sequence: HotkeySequence,
|
|
24
|
-
callback: HotkeyCallback,
|
|
25
|
-
mergedOptions: CreateHotkeySequenceOptions,
|
|
26
|
-
) {
|
|
27
|
-
return getSequenceManager().register(sequence, callback, {
|
|
28
|
-
...mergedOptions,
|
|
29
|
-
target,
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Register a global keyboard shortcut sequence for the current component.
|
|
35
|
-
*
|
|
36
|
-
* Each step may include modifiers. You can chain the same modifier across
|
|
37
|
-
* steps (e.g. `Shift+R` then `Shift+T`). Modifier-only keydown events (Shift,
|
|
38
|
-
* Control, Alt, or Meta pressed alone) are ignored while matching—they do not
|
|
39
|
-
* advance the sequence or reset progress.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* ```svelte
|
|
43
|
-
* <script lang="ts">
|
|
44
|
-
* import { createHotkeySequence } from '@tanstack/svelte-hotkeys'
|
|
45
|
-
*
|
|
46
|
-
* // Scroll to top when 'G G' is pressed
|
|
47
|
-
* createHotkeySequence(['G', 'G'], () => {
|
|
48
|
-
* scrollToTop()
|
|
49
|
-
* })
|
|
50
|
-
*
|
|
51
|
-
* // Delete line when 'D D' is pressed
|
|
52
|
-
* createHotkeySequence(['D', 'D'], () => {
|
|
53
|
-
* deleteLine()
|
|
54
|
-
* })
|
|
55
|
-
*
|
|
56
|
-
* // Delete inner word when 'D I W' is pressed
|
|
57
|
-
* createHotkeySequence(['D', 'I', 'W'], () => {
|
|
58
|
-
* deleteInnerWord()
|
|
59
|
-
* }, { timeout: 500 })
|
|
60
|
-
*
|
|
61
|
-
* // Same modifier on consecutive steps (bare Shift between chords is ignored)
|
|
62
|
-
* createHotkeySequence(['Shift+R', 'Shift+T'], () => {
|
|
63
|
-
* nextAction()
|
|
64
|
-
* })
|
|
65
|
-
* </script>
|
|
66
|
-
*
|
|
67
|
-
* <div>
|
|
68
|
-
* ....
|
|
69
|
-
* </div>
|
|
70
|
-
* ```
|
|
71
|
-
*/
|
|
72
|
-
export function createHotkeySequence(
|
|
73
|
-
sequence: MaybeGetter<HotkeySequence>,
|
|
74
|
-
callback: HotkeyCallback,
|
|
75
|
-
options: MaybeGetter<CreateHotkeySequenceOptions> = {},
|
|
76
|
-
): void {
|
|
77
|
-
let registration: SequenceRegistrationHandle | null = null
|
|
78
|
-
let lastSequenceKey: string | null = null
|
|
79
|
-
|
|
80
|
-
$effect(() => {
|
|
81
|
-
if (typeof document === 'undefined') {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const resolvedSequence = resolveMaybeGetter(sequence)
|
|
86
|
-
const resolvedOptions = resolveMaybeGetter(options)
|
|
87
|
-
const mergedOptions = {
|
|
88
|
-
...getDefaultHotkeysOptions().hotkeySequence,
|
|
89
|
-
...resolvedOptions,
|
|
90
|
-
} as CreateHotkeySequenceOptions
|
|
91
|
-
|
|
92
|
-
const { target: _t, ...optionsWithoutTarget } = mergedOptions
|
|
93
|
-
|
|
94
|
-
if (resolvedSequence.length === 0) {
|
|
95
|
-
if (registration?.isActive) {
|
|
96
|
-
registration.unregister()
|
|
97
|
-
registration = null
|
|
98
|
-
}
|
|
99
|
-
lastSequenceKey = null
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const sequenceKey = formatHotkeySequence(resolvedSequence)
|
|
104
|
-
|
|
105
|
-
if (registration?.isActive && lastSequenceKey === sequenceKey) {
|
|
106
|
-
registration.callback = callback
|
|
107
|
-
registration.setOptions(optionsWithoutTarget)
|
|
108
|
-
return
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (registration?.isActive) {
|
|
112
|
-
registration.unregister()
|
|
113
|
-
registration = null
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
registration = registerHotkeySequence(
|
|
117
|
-
document,
|
|
118
|
-
resolvedSequence,
|
|
119
|
-
callback,
|
|
120
|
-
mergedOptions,
|
|
121
|
-
)
|
|
122
|
-
lastSequenceKey = sequenceKey
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
onDestroy(() => {
|
|
126
|
-
if (registration?.isActive) {
|
|
127
|
-
registration.unregister()
|
|
128
|
-
registration = null
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Create an attachment for element-scoped keyboard sequences.
|
|
135
|
-
*
|
|
136
|
-
* @example
|
|
137
|
-
* ```svelte
|
|
138
|
-
* <script lang="ts">
|
|
139
|
-
* import { createHotkeySequenceAttachment } from '@tanstack/svelte-hotkeys'
|
|
140
|
-
*
|
|
141
|
-
* const vimKeys = createHotkeySequenceAttachment(['G', 'G'], () => {
|
|
142
|
-
* scrollToTop()
|
|
143
|
-
* })
|
|
144
|
-
* </script>
|
|
145
|
-
*
|
|
146
|
-
* <div tabindex="0" {@attach vimKeys}>
|
|
147
|
-
* Focus here and press g then g
|
|
148
|
-
* </div>
|
|
149
|
-
* ```
|
|
150
|
-
*/
|
|
151
|
-
export function createHotkeySequenceAttachment(
|
|
152
|
-
sequence: MaybeGetter<HotkeySequence>,
|
|
153
|
-
callback: HotkeyCallback,
|
|
154
|
-
options: MaybeGetter<CreateHotkeySequenceOptions> = {},
|
|
155
|
-
): Attachment<HTMLElement> {
|
|
156
|
-
return (element) => {
|
|
157
|
-
let registration: SequenceRegistrationHandle | null = null
|
|
158
|
-
let lastSequenceKey: string | null = null
|
|
159
|
-
|
|
160
|
-
$effect(() => {
|
|
161
|
-
const resolvedSequence = resolveMaybeGetter(sequence)
|
|
162
|
-
const resolvedOptions = resolveMaybeGetter(options)
|
|
163
|
-
const mergedOptions = {
|
|
164
|
-
...getDefaultHotkeysOptions().hotkeySequence,
|
|
165
|
-
...resolvedOptions,
|
|
166
|
-
} as CreateHotkeySequenceOptions
|
|
167
|
-
|
|
168
|
-
const { target: _t, ...optionsWithoutTarget } = mergedOptions
|
|
169
|
-
|
|
170
|
-
if (resolvedSequence.length === 0) {
|
|
171
|
-
if (registration?.isActive) {
|
|
172
|
-
registration.unregister()
|
|
173
|
-
registration = null
|
|
174
|
-
}
|
|
175
|
-
lastSequenceKey = null
|
|
176
|
-
return
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const sequenceKey = formatHotkeySequence(resolvedSequence)
|
|
180
|
-
|
|
181
|
-
if (registration?.isActive && lastSequenceKey === sequenceKey) {
|
|
182
|
-
registration.callback = callback
|
|
183
|
-
registration.setOptions(optionsWithoutTarget)
|
|
184
|
-
return
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (registration?.isActive) {
|
|
188
|
-
registration.unregister()
|
|
189
|
-
registration = null
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
registration = registerHotkeySequence(
|
|
193
|
-
element,
|
|
194
|
-
resolvedSequence,
|
|
195
|
-
callback,
|
|
196
|
-
mergedOptions,
|
|
197
|
-
)
|
|
198
|
-
lastSequenceKey = sequenceKey
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
return () => {
|
|
202
|
-
if (registration?.isActive) {
|
|
203
|
-
registration.unregister()
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { HotkeySequenceRecorder } from '@tanstack/hotkeys'
|
|
2
|
-
import { onDestroy } from 'svelte'
|
|
3
|
-
import { getDefaultHotkeysOptions } from './HotkeysCtx'
|
|
4
|
-
import { createStoreSubscriber, resolveMaybeGetter } from './internal.svelte'
|
|
5
|
-
import type {
|
|
6
|
-
HotkeySequence,
|
|
7
|
-
HotkeySequenceRecorderOptions,
|
|
8
|
-
} from '@tanstack/hotkeys'
|
|
9
|
-
import type { MaybeGetter } from './internal.svelte'
|
|
10
|
-
|
|
11
|
-
export interface SvelteHotkeySequenceRecorder {
|
|
12
|
-
readonly isRecording: boolean
|
|
13
|
-
readonly steps: HotkeySequence
|
|
14
|
-
readonly recordedSequence: HotkeySequence | null
|
|
15
|
-
startRecording: () => void
|
|
16
|
-
stopRecording: () => void
|
|
17
|
-
cancelRecording: () => void
|
|
18
|
-
commitRecording: () => void
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
class SvelteHotkeySequenceRecorderState implements SvelteHotkeySequenceRecorder {
|
|
22
|
-
#recorder: HotkeySequenceRecorder
|
|
23
|
-
#subscribe: () => void
|
|
24
|
-
|
|
25
|
-
constructor(options: HotkeySequenceRecorderOptions) {
|
|
26
|
-
this.#recorder = new HotkeySequenceRecorder(options)
|
|
27
|
-
this.#subscribe = createStoreSubscriber(this.#recorder.store)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
get isRecording(): boolean {
|
|
31
|
-
this.#subscribe()
|
|
32
|
-
return this.#recorder.store.state.isRecording
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get steps(): HotkeySequence {
|
|
36
|
-
this.#subscribe()
|
|
37
|
-
return this.#recorder.store.state.steps
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
get recordedSequence(): HotkeySequence | null {
|
|
41
|
-
this.#subscribe()
|
|
42
|
-
return this.#recorder.store.state.recordedSequence
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
setOptions(options: HotkeySequenceRecorderOptions): void {
|
|
46
|
-
this.#recorder.setOptions(options)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
startRecording(): void {
|
|
50
|
-
this.#recorder.start()
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
stopRecording(): void {
|
|
54
|
-
this.#recorder.stop()
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
cancelRecording(): void {
|
|
58
|
-
this.#recorder.cancel()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
commitRecording(): void {
|
|
62
|
-
this.#recorder.commit()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
destroy(): void {
|
|
66
|
-
this.#recorder.destroy()
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Svelte helper for recording multi-chord sequences (Vim-style shortcuts).
|
|
72
|
-
*/
|
|
73
|
-
export function createHotkeySequenceRecorder(
|
|
74
|
-
options: MaybeGetter<HotkeySequenceRecorderOptions>,
|
|
75
|
-
): SvelteHotkeySequenceRecorder {
|
|
76
|
-
const recorder = new SvelteHotkeySequenceRecorderState({
|
|
77
|
-
...getDefaultHotkeysOptions().hotkeySequenceRecorder,
|
|
78
|
-
...resolveMaybeGetter(options),
|
|
79
|
-
} as HotkeySequenceRecorderOptions)
|
|
80
|
-
|
|
81
|
-
$effect(() => {
|
|
82
|
-
recorder.setOptions({
|
|
83
|
-
...getDefaultHotkeysOptions().hotkeySequenceRecorder,
|
|
84
|
-
...resolveMaybeGetter(options),
|
|
85
|
-
} as HotkeySequenceRecorderOptions)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
onDestroy(() => {
|
|
89
|
-
recorder.destroy()
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
return recorder
|
|
93
|
-
}
|