@tanstack/vue-hotkeys 0.14.5 → 0.15.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.
package/README.md CHANGED
@@ -51,7 +51,7 @@
51
51
  # TanStack Hotkeys
52
52
 
53
53
  > [!NOTE]
54
- > TanStack Hotkeys is alpha. We are actively developing the library and are open to feedback and contributions.
54
+ > TanStack Hotkeys is in beta. We are actively developing the library and are open to feedback and contributions.
55
55
 
56
56
  Type-safe keyboard shortcuts for the web. Template-string bindings, parsed objects, a cross-platform `Mod` key, a singleton Hotkey Manager, and utilities for cheatsheet UIs—built to stay SSR-friendly.
57
57
 
@@ -1,12 +1,17 @@
1
1
  import { HotkeysProviderOptions } from "./HotkeysProviderContext.js";
2
2
  import { AppHotkeys, CustomHotkeys } from "@tanstack/hotkeys";
3
3
  import { PropType } from "vue";
4
+ import { HotkeysProviderScopeProps } from "@tanstack/hotkeys/adapter";
4
5
  //#region src/HotkeysProvider.d.ts
5
6
  /**
6
7
  * Vue component that provides default options, app hotkeys, and the user's
7
8
  * custom hotkeys. `customHotkeys` is read once; listen to
8
9
  * `custom-hotkeys-change` to save changes.
9
10
  *
11
+ * Nest providers to create hotkey scopes. A nested provider inherits app
12
+ * hotkeys and merges default options. With `scope`, its hotkeys fire only
13
+ * while it is mounted and enabled; with `exclusive`, only its hotkeys fire.
14
+ *
10
15
  * @example
11
16
  * ```vue
12
17
  * <template>
@@ -19,6 +24,13 @@ import { PropType } from "vue";
19
24
  * </HotkeysProvider>
20
25
  * </template>
21
26
  * ```
27
+ *
28
+ * @example
29
+ * ```vue
30
+ * <HotkeysProvider scope="edit-dialog" :exclusive="{ allow: ['global'] }">
31
+ * <DialogBody />
32
+ * </HotkeysProvider>
33
+ * ```
22
34
  */
23
35
  export declare const HotkeysProvider: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
24
36
  defaultOptions: {
@@ -33,6 +45,21 @@ export declare const HotkeysProvider: import("vue").DefineComponent<import("vue"
33
45
  type: PropType<CustomHotkeys | null>;
34
46
  default: undefined;
35
47
  };
48
+ /** See `HotkeysProviderScopeProps['scope']`. */
49
+ scope: {
50
+ type: StringConstructor;
51
+ default: undefined;
52
+ };
53
+ /** See `HotkeysProviderScopeProps['exclusive']`. */
54
+ exclusive: {
55
+ type: PropType<HotkeysProviderScopeProps["exclusive"]>;
56
+ default: boolean;
57
+ };
58
+ /** See `HotkeysProviderScopeProps['enabled']`. */
59
+ enabled: {
60
+ type: BooleanConstructor;
61
+ default: boolean;
62
+ };
36
63
  }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
37
64
  [key: string]: any;
38
65
  }>[] | undefined, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
@@ -50,11 +77,31 @@ export declare const HotkeysProvider: import("vue").DefineComponent<import("vue"
50
77
  type: PropType<CustomHotkeys | null>;
51
78
  default: undefined;
52
79
  };
