@tanstack/svelte-hotkeys 0.12.1 → 0.14.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 +3 -0
- package/dist/HotkeysCtx.d.ts +48 -12
- package/dist/HotkeysCtx.js +34 -9
- package/dist/HotkeysProvider.svelte +19 -4
- package/dist/createHotkey.svelte.d.ts +37 -24
- package/dist/createHotkey.svelte.js +3 -106
- package/dist/createHotkeyRecorder.svelte.d.ts +35 -8
- package/dist/createHotkeyRecorder.svelte.js +12 -44
- package/dist/createHotkeys.svelte.d.ts +39 -22
- package/dist/createHotkeys.svelte.js +49 -152
- package/dist/getAppHotkeys.svelte.d.ts +49 -0
- package/dist/getAppHotkeys.svelte.js +67 -0
- package/dist/getHotkeyHint.svelte.d.ts +7 -7
- package/dist/getHotkeyHint.svelte.js +25 -11
- package/dist/getHotkeyRegistrations.svelte.d.ts +9 -12
- package/dist/getHotkeyRegistrations.svelte.js +12 -21
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -3
- package/dist/internal.svelte.d.ts +6 -0
- package/dist/internal.svelte.js +8 -0
- package/package.json +5 -5
- package/dist/createHotkeySequence.svelte.d.ts +0 -65
- package/dist/createHotkeySequence.svelte.js +0 -149
- package/dist/createHotkeySequenceRecorder.svelte.d.ts +0 -15
- package/dist/createHotkeySequenceRecorder.svelte.js +0 -65
- package/dist/createHotkeySequences.svelte.d.ts +0 -49
- package/dist/createHotkeySequences.svelte.js +0 -189
package/README.md
CHANGED
|
@@ -67,6 +67,9 @@ Type-safe keyboard shortcuts for the web. Template-string bindings, parsed objec
|
|
|
67
67
|
> [!NOTE]
|
|
68
68
|
> You may know **TanStack Hotkeys** by our adapter names, too!
|
|
69
69
|
>
|
|
70
|
+
> - [**Alpine Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/alpine/quick-start)
|
|
71
|
+
> - [**Ember Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/ember/quick-start)
|
|
72
|
+
> - [**Octane Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/octane/quick-start)
|
|
70
73
|
> - [**React Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/react/react-hotkeys)
|
|
71
74
|
> - [**Preact Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/preact/preact-hotkeys)
|
|
72
75
|
> - [**Solid Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/solid/reference)
|
package/dist/HotkeysCtx.d.ts
CHANGED
|
@@ -1,23 +1,59 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
1
|
+
import { AppHotkeysStore } from '@tanstack/hotkeys';
|
|
2
|
+
import type { AppHotkeys, CustomHotkeys, HotkeyChordRecorderOptions, HotkeySequenceRecorderOptions } from '@tanstack/hotkeys';
|
|
3
|
+
import type { CreateHotkeyCommonOptions } from './createHotkey.svelte';
|
|
3
4
|
import type { Snippet } from 'svelte';
|
|
4
|
-
import type { CreateHotkeySequenceOptions } from './createHotkeySequence.svelte';
|
|
5
5
|
export interface HotkeysProviderOptions {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Defaults for every hotkey registered by `createHotkey` and `createHotkeys`.
|
|
8
|
+
* `requireReset` applies to chords and `timeout` applies to sequences.
|
|
9
|
+
*/
|
|
10
|
+
hotkey?: CreateHotkeyCommonOptions;
|
|
11
|
+
/** Defaults for every `createHotkeyRecorder`. */
|
|
12
|
+
hotkeyRecorder?: Partial<Omit<HotkeyChordRecorderOptions & HotkeySequenceRecorderOptions, 'maxSteps' | 'onRecord' | 'validate'>>;
|
|
10
13
|
}
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
/** Options for `setHotkeysContext` and props for `HotkeysProvider`. */
|
|
15
|
+
export interface HotkeysContextOptions {
|
|
13
16
|
defaultOptions?: HotkeysProviderOptions;
|
|
17
|
+
/**
|
|
18
|
+
* Every app hotkey, from `defineAppHotkeys`. Read when the context is set;
|
|
19
|
+
* listed by `getAppHotkeyList` whether or not they are registered.
|
|
20
|
+
*/
|
|
21
|
+
appHotkeys?: AppHotkeys;
|
|
22
|
+
/**
|
|
23
|
+
* Starting custom hotkeys, such as saved data. Read once; the context owns
|
|
24
|
+
* the state afterwards. Invalid entries are ignored with a warning.
|
|
25
|
+
*/
|
|
26
|
+
customHotkeys?: CustomHotkeys | null;
|
|
27
|
+
/** Called with the custom hotkeys after every change, ready to save. */
|
|
28
|
+
onCustomHotkeysChange?: (customHotkeys: CustomHotkeys) => void;
|
|
29
|
+
}
|
|
30
|
+
export interface HotkeysProviderProps extends HotkeysContextOptions {
|
|
31
|
+
children: Snippet;
|
|
14
32
|
}
|
|
15
33
|
export declare const DEFAULT_OPTIONS: HotkeysProviderOptions;
|
|
16
34
|
interface HotkeysContextValue {
|
|
17
|
-
|
|
35
|
+
readonly appHotkeysStore: AppHotkeysStore | null;
|
|
36
|
+
readonly defaultOptions: HotkeysProviderOptions;
|
|
18
37
|
}
|
|
19
|
-
|
|
20
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Sets the hotkeys context for descendants. `HotkeysProvider` calls this; call
|
|
40
|
+
* it directly in a root component's script instead of rendering the provider.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```svelte
|
|
44
|
+
* <script lang="ts">
|
|
45
|
+
* setHotkeysContext({
|
|
46
|
+
* appHotkeys,
|
|
47
|
+
* customHotkeys: JSON.parse(localStorage.getItem('hotkeys') ?? '{}'),
|
|
48
|
+
* onCustomHotkeysChange: (custom) =>
|
|
49
|
+
* localStorage.setItem('hotkeys', JSON.stringify(custom)),
|
|
50
|
+
* })
|
|
51
|
+
* </script>
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function setHotkeysContext(options?: HotkeysContextOptions): HotkeysContextValue;
|
|
55
|
+
/** Sets the context from a getter, so default options stay reactive. */
|
|
56
|
+
export declare function setHotkeysContextSource(source: () => HotkeysContextOptions): HotkeysContextValue;
|
|
21
57
|
export declare function getHotkeysContext(): HotkeysContextValue | null;
|
|
22
58
|
export declare function getDefaultHotkeysOptions(): HotkeysProviderOptions;
|
|
23
59
|
export {};
|
package/dist/HotkeysCtx.js
CHANGED
|
@@ -1,17 +1,42 @@
|
|
|
1
|
-
import { createContext } from 'svelte';
|
|
1
|
+
import { createContext, onMount } from 'svelte';
|
|
2
|
+
import { AppHotkeysStore, publishAppHotkeysStore } from '@tanstack/hotkeys';
|
|
2
3
|
export const DEFAULT_OPTIONS = {};
|
|
3
4
|
const [useHotkeysContext, setHotkeysContextValue] = createContext();
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Sets the hotkeys context for descendants. `HotkeysProvider` calls this; call
|
|
7
|
+
* it directly in a root component's script instead of rendering the provider.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```svelte
|
|
11
|
+
* <script lang="ts">
|
|
12
|
+
* setHotkeysContext({
|
|
13
|
+
* appHotkeys,
|
|
14
|
+
* customHotkeys: JSON.parse(localStorage.getItem('hotkeys') ?? '{}'),
|
|
15
|
+
* onCustomHotkeysChange: (custom) =>
|
|
16
|
+
* localStorage.setItem('hotkeys', JSON.stringify(custom)),
|
|
17
|
+
* })
|
|
18
|
+
* </script>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function setHotkeysContext(options = {}) {
|
|
22
|
+
return setHotkeysContextSource(() => options);
|
|
10
23
|
}
|
|
11
|
-
|
|
24
|
+
/** Sets the context from a getter, so default options stay reactive. */
|
|
25
|
+
export function setHotkeysContextSource(source) {
|
|
26
|
+
const { appHotkeys, customHotkeys } = source();
|
|
27
|
+
const store = appHotkeys
|
|
28
|
+
? new AppHotkeysStore(appHotkeys, {
|
|
29
|
+
customHotkeys,
|
|
30
|
+
onCustomHotkeysChange: (custom) => source().onCustomHotkeysChange?.(custom),
|
|
31
|
+
})
|
|
32
|
+
: null;
|
|
33
|
+
// Publish the store so devtools can list declared hotkeys.
|
|
34
|
+
if (store)
|
|
35
|
+
onMount(() => publishAppHotkeysStore(store));
|
|
12
36
|
return setHotkeysContextValue({
|
|
37
|
+
appHotkeysStore: store,
|
|
13
38
|
get defaultOptions() {
|
|
14
|
-
return
|
|
39
|
+
return source().defaultOptions ?? DEFAULT_OPTIONS;
|
|
15
40
|
},
|
|
16
41
|
});
|
|
17
42
|
}
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { setHotkeysContextSource } from './HotkeysCtx'
|
|
3
3
|
|
|
4
4
|
import type { HotkeysProviderProps } from './HotkeysCtx'
|
|
5
5
|
|
|
6
|
-
let {
|
|
7
|
-
|
|
6
|
+
let {
|
|
7
|
+
children,
|
|
8
|
+
defaultOptions,
|
|
9
|
+
appHotkeys,
|
|
10
|
+
customHotkeys,
|
|
11
|
+
onCustomHotkeysChange,
|
|
12
|
+
}: HotkeysProviderProps = $props()
|
|
8
13
|
|
|
9
|
-
setHotkeysContextSource(() =>
|
|
14
|
+
const context = setHotkeysContextSource(() => ({
|
|
15
|
+
defaultOptions,
|
|
16
|
+
appHotkeys,
|
|
17
|
+
customHotkeys,
|
|
18
|
+
onCustomHotkeysChange,
|
|
19
|
+
}))
|
|
20
|
+
|
|
21
|
+
// Keep declarations current (for example after hot module replacement).
|
|
22
|
+
$effect(() => {
|
|
23
|
+
if (appHotkeys) context.appHotkeysStore?.setAppHotkeys(appHotkeys)
|
|
24
|
+
})
|
|
10
25
|
</script>
|
|
11
26
|
|
|
12
27
|
{@render children()}
|
|
@@ -1,42 +1,55 @@
|
|
|
1
|
-
import type { HotkeyCallback, HotkeyOptions, RegisterableHotkey } from '@tanstack/hotkeys';
|
|
2
|
-
import type { MaybeGetter } from './internal.svelte';
|
|
3
1
|
import type { Attachment } from 'svelte/attachments';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
2
|
+
import type { AppHotkey, HotkeyCallback, RegisterableHotkey } from '@tanstack/hotkeys';
|
|
3
|
+
import type { AdapterAppHotkeyOptions, AdapterChordOptions, AdapterCommonOptions, AdapterHotkeyOptions, AdapterOptionsFor, AdapterSequenceOptions } from '@tanstack/hotkeys/adapter';
|
|
4
|
+
import type { MaybeGetter } from './internal.svelte';
|
|
5
|
+
/** The document or window to listen on. Use an attachment for elements. */
|
|
6
|
+
export type CreateHotkeyTarget = Document | Window;
|
|
7
|
+
/** Options shared by chords and sequences. */
|
|
8
|
+
export type CreateHotkeyOptions = AdapterHotkeyOptions<CreateHotkeyTarget>;
|
|
9
|
+
/** Options for a chord such as `'Mod+S'`. */
|
|
10
|
+
export type CreateHotkeyChordOptions = AdapterChordOptions<CreateHotkeyTarget>;
|
|
11
|
+
/** Options for a sequence such as `['G', 'G']`. */
|
|
12
|
+
export type CreateHotkeySequenceOptions = AdapterSequenceOptions<CreateHotkeyTarget>;
|
|
13
|
+
/** Options applied to every hotkey, such as provider defaults. Each applies to the kinds that support it. */
|
|
14
|
+
export type CreateHotkeyCommonOptions = AdapterCommonOptions<CreateHotkeyTarget>;
|
|
15
|
+
/** The options type for a hotkey: chord options for chords, sequence options for sequences. */
|
|
16
|
+
export type CreateHotkeyOptionsFor<T extends RegisterableHotkey> = AdapterOptionsFor<T, CreateHotkeyTarget>;
|
|
17
|
+
/** Call-site options for an app hotkey, typed by its declared default kind. */
|
|
18
|
+
export type CreateAppHotkeyOptions<T extends AppHotkey = AppHotkey> = AdapterAppHotkeyOptions<T, CreateHotkeyTarget>;
|
|
7
19
|
/**
|
|
8
|
-
*
|
|
20
|
+
* Svelte function for registering a hotkey on the document: a chord such as
|
|
21
|
+
* `'Mod+S'`, a sequence such as `['G', 'G']`, or an app hotkey from
|
|
22
|
+
* `defineAppHotkeys`. Pass getters for reactive values. Use
|
|
23
|
+
* `createHotkeyAttachment` for element-scoped hotkeys.
|
|
24
|
+
*
|
|
25
|
+
* Chords accept `requireReset`; sequences accept `timeout`. A one-step
|
|
26
|
+
* sequence registers as its chord. An app hotkey uses its effective hotkey
|
|
27
|
+
* from `HotkeysProvider` (including the user's custom hotkey) and its
|
|
28
|
+
* declared meta and options, and registers nothing while unbound.
|
|
9
29
|
*
|
|
10
30
|
* @example
|
|
11
31
|
* ```svelte
|
|
12
32
|
* <script lang="ts">
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* createHotkey('
|
|
16
|
-
* console.log('Mod+S pressed')
|
|
17
|
-
* })
|
|
33
|
+
* createHotkey('Mod+S', () => save())
|
|
34
|
+
* createHotkey(['G', 'G'], () => scrollToTop(), { timeout: 500 })
|
|
35
|
+
* createHotkey('Escape', () => close(), () => ({ enabled: isOpen }))
|
|
18
36
|
* </script>
|
|
19
37
|
* ```
|
|
20
38
|
*/
|
|
21
|
-
export declare function createHotkey(hotkey: MaybeGetter<
|
|
39
|
+
export declare function createHotkey<T extends AppHotkey>(hotkey: MaybeGetter<T>, callback: HotkeyCallback, options?: MaybeGetter<CreateAppHotkeyOptions<T>>): void;
|
|
40
|
+
export declare function createHotkey<T extends RegisterableHotkey>(hotkey: MaybeGetter<T>, callback: HotkeyCallback, options?: MaybeGetter<CreateHotkeyOptionsFor<T>>): void;
|
|
22
41
|
/**
|
|
23
|
-
* Create an attachment for element-scoped
|
|
42
|
+
* Create an attachment for an element-scoped hotkey: a chord, a sequence, or
|
|
43
|
+
* an app hotkey that listens on the attached element.
|
|
24
44
|
*
|
|
25
45
|
* @example
|
|
26
46
|
* ```svelte
|
|
27
47
|
* <script lang="ts">
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* let count = $state(0)
|
|
31
|
-
* const saveHotkey = createHotkeyAttachment('Mod+S', () => {
|
|
32
|
-
* count++
|
|
33
|
-
* })
|
|
34
|
-
*
|
|
48
|
+
* const saveKey = createHotkeyAttachment('Mod+S', () => save())
|
|
35
49
|
* </script>
|
|
36
50
|
*
|
|
37
|
-
* <div tabindex="0" {@attach
|
|
38
|
-
* Count: {count}
|
|
39
|
-
* </div>
|
|
51
|
+
* <div tabindex="0" {@attach saveKey}>Editor content</div>
|
|
40
52
|
* ```
|
|
41
53
|
*/
|
|
42
|
-
export declare function createHotkeyAttachment(hotkey: MaybeGetter<
|
|
54
|
+
export declare function createHotkeyAttachment<T extends AppHotkey>(hotkey: MaybeGetter<T>, callback: HotkeyCallback, options?: MaybeGetter<CreateAppHotkeyOptions<T>>): Attachment<HTMLElement>;
|
|
55
|
+
export declare function createHotkeyAttachment<T extends RegisterableHotkey>(hotkey: MaybeGetter<T>, callback: HotkeyCallback, options?: MaybeGetter<CreateHotkeyOptionsFor<T>>): Attachment<HTMLElement>;
|
|
@@ -1,110 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { onDestroy } from 'svelte';
|
|
3
|
-
import { getDefaultHotkeysOptions } from './HotkeysCtx';
|
|
4
|
-
import { resolveMaybeGetter } from './internal.svelte';
|
|
5
|
-
function registerHotkey(target, hotkey, callback, mergedOptions) {
|
|
6
|
-
return getHotkeyManager().register(normalizeRegisterableHotkey(hotkey, mergedOptions.platform ?? detectPlatform()), callback, {
|
|
7
|
-
...mergedOptions,
|
|
8
|
-
target,
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Register a global hotkey for the current component.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```svelte
|
|
16
|
-
* <script lang="ts">
|
|
17
|
-
* import { createHotkey } from '@tanstack/svelte-hotkeys'
|
|
18
|
-
*
|
|
19
|
-
* createHotkey('Mod+S', () => {
|
|
20
|
-
* console.log('Mod+S pressed')
|
|
21
|
-
* })
|
|
22
|
-
* </script>
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
1
|
+
import { createHotkeys, createHotkeysAttachment } from './createHotkeys.svelte';
|
|
25
2
|
export function createHotkey(hotkey, callback, options = {}) {
|
|
26
|
-
|
|
27
|
-
let lastHotkeyStr = null;
|
|
28
|
-
$effect(() => {
|
|
29
|
-
if (typeof document === 'undefined') {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const resolvedHotkey = resolveMaybeGetter(hotkey);
|
|
33
|
-
const resolvedOptions = resolveMaybeGetter(options);
|
|
34
|
-
const mergedOptions = {
|
|
35
|
-
...getDefaultHotkeysOptions().hotkey,
|
|
36
|
-
...resolvedOptions,
|
|
37
|
-
};
|
|
38
|
-
const hotkeyStr = normalizeRegisterableHotkey(resolvedHotkey, mergedOptions.platform ?? detectPlatform());
|
|
39
|
-
const { target: _t, ...optionsWithoutTarget } = mergedOptions;
|
|
40
|
-
if (registration?.isActive && lastHotkeyStr === hotkeyStr) {
|
|
41
|
-
registration.callback = callback;
|
|
42
|
-
registration.setOptions(optionsWithoutTarget);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (registration?.isActive) {
|
|
46
|
-
registration.unregister();
|
|
47
|
-
registration = null;
|
|
48
|
-
}
|
|
49
|
-
registration = registerHotkey(document, resolvedHotkey, callback, mergedOptions);
|
|
50
|
-
lastHotkeyStr = hotkeyStr;
|
|
51
|
-
});
|
|
52
|
-
onDestroy(() => {
|
|
53
|
-
if (registration?.isActive) {
|
|
54
|
-
registration.unregister();
|
|
55
|
-
registration = null;
|
|
56
|
-
}
|
|
57
|
-
});
|
|
3
|
+
createHotkeys([{ hotkey, callback, options }]);
|
|
58
4
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Create an attachment for element-scoped hotkeys.
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* ```svelte
|
|
64
|
-
* <script lang="ts">
|
|
65
|
-
* import { createHotkeyAttachment } from '@tanstack/svelte-hotkeys'
|
|
66
|
-
*
|
|
67
|
-
* let count = $state(0)
|
|
68
|
-
* const saveHotkey = createHotkeyAttachment('Mod+S', () => {
|
|
69
|
-
* count++
|
|
70
|
-
* })
|
|
71
|
-
*
|
|
72
|
-
* </script>
|
|
73
|
-
*
|
|
74
|
-
* <div tabindex="0" {@attach saveHotkey}>
|
|
75
|
-
* Count: {count}
|
|
76
|
-
* </div>
|
|
77
|
-
* ```
|
|
78
|
-
*/
|
|
79
5
|
export function createHotkeyAttachment(hotkey, callback, options = {}) {
|
|
80
|
-
return (
|
|
81
|
-
let registration = null;
|
|
82
|
-
let lastHotkeyStr = null;
|
|
83
|
-
$effect(() => {
|
|
84
|
-
const resolvedHotkey = resolveMaybeGetter(hotkey);
|
|
85
|
-
const resolvedOptions = resolveMaybeGetter(options);
|
|
86
|
-
const mergedOptions = {
|
|
87
|
-
...getDefaultHotkeysOptions().hotkey,
|
|
88
|
-
...resolvedOptions,
|
|
89
|
-
};
|
|
90
|
-
const hotkeyStr = normalizeRegisterableHotkey(resolvedHotkey, mergedOptions.platform ?? detectPlatform());
|
|
91
|
-
const { target: _t, ...optionsWithoutTarget } = mergedOptions;
|
|
92
|
-
if (registration?.isActive && lastHotkeyStr === hotkeyStr) {
|
|
93
|
-
registration.callback = callback;
|
|
94
|
-
registration.setOptions(optionsWithoutTarget);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (registration?.isActive) {
|
|
98
|
-
registration.unregister();
|
|
99
|
-
registration = null;
|
|
100
|
-
}
|
|
101
|
-
registration = registerHotkey(element, resolvedHotkey, callback, mergedOptions);
|
|
102
|
-
lastHotkeyStr = hotkeyStr;
|
|
103
|
-
});
|
|
104
|
-
return () => {
|
|
105
|
-
if (registration?.isActive) {
|
|
106
|
-
registration.unregister();
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
};
|
|
6
|
+
return createHotkeysAttachment([{ hotkey, callback, options }]);
|
|
110
7
|
}
|
|
@@ -1,15 +1,42 @@
|
|
|
1
|
-
import type { Hotkey, HotkeyRecorderOptions } from '@tanstack/hotkeys';
|
|
2
|
-
|
|
3
|
-
export interface SvelteHotkeyRecorder {
|
|
1
|
+
import type { Hotkey, HotkeyChord, HotkeyChordRecorderOptions, HotkeyRecorderOptions, HotkeySequence, HotkeySequenceRecorderOptions } from '@tanstack/hotkeys';
|
|
2
|
+
export interface SvelteHotkeyRecorder<THotkey extends Hotkey = Hotkey> {
|
|
4
3
|
/** Whether recording is currently active */
|
|
5
4
|
readonly isRecording: boolean;
|
|
6
|
-
/**
|
|
7
|
-
readonly
|
|
5
|
+
/** Chords recorded so far in a multi-step recording (for live preview) */
|
|
6
|
+
readonly steps: HotkeySequence;
|
|
7
|
+
/** The last committed hotkey */
|
|
8
|
+
readonly recordedHotkey: THotkey | null;
|
|
8
9
|
/** Start recording a new hotkey */
|
|
9
10
|
startRecording: () => void;
|
|
10
|
-
/** Stop recording
|
|
11
|
+
/** Stop recording without calling onCancel */
|
|
11
12
|
stopRecording: () => void;
|
|
12
|
-
/** Cancel recording
|
|
13
|
+
/** Cancel recording and call onCancel */
|
|
13
14
|
cancelRecording: () => void;
|
|
15
|
+
/** Commit the recorded steps now (multi-step recordings) */
|
|
16
|
+
commitRecording: () => void;
|
|
14
17
|
}
|
|
15
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Svelte function for recording keyboard shortcuts. Options may be a getter.
|
|
20
|
+
*
|
|
21
|
+
* With the default `maxSteps: 1`, the first valid chord is recorded. With a
|
|
22
|
+
* larger `maxSteps`, each chord adds a step; the recording commits on Enter
|
|
23
|
+
* (unless `commitKeys: 'none'`), after `idleTimeoutMs`, or at `maxSteps`, and
|
|
24
|
+
* `onRecord` receives a chord (one step) or a sequence.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```svelte
|
|
28
|
+
* <script lang="ts">
|
|
29
|
+
* const recorder = createHotkeyRecorder({ onRecord: (hotkey) => (shortcut = hotkey) })
|
|
30
|
+
* const sequenceRecorder = createHotkeyRecorder({ maxSteps: 3, onRecord: save })
|
|
31
|
+
* </script>
|
|
32
|
+
*
|
|
33
|
+
* <button onclick={recorder.startRecording}>
|
|
34
|
+
* {recorder.isRecording ? 'Press keys…' : formatForDisplay(shortcut)}
|
|
35
|
+
* </button>
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function createHotkeyRecorder(options: HotkeyChordRecorderOptions): SvelteHotkeyRecorder<HotkeyChord>;
|
|
39
|
+
export declare function createHotkeyRecorder(options: HotkeySequenceRecorderOptions): SvelteHotkeyRecorder;
|
|
40
|
+
export declare function createHotkeyRecorder(options: () => HotkeySequenceRecorderOptions): SvelteHotkeyRecorder;
|
|
41
|
+
export declare function createHotkeyRecorder(options: () => HotkeyChordRecorderOptions): SvelteHotkeyRecorder<HotkeyChord>;
|
|
42
|
+
export declare function createHotkeyRecorder(options: () => HotkeyRecorderOptions): SvelteHotkeyRecorder;
|
|
@@ -2,42 +2,6 @@ import { HotkeyRecorder } from '@tanstack/hotkeys';
|
|
|
2
2
|
import { onDestroy } from 'svelte';
|
|
3
3
|
import { getDefaultHotkeysOptions } from './HotkeysCtx';
|
|
4
4
|
import { createStoreSubscriber, resolveMaybeGetter } from './internal.svelte';
|
|
5
|
-
/**
|
|
6
|
-
* Svelte function for recording keyboard shortcuts.
|
|
7
|
-
*
|
|
8
|
-
* This function provides a thin wrapper around the framework-agnostic `HotkeyRecorder`
|
|
9
|
-
* class, managing all the complexity of capturing keyboard events, converting them
|
|
10
|
-
* to hotkey strings, and handling edge cases like Escape to cancel or Backspace/Delete
|
|
11
|
-
* to clear.
|
|
12
|
-
*
|
|
13
|
-
* @param options - Configuration options for the recorder
|
|
14
|
-
* @returns An object with recording state and control functions
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```svelte
|
|
18
|
-
* <script>
|
|
19
|
-
* import { createHotkeyRecorder } from '@tanstack/svelte-hotkeys'
|
|
20
|
-
*
|
|
21
|
-
* const recorder = createHotkeyRecorder({
|
|
22
|
-
* onRecord: (hotkey) => {
|
|
23
|
-
* console.log('Recorded:', hotkey) // e.g., "Mod+Shift S"
|
|
24
|
-
* },
|
|
25
|
-
* onCancel: () => {
|
|
26
|
-
* console.log('Recording cancelled')
|
|
27
|
-
* },
|
|
28
|
-
* })
|
|
29
|
-
* </script>
|
|
30
|
-
*
|
|
31
|
-
* <div>
|
|
32
|
-
* <button onclick={recorder.startRecording}>
|
|
33
|
-
* {recorder.isRecording ? 'Recording...' : 'Edit Shortcut'}
|
|
34
|
-
* </button>
|
|
35
|
-
* {#if recorder.recordedHotkey}
|
|
36
|
-
* <div>Recording: {recorder.recordedHotkey}</div>
|
|
37
|
-
* {/if}
|
|
38
|
-
* </div>
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
5
|
class SvelteHotkeyRecorderState {
|
|
42
6
|
#recorder;
|
|
43
7
|
#subscribe;
|
|
@@ -49,6 +13,10 @@ class SvelteHotkeyRecorderState {
|
|
|
49
13
|
this.#subscribe();
|
|
50
14
|
return this.#recorder.store.state.isRecording;
|
|
51
15
|
}
|
|
16
|
+
get steps() {
|
|
17
|
+
this.#subscribe();
|
|
18
|
+
return this.#recorder.store.state.steps;
|
|
19
|
+
}
|
|
52
20
|
get recordedHotkey() {
|
|
53
21
|
this.#subscribe();
|
|
54
22
|
return this.#recorder.store.state.recordedHotkey;
|
|
@@ -56,32 +24,32 @@ class SvelteHotkeyRecorderState {
|
|
|
56
24
|
setOptions(options) {
|
|
57
25
|
this.#recorder.setOptions(options);
|
|
58
26
|
}
|
|
59
|
-
//
|
|
27
|
+
// Arrow functions keep the receiver when used directly as event handlers.
|
|
60
28
|
startRecording = () => {
|
|
61
29
|
this.#recorder.start();
|
|
62
30
|
};
|
|
63
|
-
// Keep the recorder receiver when used directly as an event handler.
|
|
64
31
|
stopRecording = () => {
|
|
65
32
|
this.#recorder.stop();
|
|
66
33
|
};
|
|
67
|
-
// Keep the recorder receiver when used directly as an event handler.
|
|
68
34
|
cancelRecording = () => {
|
|
69
35
|
this.#recorder.cancel();
|
|
70
36
|
};
|
|
37
|
+
commitRecording = () => {
|
|
38
|
+
this.#recorder.commit();
|
|
39
|
+
};
|
|
71
40
|
destroy() {
|
|
72
41
|
this.#recorder.destroy();
|
|
73
42
|
}
|
|
74
43
|
}
|
|
75
44
|
export function createHotkeyRecorder(options) {
|
|
76
|
-
const
|
|
45
|
+
const resolve = () => ({
|
|
77
46
|
...getDefaultHotkeysOptions().hotkeyRecorder,
|
|
78
47
|
...resolveMaybeGetter(options),
|
|
79
48
|
});
|
|
49
|
+
// Overloads already checked the options; either shape is valid here.
|
|
50
|
+
const recorder = new SvelteHotkeyRecorderState(resolve());
|
|
80
51
|
$effect(() => {
|
|
81
|
-
recorder.setOptions(
|
|
82
|
-
...getDefaultHotkeysOptions().hotkeyRecorder,
|
|
83
|
-
...resolveMaybeGetter(options),
|
|
84
|
-
});
|
|
52
|
+
recorder.setOptions(resolve());
|
|
85
53
|
});
|
|
86
54
|
onDestroy(() => {
|
|
87
55
|
recorder.destroy();
|
|
@@ -1,52 +1,69 @@
|
|
|
1
|
-
import type { HotkeyCallback, RegisterableHotkey } from '@tanstack/hotkeys';
|
|
2
|
-
import type { CreateHotkeyOptions } from './createHotkey.svelte';
|
|
3
|
-
import type { MaybeGetter } from './internal.svelte';
|
|
4
1
|
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
import type { AppHotkey, HotkeyCallback, HotkeySequence, RegisterableHotkey, RegisterableHotkeyChord } from '@tanstack/hotkeys';
|
|
3
|
+
import type { MaybeGetter } from './internal.svelte';
|
|
4
|
+
import type { CreateAppHotkeyOptions, CreateHotkeyChordOptions, CreateHotkeyCommonOptions, CreateHotkeyOptions, CreateHotkeySequenceOptions } from './createHotkey.svelte';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* One hotkey for `createHotkeys`. The hotkey and options may be getters.
|
|
7
|
+
* Chords accept `requireReset`; sequences accept `timeout`; hotkeys of unknown
|
|
8
|
+
* kind accept only shared options.
|
|
7
9
|
*/
|
|
8
|
-
export
|
|
9
|
-
/**
|
|
10
|
-
hotkey: MaybeGetter<
|
|
10
|
+
export type CreateHotkeyDefinition = {
|
|
11
|
+
/** A chord string such as `'Mod+S'`, or a RawHotkey object */
|
|
12
|
+
hotkey: MaybeGetter<RegisterableHotkeyChord>;
|
|
11
13
|
/** The function to call when the hotkey is pressed */
|
|
12
14
|
callback: HotkeyCallback;
|
|
13
15
|
/** Per-hotkey options (merged on top of commonOptions) */
|
|
16
|
+
options?: MaybeGetter<CreateHotkeyChordOptions>;
|
|
17
|
+
} | {
|
|
18
|
+
/** A sequence such as `['G', 'G']` */
|
|
19
|
+
hotkey: MaybeGetter<HotkeySequence>;
|
|
20
|
+
callback: HotkeyCallback;
|
|
21
|
+
options?: MaybeGetter<CreateHotkeySequenceOptions>;
|
|
22
|
+
} | {
|
|
23
|
+
/** An app hotkey from `defineAppHotkeys` */
|
|
24
|
+
hotkey: MaybeGetter<AppHotkey>;
|
|
25
|
+
callback: HotkeyCallback;
|
|
26
|
+
options?: MaybeGetter<CreateAppHotkeyOptions>;
|
|
27
|
+
} | {
|
|
28
|
+
/** A hotkey whose kind is not known statically. Accepts only shared options. */
|
|
29
|
+
hotkey: MaybeGetter<RegisterableHotkey>;
|
|
30
|
+
callback: HotkeyCallback;
|
|
14
31
|
options?: MaybeGetter<CreateHotkeyOptions>;
|
|
15
|
-
}
|
|
32
|
+
};
|
|
16
33
|
/**
|
|
17
|
-
*
|
|
34
|
+
* Svelte function for registering several hotkeys at once on the document:
|
|
35
|
+
* chords, sequences, and app hotkeys. Pass getters for reactive values. Use
|
|
36
|
+
* `createHotkeysAttachment` for element-scoped hotkeys.
|
|
37
|
+
*
|
|
38
|
+
* Options merge in this order: provider defaults, app hotkey declaration,
|
|
39
|
+
* commonOptions, per-hotkey options. Each option applies only to the kinds
|
|
40
|
+
* that support it. Unbound app hotkeys and empty sequences register nothing.
|
|
18
41
|
*
|
|
19
42
|
* @example
|
|
20
43
|
* ```svelte
|
|
21
44
|
* <script lang="ts">
|
|
22
|
-
* import { createHotkeys } from '@tanstack/svelte-hotkeys'
|
|
23
|
-
*
|
|
24
45
|
* createHotkeys([
|
|
25
46
|
* { hotkey: 'Mod+S', callback: () => save() },
|
|
26
|
-
* { hotkey: '
|
|
27
|
-
* { hotkey: 'Escape', callback: () => close() },
|
|
47
|
+
* { hotkey: ['G', 'G'], callback: () => scrollToTop(), options: { timeout: 500 } },
|
|
28
48
|
* ])
|
|
29
49
|
* </script>
|
|
30
50
|
* ```
|
|
31
51
|
*/
|
|
32
|
-
export declare function createHotkeys(hotkeys: MaybeGetter<
|
|
52
|
+
export declare function createHotkeys(hotkeys: MaybeGetter<ReadonlyArray<CreateHotkeyDefinition>>, commonOptions?: MaybeGetter<CreateHotkeyCommonOptions>): void;
|
|
33
53
|
/**
|
|
34
|
-
* Create an attachment for element-scoped
|
|
54
|
+
* Create an attachment for element-scoped hotkeys: chords, sequences, and app
|
|
55
|
+
* hotkeys listen on the attached element.
|
|
35
56
|
*
|
|
36
57
|
* @example
|
|
37
58
|
* ```svelte
|
|
38
59
|
* <script lang="ts">
|
|
39
|
-
* import { createHotkeysAttachment } from '@tanstack/svelte-hotkeys'
|
|
40
|
-
*
|
|
41
60
|
* const editorKeys = createHotkeysAttachment([
|
|
42
61
|
* { hotkey: 'Mod+S', callback: () => save() },
|
|
43
|
-
* { hotkey: '
|
|
62
|
+
* { hotkey: ['G', 'G'], callback: () => scrollToTop() },
|
|
44
63
|
* ])
|
|
45
64
|
* </script>
|
|
46
65
|
*
|
|
47
|
-
* <div tabindex="0" {@attach editorKeys}>
|
|
48
|
-
* Editor content
|
|
49
|
-
* </div>
|
|
66
|
+
* <div tabindex="0" {@attach editorKeys}>Editor content</div>
|
|
50
67
|
* ```
|
|
51
68
|
*/
|
|
52
|
-
export declare function createHotkeysAttachment(hotkeys: MaybeGetter<
|
|
69
|
+
export declare function createHotkeysAttachment(hotkeys: MaybeGetter<ReadonlyArray<CreateHotkeyDefinition>>, commonOptions?: MaybeGetter<CreateHotkeyCommonOptions>): Attachment<HTMLElement>;
|