@tanstack/svelte-hotkeys 0.13.0 → 0.14.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.
@@ -1,184 +1,81 @@
1
- import { detectPlatform, getHotkeyManager, normalizeRegisterableHotkey, } from '@tanstack/hotkeys';
1
+ import { createHotkeyBindings, prepareHotkeyDefinitions, } from '@tanstack/hotkeys/adapter';
2
2
  import { onDestroy } from 'svelte';
3
- import { SvelteMap, SvelteSet } from 'svelte/reactivity';
4
- import { getDefaultHotkeysOptions } from './HotkeysCtx';
5
- import { resolveMaybeGetter } from './internal.svelte';
6
- function cleanupRegistrations(registrations) {
7
- for (const { handle } of registrations.values()) {
8
- if (handle.isActive) {
9
- handle.unregister();
3
+ import { getHotkeysContext } from './HotkeysCtx';
4
+ import { createAppHotkeysSubscriber, resolveMaybeGetter, } from './internal.svelte';
5
+ /**
6
+ * Registers definitions in an effect. With an element, every hotkey listens on
7
+ * that element; otherwise each uses its own target (document by default).
8
+ */
9
+ function bindHotkeys(hotkeys, commonOptions, element) {
10
+ const context = getHotkeysContext();
11
+ const subscribeAppHotkeys = createAppHotkeysSubscriber(context?.appHotkeysStore ?? null);
12
+ const bindings = createHotkeyBindings();
13
+ $effect(() => {
14
+ if (typeof document === 'undefined') {
15
+ return;
10
16
  }
11
- }
12
- registrations.clear();
17
+ // Track app hotkeys so registrations move with custom hotkeys.
18
+ subscribeAppHotkeys();
19
+ const definitions = resolveMaybeGetter(hotkeys).map((definition) => ({
20
+ hotkey: resolveMaybeGetter(definition.hotkey),
21
+ callback: definition.callback,
22
+ options: definition.options
23
+ ? resolveMaybeGetter(definition.options)
24
+ : undefined,
25
+ }));
26
+ bindings.update(prepareHotkeyDefinitions(definitions, {
27
+ appHotkeysStore: context?.appHotkeysStore,
28
+ defaults: context?.defaultOptions.hotkey,
29
+ commonOptions: element
30
+ ? { ...resolveMaybeGetter(commonOptions), target: element }
31
+ : resolveMaybeGetter(commonOptions),
32
+ resolveTarget: element ? () => element : undefined,
33
+ }));
34
+ });
35
+ return bindings;
13
36
  }
14
37
  /**
15
- * Register multiple global hotkeys for the current component.
38
+ * Svelte function for registering several hotkeys at once on the document:
39
+ * chords, sequences, and app hotkeys. Pass getters for reactive values. Use
40
+ * `createHotkeysAttachment` for element-scoped hotkeys.
41
+ *
42
+ * Options merge in this order: provider defaults, app hotkey declaration,
43
+ * commonOptions, per-hotkey options. Each option applies only to the kinds
44
+ * that support it. Unbound app hotkeys and empty sequences register nothing.
16
45
  *
17
46
  * @example
18
47
  * ```svelte
19
48
  * <script lang="ts">
20
- * import { createHotkeys } from '@tanstack/svelte-hotkeys'
21
- *
22
49
  * createHotkeys([
23
50
  * { hotkey: 'Mod+S', callback: () => save() },
24
- * { hotkey: 'Mod+Z', callback: () => undo() },
25
- * { hotkey: 'Escape', callback: () => close() },
51
+ * { hotkey: ['G', 'G'], callback: () => scrollToTop(), options: { timeout: 500 } },
26
52
  * ])
27
53
  * </script>
28
54
  * ```
29
55
  */
30
56
  export function createHotkeys(hotkeys, commonOptions = {}) {
31
- const registrations = new SvelteMap();
32
- onDestroy(() => {
33
- cleanupRegistrations(registrations);
34
- });
35
- $effect(() => {
36
- if (typeof document === 'undefined') {
37
- return;
38
- }
39
- const resolvedHotkeys = resolveMaybeGetter(hotkeys);
40
- const resolvedCommonOptions = resolveMaybeGetter(commonOptions);
41
- const nextKeys = new SvelteSet();
42
- const prepared = [];
43
- for (let i = 0; i < resolvedHotkeys.length; i++) {
44
- const def = resolvedHotkeys[i];
45
- const resolvedHotkey = resolveMaybeGetter(def.hotkey);
46
- const resolvedDefOptions = def.options
47
- ? resolveMaybeGetter(def.options)
48
- : {};
49
- const mergedOptions = {
50
- ...getDefaultHotkeysOptions().hotkey,
51
- ...resolvedCommonOptions,
52
- ...resolvedDefOptions,
53
- };
54
- const resolvedTarget = mergedOptions.target ??
55
- (typeof document !== 'undefined' ? document : null);
56
- if (!resolvedTarget) {
57
- continue;
58
- }
59
- const hotkeyString = normalizeRegisterableHotkey(resolvedHotkey, mergedOptions.platform ?? detectPlatform());
60
- const registrationKey = `${i}:${hotkeyString}`;
61
- nextKeys.add(registrationKey);
62
- prepared.push({
63
- registrationKey,
64
- def,
65
- mergedOptions,
66
- hotkeyString,
67
- resolvedTarget,
68
- });
69
- }
70
- for (const [key, record] of [...registrations.entries()]) {
71
- if (!nextKeys.has(key)) {
72
- if (record.handle.isActive) {
73
- record.handle.unregister();
74
- }
75
- registrations.delete(key);
76
- }
77
- }
78
- for (const p of prepared) {
79
- const existing = registrations.get(p.registrationKey);
80
- const { target: _target, ...optionsWithoutTarget } = p.mergedOptions;
81
- if (existing?.handle.isActive && existing.target === p.resolvedTarget) {
82
- existing.handle.callback = p.def.callback;
83
- existing.handle.setOptions(optionsWithoutTarget);
84
- continue;
85
- }
86
- if (existing?.handle.isActive) {
87
- existing.handle.unregister();
88
- }
89
- if (existing) {
90
- registrations.delete(p.registrationKey);
91
- }
92
- const handle = getHotkeyManager().register(p.hotkeyString, p.def.callback, {
93
- ...optionsWithoutTarget,
94
- target: p.resolvedTarget,
95
- });
96
- registrations.set(p.registrationKey, {
97
- handle,
98
- target: p.resolvedTarget,
99
- });
100
- }
101
- });
57
+ const bindings = bindHotkeys(hotkeys, commonOptions);
58
+ onDestroy(() => bindings.destroy());
102
59
  }
103
60
  /**
104
- * Create an attachment for element-scoped multi-hotkey registration.
61
+ * Create an attachment for element-scoped hotkeys: chords, sequences, and app
62
+ * hotkeys listen on the attached element.
105
63
  *
106
64
  * @example
107
65
  * ```svelte
108
66
  * <script lang="ts">
109
- * import { createHotkeysAttachment } from '@tanstack/svelte-hotkeys'
110
- *
111
67
  * const editorKeys = createHotkeysAttachment([
112
68
  * { hotkey: 'Mod+S', callback: () => save() },
113
- * { hotkey: 'Mod+Z', callback: () => undo() },
69
+ * { hotkey: ['G', 'G'], callback: () => scrollToTop() },
114
70
  * ])
115
71
  * </script>
116
72
  *
117
- * <div tabindex="0" {@attach editorKeys}>
118
- * Editor content
119
- * </div>
73
+ * <div tabindex="0" {@attach editorKeys}>Editor content</div>
120
74
  * ```
121
75
  */
122
76
  export function createHotkeysAttachment(hotkeys, commonOptions = {}) {
123
77
  return (element) => {
124
- const registrations = new SvelteMap();
125
- $effect(() => {
126
- const resolvedHotkeys = resolveMaybeGetter(hotkeys);
127
- const resolvedCommonOptions = resolveMaybeGetter(commonOptions);
128
- const nextKeys = new SvelteSet();
129
- const prepared = [];
130
- for (let i = 0; i < resolvedHotkeys.length; i++) {
131
- const def = resolvedHotkeys[i];
132
- const resolvedHotkey = resolveMaybeGetter(def.hotkey);
133
- const resolvedDefOptions = def.options
134
- ? resolveMaybeGetter(def.options)
135
- : {};
136
- const mergedOptions = {
137
- ...getDefaultHotkeysOptions().hotkey,
138
- ...resolvedCommonOptions,
139
- ...resolvedDefOptions,
140
- };
141
- const hotkeyString = normalizeRegisterableHotkey(resolvedHotkey, mergedOptions.platform ?? detectPlatform());
142
- const registrationKey = `${i}:${hotkeyString}`;
143
- nextKeys.add(registrationKey);
144
- prepared.push({
145
- registrationKey,
146
- def,
147
- mergedOptions,
148
- hotkeyString,
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
- for (const p of prepared) {
160
- const existing = registrations.get(p.registrationKey);
161
- const { target: _target, ...optionsWithoutTarget } = p.mergedOptions;
162
- if (existing?.handle.isActive) {
163
- existing.handle.callback = p.def.callback;
164
- existing.handle.setOptions(optionsWithoutTarget);
165
- continue;
166
- }
167
- if (existing?.handle.isActive) {
168
- existing.handle.unregister();
169
- }
170
- if (existing) {
171
- registrations.delete(p.registrationKey);
172
- }
173
- const handle = getHotkeyManager().register(p.hotkeyString, p.def.callback, {
174
- ...optionsWithoutTarget,
175
- target: element,
176
- });
177
- registrations.set(p.registrationKey, { handle, target: element });
178
- }
179
- });
180
- return () => {
181
- cleanupRegistrations(registrations);
182
- };
78
+ const bindings = bindHotkeys(hotkeys, commonOptions, element);
79
+ return () => bindings.destroy();
183
80
  };
184
81
  }
@@ -0,0 +1,49 @@
1
+ import type { AppHotkey, AppHotkeyListItem, CustomHotkeys, Hotkey, RegisteredAppHotkeys } from '@tanstack/hotkeys';
2
+ export interface SvelteAppHotkeys {
3
+ /** Effective app hotkeys: each declaration with the user's custom hotkey applied. */
4
+ readonly current: RegisteredAppHotkeys;
5
+ }
6
+ /**
7
+ * Returns reactive access to the effective app hotkeys from `HotkeysProvider`,
8
+ * typed by `Register`.
9
+ *
10
+ * @example
11
+ * ```svelte
12
+ * <script lang="ts">
13
+ * const hotkeys = getAppHotkeys()
14
+ * createHotkey(() => hotkeys.current['doc.save'], () => save())
15
+ * </script>
16
+ * ```
17
+ */
18
+ export declare function getAppHotkeys(): SvelteAppHotkeys;
19
+ export interface SvelteAppHotkeyList {
20
+ /** Every app hotkey with its live status, in declaration order. */
21
+ readonly current: Array<AppHotkeyListItem<RegisteredAppHotkeys[keyof RegisteredAppHotkeys]>>;
22
+ }
23
+ /**
24
+ * Lists every app hotkey with its live status, for cheat sheets and settings
25
+ * screens. App hotkeys whose components have not mounted are `'inactive'`;
26
+ * those without a hotkey are `'unbound'`.
27
+ */
28
+ export declare function getAppHotkeyList(): SvelteAppHotkeyList;
29
+ export interface SvelteCustomHotkeys {
30
+ /** The user's hotkeys that differ from the defaults. */
31
+ readonly current: CustomHotkeys;
32
+ /**
33
+ * Sets the user's hotkey for an app hotkey. `null` unbinds it.
34
+ * Returns conflicting app hotkeys; when any exist, nothing changes.
35
+ */
36
+ setCustomHotkey: (id: keyof RegisteredAppHotkeys & string, hotkey: Hotkey | null) => Array<AppHotkey>;
37
+ /** Restores the default hotkey for an app hotkey. */
38
+ resetCustomHotkey: (id: keyof RegisteredAppHotkeys & string) => void;
39
+ /** Restores every default hotkey. */
40
+ resetCustomHotkeys: () => void;
41
+ /** Other app hotkeys that would collide if `id` used `hotkey`. */
42
+ findConflicts: (id: keyof RegisteredAppHotkeys & string, hotkey: Hotkey) => Array<AppHotkey>;
43
+ }
44
+ /**
45
+ * Reads and changes the user's custom hotkeys. Changes apply to every
46
+ * registered app hotkey immediately and are passed to the provider's
47
+ * `onCustomHotkeysChange`, ready to save.
48
+ */
49
+ export declare function getCustomHotkeys(): SvelteCustomHotkeys;
@@ -0,0 +1,67 @@
1
+ import { getHotkeysContext } from './HotkeysCtx';
2
+ import { createStoreSubscriber } from './internal.svelte';
3
+ import { getHotkeyRegistrations } from './getHotkeyRegistrations.svelte';
4
+ function requireStore(name) {
5
+ const store = getHotkeysContext()?.appHotkeysStore;
6
+ if (!store) {
7
+ throw new Error(`${name} requires a HotkeysProvider with appHotkeys`);
8
+ }
9
+ return {
10
+ store: store,
11
+ subscribe: createStoreSubscriber(store.store),
12
+ };
13
+ }
14
+ /**
15
+ * Returns reactive access to the effective app hotkeys from `HotkeysProvider`,
16
+ * typed by `Register`.
17
+ *
18
+ * @example
19
+ * ```svelte
20
+ * <script lang="ts">
21
+ * const hotkeys = getAppHotkeys()
22
+ * createHotkey(() => hotkeys.current['doc.save'], () => save())
23
+ * </script>
24
+ * ```
25
+ */
26
+ export function getAppHotkeys() {
27
+ const { store, subscribe } = requireStore('getAppHotkeys');
28
+ return {
29
+ get current() {
30
+ subscribe();
31
+ return store.appHotkeys;
32
+ },
33
+ };
34
+ }
35
+ /**
36
+ * Lists every app hotkey with its live status, for cheat sheets and settings
37
+ * screens. App hotkeys whose components have not mounted are `'inactive'`;
38
+ * those without a hotkey are `'unbound'`.
39
+ */
40
+ export function getAppHotkeyList() {
41
+ const { store, subscribe } = requireStore('getAppHotkeyList');
42
+ const registrations = getHotkeyRegistrations();
43
+ return {
44
+ get current() {
45
+ subscribe();
46
+ return store.getList(registrations.hotkeys);
47
+ },
48
+ };
49
+ }
50
+ /**
51
+ * Reads and changes the user's custom hotkeys. Changes apply to every
52
+ * registered app hotkey immediately and are passed to the provider's
53
+ * `onCustomHotkeysChange`, ready to save.
54
+ */
55
+ export function getCustomHotkeys() {
56
+ const { store, subscribe } = requireStore('getCustomHotkeys');
57
+ return {
58
+ get current() {
59
+ subscribe();
60
+ return store.customHotkeys;
61
+ },
62
+ setCustomHotkey: (id, hotkey) => store.setCustomHotkey(id, hotkey),
63
+ resetCustomHotkey: (id) => store.resetCustomHotkey(id),
64
+ resetCustomHotkeys: () => store.resetCustomHotkeys(),
65
+ findConflicts: (id, hotkey) => store.findConflicts(id, hotkey),
66
+ };
67
+ }
@@ -1,13 +1,13 @@
1
- import type { HeldModifierOptions, RegisterableHotkey } from '@tanstack/hotkeys';
1
+ import type { AppHotkey, HeldModifierOptions, RegisterableHotkey } from '@tanstack/hotkeys';
2
2
  import type { MaybeGetter } from './internal.svelte';
3
3
  export interface SvelteHotkeyHint {
4
4
  readonly visible: boolean;
5
5
  }
6
6
  /**
7
- * Returns an object with a reactive `visible` getter indicating whether held modifiers reveal this shortcut.
8
- * Pass getters to track changing bindings and options.
9
- * Uses the nonempty-subset/AltGr rules of `matchesHeldModifiers`; `exact` requires
10
- * every modifier. Combine with the action's enabled state before showing a badge.
11
- * This helper does not register a shortcut or check whether its target is focused.
7
+ * Returns an object with a reactive `visible` getter indicating whether held
8
+ * modifiers reveal this shortcut. Pass getters to track changing hotkeys and
9
+ * options. A sequence reveals its hint from its first step, and an app hotkey
10
+ * uses its effective hotkey (false while unbound). This helper does not
11
+ * register a shortcut or check whether its target is focused.
12
12
  */
13
- export declare function getHotkeyHint(hotkey: MaybeGetter<RegisterableHotkey>, options?: MaybeGetter<HeldModifierOptions>): SvelteHotkeyHint;
13
+ export declare function getHotkeyHint(hotkey: MaybeGetter<RegisterableHotkey | AppHotkey>, options?: MaybeGetter<HeldModifierOptions>): SvelteHotkeyHint;
@@ -1,29 +1,43 @@
1
1
  import { createSubscriber } from 'svelte/reactivity';
2
- import { getKeyStateTracker, matchesHeldModifiers } from '@tanstack/hotkeys';
2
+ import { getKeyStateTracker, isAppHotkey, matchesHeldModifiers, resolveAppHotkey, } from '@tanstack/hotkeys';
3
+ import { getHotkeysContext } from './HotkeysCtx';
3
4
  import { resolveMaybeGetter } from './internal.svelte';
4
5
  /**
5
- * Returns an object with a reactive `visible` getter indicating whether held modifiers reveal this shortcut.
6
- * Pass getters to track changing bindings and options.
7
- * Uses the nonempty-subset/AltGr rules of `matchesHeldModifiers`; `exact` requires
8
- * every modifier. Combine with the action's enabled state before showing a badge.
9
- * This helper does not register a shortcut or check whether its target is focused.
6
+ * Returns an object with a reactive `visible` getter indicating whether held
7
+ * modifiers reveal this shortcut. Pass getters to track changing hotkeys and
8
+ * options. A sequence reveals its hint from its first step, and an app hotkey
9
+ * uses its effective hotkey (false while unbound). This helper does not
10
+ * register a shortcut or check whether its target is focused.
10
11
  */
11
12
  export function getHotkeyHint(hotkey, options = {}) {
12
13
  const tracker = getKeyStateTracker();
13
- // Resolve current reactive arguments without caching a stale binding.
14
- const read = () => matchesHeldModifiers(resolveMaybeGetter(hotkey), tracker.store.state.heldKeys, resolveMaybeGetter(options));
14
+ const store = getHotkeysContext()?.appHotkeysStore ?? null;
15
+ // Resolve current reactive arguments without caching a stale hotkey.
16
+ const read = () => {
17
+ const value = resolveMaybeGetter(hotkey);
18
+ const resolved = isAppHotkey(value)
19
+ ? resolveAppHotkey(value, store).hotkey
20
+ : value;
21
+ return (resolved !== null &&
22
+ matchesHeldModifiers(resolved, tracker.store.state.heldKeys, resolveMaybeGetter(options)));
23
+ };
15
24
  let previous = false;
16
25
  // Notify Svelte only when visibility changes, not for every unrelated held key.
17
26
  const subscribe = createSubscriber((update) => {
18
27
  previous = read();
19
- const subscription = tracker.store.subscribe(() => {
28
+ const check = () => {
20
29
  const next = read();
21
30
  if (next !== previous) {
22
31
  previous = next;
23
32
  update();
24
33
  }
25
- });
26
- return () => subscription.unsubscribe();
34
+ };
35
+ const keys = tracker.store.subscribe(check);
36
+ const custom = store?.store.subscribe(check);
37
+ return () => {
38
+ keys.unsubscribe();
39
+ custom?.unsubscribe();
40
+ };
27
41
  });
28
42
  return {
29
43
  /** Reads visibility and subscribes the current reactive consumer when needed. */
@@ -1,25 +1,22 @@
1
- import type { HotkeyRegistrationView, SequenceRegistrationView } from '@tanstack/hotkeys';
1
+ import type { HotkeyRegistrationView } from '@tanstack/hotkeys';
2
2
  export interface SvelteHotkeyRegistrations {
3
+ /** Every registration, chords and sequences. Narrow each view with `kind`. */
3
4
  readonly hotkeys: Array<HotkeyRegistrationView>;
4
- readonly sequences: Array<SequenceRegistrationView>;
5
5
  }
6
6
  /**
7
- * Svelte function that returns reactive access to all hotkey and sequence
8
- * registrations from the singleton managers.
7
+ * Svelte function that returns reactive access to every hotkey registration,
8
+ * chords and sequences, from the singleton HotkeyManager.
9
9
  *
10
- * This is a standalone function that does NOT require the HotkeysProvider.
11
- *
12
- * @returns Object with reactive `hotkeys` and `sequences` properties
10
+ * This function does NOT require the HotkeysProvider.
13
11
  *
14
12
  * @example
15
13
  * ```svelte
16
- * <script>
17
- * import { getHotkeyRegistrations } from '@tanstack/svelte-hotkeys'
18
- *
14
+ * <script lang="ts">
19
15
  * const registrations = getHotkeyRegistrations()
20
16
  * </script>
21
- * {#each registrations.hotkeys as reg}
22
- * <div>{reg.options.meta?.name} — {reg.triggerCount} triggers</div>
17
+ *
18
+ * {#each registrations.hotkeys as reg (reg.id)}
19
+ * <li>{reg.options.meta?.name}: {formatForDisplay(reg.hotkey)}</li>
23
20
  * {/each}
24
21
  * ```
25
22
  */
@@ -1,36 +1,27 @@
1
- import { getHotkeyManager, getSequenceManager, toHotkeyRegistrationView, } from '@tanstack/hotkeys';
1
+ import { getHotkeyManager, toHotkeyRegistrationView } from '@tanstack/hotkeys';
2
2
  import { createStoreSubscriber } from './internal.svelte';
3
3
  class HotkeyRegistrationsState {
4
- #hotkeyManager = getHotkeyManager();
5
- #sequenceManager = getSequenceManager();
6
- #subscribeHotkeys = createStoreSubscriber(this.#hotkeyManager.registrations);
7
- #subscribeSequences = createStoreSubscriber(this.#sequenceManager.registrations);
4
+ #manager = getHotkeyManager();
5
+ #subscribe = createStoreSubscriber(this.#manager.registrations);
8
6
  get hotkeys() {
9
- this.#subscribeHotkeys();
10
- return Array.from(this.#hotkeyManager.registrations.state.values()).map(toHotkeyRegistrationView);
11
- }
12
- get sequences() {
13
- this.#subscribeSequences();
14
- return Array.from(this.#sequenceManager.registrations.state.values());
7
+ this.#subscribe();
8
+ return Array.from(this.#manager.registrations.state.values()).map(toHotkeyRegistrationView);
15
9
  }
16
10
  }
17
11
  /**
18
- * Svelte function that returns reactive access to all hotkey and sequence
19
- * registrations from the singleton managers.
20
- *
21
- * This is a standalone function that does NOT require the HotkeysProvider.
12
+ * Svelte function that returns reactive access to every hotkey registration,
13
+ * chords and sequences, from the singleton HotkeyManager.
22
14
  *
23
- * @returns Object with reactive `hotkeys` and `sequences` properties
15
+ * This function does NOT require the HotkeysProvider.
24
16
  *
25
17
  * @example
26
18
  * ```svelte
27
- * <script>
28
- * import { getHotkeyRegistrations } from '@tanstack/svelte-hotkeys'
29
- *
19
+ * <script lang="ts">
30
20
  * const registrations = getHotkeyRegistrations()
31
21
  * </script>
32
- * {#each registrations.hotkeys as reg}
33
- * <div>{reg.options.meta?.name} — {reg.triggerCount} triggers</div>
22
+ *
23
+ * {#each registrations.hotkeys as reg (reg.id)}
24
+ * <li>{reg.options.meta?.name}: {formatForDisplay(reg.hotkey)}</li>
34
25
  * {/each}
35
26
  * ```
36
27
  */
package/dist/index.d.ts CHANGED
@@ -1,15 +1,13 @@
1
1
  export * from '@tanstack/hotkeys';
2
2
  export * from './createHotkey.svelte';
3
3
  export * from './createHotkeys.svelte';
4
- export * from './createHotkeySequence.svelte';
5
- export * from './createHotkeySequences.svelte';
6
4
  export * from './createHotkeyRecorder.svelte';
7
- export * from './createHotkeySequenceRecorder.svelte';
8
5
  export * from './getHeldKeys.svelte';
9
6
  export * from './getHotkeyRegistrations.svelte';
10
7
  export * from './getHeldKeyCodesMap.svelte';
11
8
  export * from './getIsKeyHeld.svelte';
9
+ export * from './getAppHotkeys.svelte';
12
10
  export { default as HotkeysProvider } from './HotkeysProvider.svelte';
13
11
  export { DEFAULT_OPTIONS, getDefaultHotkeysOptions, getHotkeysContext, setHotkeysContext, } from './HotkeysCtx';
14
- export type { HotkeysProviderOptions, HotkeysProviderProps } from './HotkeysCtx';
12
+ export type { HotkeysContextOptions, HotkeysProviderOptions, HotkeysProviderProps, } from './HotkeysCtx';
15
13
  export * from './getHotkeyHint.svelte';
package/dist/index.js CHANGED
@@ -2,14 +2,12 @@
2
2
  export * from '@tanstack/hotkeys';
3
3
  export * from './createHotkey.svelte';
4
4
  export * from './createHotkeys.svelte';
5
- export * from './createHotkeySequence.svelte';
6
- export * from './createHotkeySequences.svelte';
7
5
  export * from './createHotkeyRecorder.svelte';
8
- export * from './createHotkeySequenceRecorder.svelte';
9
6
  export * from './getHeldKeys.svelte';
10
7
  export * from './getHotkeyRegistrations.svelte';
11
8
  export * from './getHeldKeyCodesMap.svelte';
12
9
  export * from './getIsKeyHeld.svelte';
10
+ export * from './getAppHotkeys.svelte';
13
11
  export { default as HotkeysProvider } from './HotkeysProvider.svelte';
14
12
  export { DEFAULT_OPTIONS, getDefaultHotkeysOptions, getHotkeysContext, setHotkeysContext, } from './HotkeysCtx';
15
13
  export * from './getHotkeyHint.svelte';
@@ -1,3 +1,4 @@
1
+ import type { AppHotkeysStore } from '@tanstack/hotkeys';
1
2
  export type MaybeGetter<T> = T | (() => T);
2
3
  interface SubscribableStore<TState> {
3
4
  state: TState;
@@ -7,4 +8,9 @@ interface SubscribableStore<TState> {
7
8
  }
8
9
  export declare function resolveMaybeGetter<T>(value: MaybeGetter<T>): T;
9
10
  export declare function createStoreSubscriber<TState>(store: SubscribableStore<TState>): () => void;
11
+ /**
12
+ * Returns a function that subscribes the current reactive consumer to an app
13
+ * hotkeys store, so it re-runs when app hotkeys or custom hotkeys change.
14
+ */
15
+ export declare function createAppHotkeysSubscriber(store: AppHotkeysStore | null): () => void;
10
16
  export {};
@@ -10,3 +10,11 @@ export function createStoreSubscriber(store) {
10
10
  : () => subscription.unsubscribe();
11
11
  });
12
12
  }
13
+ const noop = () => { };
14
+ /**
15
+ * Returns a function that subscribes the current reactive consumer to an app
16
+ * hotkeys store, so it re-runs when app hotkeys or custom hotkeys change.
17
+ */
18
+ export function createAppHotkeysSubscriber(store) {
19
+ return store ? createStoreSubscriber(store.store) : noop;
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/svelte-hotkeys",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Svelte adapter for TanStack Hotkeys",
5
5
  "author": "Kunal Rao",
6
6
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "dist"
40
40
  ],
41
41
  "dependencies": {
42
- "@tanstack/hotkeys": "0.11.0"
42
+ "@tanstack/hotkeys": "0.12.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@sveltejs/package": "^3.0.0",
@@ -1,65 +0,0 @@
1
- import type { HotkeyCallback, HotkeySequence, SequenceOptions } from '@tanstack/hotkeys';
2
- import type { MaybeGetter } from './internal.svelte';
3
- import type { Attachment } from 'svelte/attachments';
4
- export interface CreateHotkeySequenceOptions extends Omit<SequenceOptions, 'target'> {
5
- target?: Document | Window;
6
- }
7
- /**
8
- * Register a global keyboard shortcut sequence for the current component.
9
- *
10
- * Each step may include modifiers. You can chain the same modifier across
11
- * steps (e.g. `Shift+R` then `Shift+T`). Modifier-only keydown events (Shift,
12
- * Control, Alt, or Meta pressed alone) are ignored while matching—they do not
13
- * advance the sequence or reset progress.
14
- *
15
- * @example
16
- * ```svelte
17
- * <script lang="ts">
18
- * import { createHotkeySequence } from '@tanstack/svelte-hotkeys'
19
- *
20
- * // Scroll to top when 'G G' is pressed
21
- * createHotkeySequence(['G', 'G'], () => {
22
- * scrollToTop()
23
- * })
24
- *
25
- * // Delete line when 'D D' is pressed
26
- * createHotkeySequence(['D', 'D'], () => {
27
- * deleteLine()
28
- * })
29
- *
30
- * // Delete inner word when 'D I W' is pressed
31
- * createHotkeySequence(['D', 'I', 'W'], () => {
32
- * deleteInnerWord()
33
- * }, { timeout: 500 })
34
- *
35
- * // Same modifier on consecutive steps (bare Shift between chords is ignored)
36
- * createHotkeySequence(['Shift+R', 'Shift+T'], () => {
37
- * nextAction()
38
- * })
39
- * </script>
40
- *
41
- * <div>
42
- * ....
43
- * </div>
44
- * ```
45
- */
46
- export declare function createHotkeySequence(sequence: MaybeGetter<HotkeySequence>, callback: HotkeyCallback, options?: MaybeGetter<CreateHotkeySequenceOptions>): void;
47
- /**
48
- * Create an attachment for element-scoped keyboard sequences.
49
- *
50
- * @example
51
- * ```svelte
52
- * <script lang="ts">
53
- * import { createHotkeySequenceAttachment } from '@tanstack/svelte-hotkeys'
54
- *
55
- * const vimKeys = createHotkeySequenceAttachment(['G', 'G'], () => {
56
- * scrollToTop()
57
- * })
58
- * </script>
59
- *
60
- * <div tabindex="0" {@attach vimKeys}>
61
- * Focus here and press g then g
62
- * </div>
63
- * ```
64
- */
65
- export declare function createHotkeySequenceAttachment(sequence: MaybeGetter<HotkeySequence>, callback: HotkeyCallback, options?: MaybeGetter<CreateHotkeySequenceOptions>): Attachment<HTMLElement>;