80
+ /** See `HotkeysProviderScopeProps['scope']`. */
81
+ scope: {
82
+ type: StringConstructor;
83
+ default: undefined;
84
+ };
85
+ /** See `HotkeysProviderScopeProps['exclusive']`. */
86
+ exclusive: {
87
+ type: PropType<HotkeysProviderScopeProps["exclusive"]>;
88
+ default: boolean;
89
+ };
90
+ /** See `HotkeysProviderScopeProps['enabled']`. */
91
+ enabled: {
92
+ type: BooleanConstructor;
93
+ default: boolean;
94
+ };
53
95
  }>> & Readonly<{
54
96
  onCustomHotkeysChange?: ((_customHotkeys: CustomHotkeys<Readonly<Record<string, import("@tanstack/hotkeys").AppHotkey<string, import("@tanstack/hotkeys").HotkeyChord | import("@tanstack/hotkeys").HotkeySequence | null>>>>) => any) | undefined;
55
97
  }>, {
98
+ exclusive: boolean | {
99
+ allow: ReadonlyArray<string>;
100
+ } | undefined;
56
101
  defaultOptions: HotkeysProviderOptions;
57
102
  appHotkeys: Readonly<Record<string, import("@tanstack/hotkeys").AppHotkey<string, import("@tanstack/hotkeys").HotkeyChord | import("@tanstack/hotkeys").HotkeySequence | null>>>;
58
103
  customHotkeys: CustomHotkeys<Readonly<Record<string, import("@tanstack/hotkeys").AppHotkey<string, import("@tanstack/hotkeys").HotkeyChord | import("@tanstack/hotkeys").HotkeySequence | null>>>> | null;
104
+ scope: string;
105
+ enabled: boolean;
59
106
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
60
107
  //#endregion
@@ -7,6 +7,10 @@ import { defineComponent } from "vue";
7
7
  * custom hotkeys. `customHotkeys` is read once; listen to
8
8
  * `custom-hotkeys-change` to save changes.
9
9
  *
10
+ * Nest providers to create hotkey scopes. A nested provider inherits app
11
+ * hotkeys and merges default options. With `scope`, its hotkeys fire only
12
+ * while it is mounted and enabled; with `exclusive`, only its hotkeys fire.
13
+ *
10
14
  * @example
11
15
  * ```vue
12
16
  * <template>
@@ -19,6 +23,13 @@ import { defineComponent } from "vue";
19
23
  * </HotkeysProvider>
20
24
  * </template>
21
25
  * ```
26
+ *
27
+ * @example
28
+ * ```vue
29
+ * <HotkeysProvider scope="edit-dialog" :exclusive="{ allow: ['global'] }">
30
+ * <DialogBody />
31
+ * </HotkeysProvider>
32
+ * ```
22
33
  */
23
34
  const HotkeysProvider = defineComponent({
24
35
  name: "HotkeysProvider",
@@ -34,6 +45,21 @@ const HotkeysProvider = defineComponent({
34
45
  customHotkeys: {
35
46
  type: Object,
36
47
  default: void 0
48
+ },
49
+ /** See `HotkeysProviderScopeProps['scope']`. */
50
+ scope: {
51
+ type: String,
52
+ default: void 0
53
+ },
54
+ /** See `HotkeysProviderScopeProps['exclusive']`. */
55
+ exclusive: {
56
+ type: [Boolean, Object],
57
+ default: false
58
+ },
59
+ /** See `HotkeysProviderScopeProps['enabled']`. */
60
+ enabled: {
61
+ type: Boolean,
62
+ default: true
37
63
  }
38
64
  },
39
65
  emits: { customHotkeysChange: (_customHotkeys) => true },
@@ -42,6 +68,9 @@ const HotkeysProvider = defineComponent({
42
68
  defaultOptions: () => props.defaultOptions,
43
69
  appHotkeys: () => props.appHotkeys,
44
70
  customHotkeys: props.customHotkeys,
71
+ scope: () => props.scope,
72
+ exclusive: () => props.exclusive,
73
+ enabled: () => props.enabled,
45
74
  onCustomHotkeysChange: (custom) => emit("customHotkeysChange", custom)
46
75
  });
47
76
  return () => slots.default?.();
@@ -1,6 +1,7 @@
1
1
  import { UseHotkeyCommonOptions } from "./useHotkey.js";
2
2
  import { AppHotkeys, AppHotkeysStore, CustomHotkeys, HotkeyChordRecorderOptions, HotkeySequenceRecorderOptions } from "@tanstack/hotkeys";
3
3
  import { MaybeRefOrGetter } from "vue";
4
+ import { HotkeysProviderScopeProps } from "@tanstack/hotkeys/adapter";
4
5
  //#region src/HotkeysProviderContext.d.ts
5
6
  export interface HotkeysProviderOptions {
6
7
  /**
@@ -13,11 +14,21 @@ export interface HotkeysProviderOptions {
13
14
  }
14
15
  interface HotkeysContextValue {
15
16
  readonly appHotkeysStore: AppHotkeysStore | null;
17
+ /** Merged with every ancestor's defaults, including `hotkey.scope`. */
16
18
  readonly defaultOptions: HotkeysProviderOptions;
19
+ /** Whether this context and every ancestor are enabled. */
20
+ readonly enabled: boolean;
17
21
  }
18
22
  /** Options for `provideHotkeysContext`. */
19
23
  export interface ProvideHotkeysContextOptions {
24
+ /** Merged with the parent context's defaults. */
20
25
  defaultOptions?: MaybeRefOrGetter<HotkeysProviderOptions | undefined>;
26
+ /** See `HotkeysProviderScopeProps['scope']`. */
27
+ scope?: MaybeRefOrGetter<HotkeysProviderScopeProps['scope']>;
28
+ /** See `HotkeysProviderScopeProps['exclusive']`. */
29
+ exclusive?: MaybeRefOrGetter<HotkeysProviderScopeProps['exclusive']>;
30
+ /** See `HotkeysProviderScopeProps['enabled']`. */
31
+ enabled?: MaybeRefOrGetter<HotkeysProviderScopeProps['enabled']>;
21
32
  /**
22
33
  * Every app hotkey, from `defineAppHotkeys`. Read when the context is
23
34
  * provided; later changes update the declarations.
@@ -33,8 +44,13 @@ export interface ProvideHotkeysContextOptions {
33
44
  }
34
45
  /**
35
46
  * Provides default options, app hotkeys, and the user's custom hotkeys to
36
- * descendants. `HotkeysProvider` calls this; call it directly in a root
37
- * component's setup instead of rendering the provider.
47
+ * descendants. `HotkeysProvider` calls this; call it directly in a component's
48
+ * setup instead of rendering the provider.
49
+ *
50
+ * Nest contexts to create hotkey scopes. A nested context inherits app
51
+ * hotkeys and merges default options. With `scope`, its hotkeys fire only
52
+ * while the component is mounted and enabled; with `exclusive`, only its
53
+ * hotkeys fire.
38
54
  *
39
55
  * @example
40
56
  * ```ts
@@ -1,13 +1,19 @@
1
1
  import { AppHotkeysStore, publishAppHotkeysStore } from "@tanstack/hotkeys";
2
- import { inject, onScopeDispose, provide, toValue, watch } from "vue";
2
+ import { computed, inject, onMounted, onScopeDispose, provide, toValue, watch } from "vue";
3
+ import { activateHotkeysProviderScope, getHotkeysProviderScopeKey, mergeHotkeysProviderDefaults } from "@tanstack/hotkeys/adapter";
3
4
 
4
5
  //#region src/HotkeysProviderContext.ts
5
6
  const HotkeysContext = Symbol("HotkeysContext");
6
7
  const DEFAULT_OPTIONS = {};
7
8
  /**
8
9
  * Provides default options, app hotkeys, and the user's custom hotkeys to
9
- * descendants. `HotkeysProvider` calls this; call it directly in a root
10
- * component's setup instead of rendering the provider.
10
+ * descendants. `HotkeysProvider` calls this; call it directly in a component's
11
+ * setup instead of rendering the provider.
12
+ *
13
+ * Nest contexts to create hotkey scopes. A nested context inherits app
14
+ * hotkeys and merges default options. With `scope`, its hotkeys fire only
15
+ * while the component is mounted and enabled; with `exclusive`, only its
16
+ * hotkeys fire.
11
17
  *
12
18
  * @example
13
19
  * ```ts
@@ -20,6 +26,7 @@ const DEFAULT_OPTIONS = {};
20
26
  * ```
21
27
  */
22
28
  function provideHotkeysContext(options = {}) {
29
+ const parent = inject(HotkeysContext, null);
23
30
  const appHotkeys = toValue(options.appHotkeys);
24
31
  const store = appHotkeys ? new AppHotkeysStore(appHotkeys, {
25
32
  customHotkeys: options.customHotkeys,
@@ -31,12 +38,29 @@ function provideHotkeysContext(options = {}) {
31
38
  });
32
39
  if (typeof document !== "undefined") onScopeDispose(publishAppHotkeysStore(store));
33
40
  }
34
- provide(HotkeysContext, {
35
- appHotkeysStore: store,
41
+ const active = computed(() => (parent?.enabled ?? true) && toValue(options.enabled) !== false);
42
+ const defaultOptions = computed(() => mergeHotkeysProviderDefaults(parent?.defaultOptions, toValue(options.defaultOptions), toValue(options.scope)));
43
+ const scopeKey = computed(() => getHotkeysProviderScopeKey({
44
+ scope: toValue(options.scope),
45
+ exclusive: toValue(options.exclusive),
46
+ active: active.value,
47
+ parent: parent?.defaultOptions.hotkey?.scope
48
+ }));
49
+ onMounted(() => {
50
+ watch(scopeKey, (key, _, onCleanup) => {
51
+ if (key) onCleanup(activateHotkeysProviderScope(key));
52
+ }, { immediate: true });
53
+ });
54
+ const contextValue = {
55
+ appHotkeysStore: store ?? parent?.appHotkeysStore ?? null,
36
56
  get defaultOptions() {
37
- return toValue(options.defaultOptions) ?? DEFAULT_OPTIONS;
57
+ return defaultOptions.value;
58
+ },
59
+ get enabled() {
60
+ return active.value;
38
61
  }
39
- });
62
+ };
63
+ provide(HotkeysContext, contextValue);
40
64
  }
41
65
  function useHotkeysContext() {
42
66
  return inject(HotkeysContext, null);
@@ -7,8 +7,8 @@ import { ComputedRef } from "vue";
7
7
  *
8
8
  * @example
9
9
  * ```ts
10
- * const hotkeys = useAppHotkeys()
11
- * useHotkey(() => hotkeys.value['doc.save'], () => save())
10
+ * const appHotkeys = useAppHotkeys()
11
+ * useHotkey(() => appHotkeys.value['doc.save'], () => save())
12
12
  * ```
13
13
  */
14
14
  export declare function useAppHotkeys(): ComputedRef<RegisteredAppHotkeys>;
@@ -17,8 +17,8 @@ function useRequiredStore(name) {
17
17
  *
18
18
  * @example
19
19
  * ```ts
20
- * const hotkeys = useAppHotkeys()
21
- * useHotkey(() => hotkeys.value['doc.save'], () => save())
20
+ * const appHotkeys = useAppHotkeys()
21
+ * useHotkey(() => appHotkeys.value['doc.save'], () => save())
22
22
  * ```
23
23
  */
24
24
  function useAppHotkeys() {
@@ -1,4 +1,4 @@
1
- import { AppHotkey, HotkeyCallback, RegisterableHotkey, Target } from "@tanstack/hotkeys";
1
+ import { AppHotkey, HotkeyCallback, HotkeyCallbackContextFor, RegisterableHotkey, Target } from "@tanstack/hotkeys";
2
2
  import { MaybeRefOrGetter } from "vue";
3
3
  import { AdapterAppHotkeyOptions, AdapterChordOptions, AdapterCommonOptions, AdapterHotkeyOptions, AdapterOptionsFor, AdapterSequenceOptions } from "@tanstack/hotkeys/adapter";
4
4
  //#region src/useHotkey.d.ts
@@ -42,5 +42,5 @@ export type UseAppHotkeyOptions<T extends AppHotkey = AppHotkey> = WithReactiveE
42
42
  * ```
43
43
  */
44
44
  export declare function useHotkey<T extends AppHotkey>(hotkey: MaybeRefOrGetter<T>, callback: HotkeyCallback, options?: MaybeRefOrGetter<UseAppHotkeyOptions<T>>): void;
45
- export declare function useHotkey<T extends RegisterableHotkey>(hotkey: MaybeRefOrGetter<T>, callback: HotkeyCallback, options?: MaybeRefOrGetter<UseHotkeyOptionsFor<T>>): void;
45
+ export declare function useHotkey<const T extends RegisterableHotkey>(hotkey: MaybeRefOrGetter<T>, callback: HotkeyCallback<HotkeyCallbackContextFor<T>>, options?: MaybeRefOrGetter<UseHotkeyOptionsFor<T>>): void;
46
46
  //#endregion
@@ -28,7 +28,7 @@ export interface VueHotkeyRecorder<THotkey extends Hotkey = Hotkey> {
28
28
  * @example
29
29
  * ```ts
30
30
  * const recorder = useHotkeyRecorder({ onRecord: (hotkey) => (shortcut.value = hotkey) })
31
- * const sequenceRecorder = useHotkeyRecorder({ maxSteps: 3, onRecord: save })
31
+ * const sequenceRecorder = useHotkeyRecorder({ maxSteps: Infinity, onRecord: save })
32
32
  * ```
33
33
  */
34
34
  export declare function useHotkeyRecorder(options: HotkeyChordRecorderOptions): VueHotkeyRecorder<HotkeyChord>;
@@ -1,5 +1,5 @@
1
1
  import { UseAppHotkeyOptions, UseHotkeyChordOptions, UseHotkeyCommonOptions, UseHotkeyOptions, UseHotkeySequenceOptions } from "./useHotkey.js";
2
- import { AppHotkey, HotkeyCallback, HotkeySequence, RegisterableHotkey, RegisterableHotkeyChord } from "@tanstack/hotkeys";
2
+ import { AppHotkey, HotkeyCallback, RegisterableHotkey, RegisterableHotkeyChord, RegisterableHotkeySequence } from "@tanstack/hotkeys";
3
3
  import { MaybeRefOrGetter } from "vue";
4
4
  //#region src/useHotkeys.d.ts
5
5
  /**
@@ -8,15 +8,15 @@ import { MaybeRefOrGetter } from "vue";
8
8
  * kind accept only shared options.
9
9
  */
10
10
  export type UseHotkeyDefinition = {
11
- /** A chord string such as `'Mod+S'`, or a RawHotkey object */
11
+ /** A chord string such as `'Mod+S'`, or a chord object */
12
12
  hotkey: MaybeRefOrGetter<RegisterableHotkeyChord>;
13
13
  /** The function to call when the hotkey is pressed */
14
14
  callback: HotkeyCallback;
15
15
  /** Per-hotkey options (merged on top of commonOptions) */
16
16
  options?: MaybeRefOrGetter<UseHotkeyChordOptions>;
17
17
  } | {
18
- /** A sequence such as `['G', 'G']` */
19
- hotkey: MaybeRefOrGetter<HotkeySequence>;
18
+ /** A sequence such as `['G', 'G']`, with each step a string or an object */
19
+ hotkey: MaybeRefOrGetter<RegisterableHotkeySequence>;
20
20
  callback: HotkeyCallback;
21
21
  options?: MaybeRefOrGetter<UseHotkeySequenceOptions>;
22
22
  } | {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/vue-hotkeys",
3
- "version": "0.14.5",
3
+ "version": "0.15.1",
4
4
  "description": "Vue adapter for TanStack Hotkeys",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -36,7 +36,7 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@tanstack/hotkeys": "0.15.1",
39
+ "@tanstack/hotkeys": "0.16.1",
40
40
  "@tanstack/vue-store": "^0.11.2"
41
41
  },
42
42
  "devDependencies": {