@tanstack/vue-hotkeys 0.19.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/HotkeysProvider.d.ts +2 -1
- package/dist/HotkeysProvider.js +2 -1
- package/dist/HotkeysProviderContext.d.ts +9 -3
- package/dist/HotkeysProviderContext.js +5 -3
- package/dist/_useLive.js +19 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/useFormatForDisplay.d.ts +24 -0
- package/dist/useFormatForDisplay.js +34 -0
- package/dist/useHotkeyRecorder.js +11 -2
- package/dist/useHotkeys.js +3 -0
- package/package.json +2 -2
- package/skills/vue-hotkeys/SKILL.md +2 -0
|
@@ -11,7 +11,8 @@ import { HotkeysProviderScopeProps } from "@tanstack/hotkeys/adapter";
|
|
|
11
11
|
*
|
|
12
12
|
* Nest providers to create hotkey scopes. A nested provider inherits app
|
|
13
13
|
* hotkeys and merges default options. With `scope`, its hotkeys fire only
|
|
14
|
-
* while it is mounted
|
|
14
|
+
* while it is mounted, enabled, and not hidden by `<KeepAlive>`; with
|
|
15
|
+
* `exclusive`, only its hotkeys fire.
|
|
15
16
|
*
|
|
16
17
|
* @example
|
|
17
18
|
* ```vue
|
package/dist/HotkeysProvider.js
CHANGED
|
@@ -10,7 +10,8 @@ import { defineComponent } from "vue";
|
|
|
10
10
|
*
|
|
11
11
|
* Nest providers to create hotkey scopes. A nested provider inherits app
|
|
12
12
|
* hotkeys and merges default options. With `scope`, its hotkeys fire only
|
|
13
|
-
* while it is mounted
|
|
13
|
+
* while it is mounted, enabled, and not hidden by `<KeepAlive>`; with
|
|
14
|
+
* `exclusive`, only its hotkeys fire.
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* ```vue
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { UseHotkeyCommonOptions } from "./useHotkey.js";
|
|
2
|
-
import { AppHotkeys, AppHotkeysStore, CustomHotkeys, HotkeyChordRecorderOptions, HotkeySequenceRecorderOptions } from "@tanstack/hotkeys";
|
|
2
|
+
import { AppHotkeys, AppHotkeysStore, CustomHotkeys, HotkeyChordRecorderOptions, HotkeyPlatform, HotkeySequenceRecorderOptions } from "@tanstack/hotkeys";
|
|
3
3
|
import { MaybeRefOrGetter } from "vue";
|
|
4
4
|
import { HotkeysProviderScopeProps } from "@tanstack/hotkeys/adapter";
|
|
5
5
|
//#region src/HotkeysProviderContext.d.ts
|
|
6
6
|
export interface HotkeysProviderOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The user's platform, for labels from `useFormatForDisplay`, hotkeys, and
|
|
9
|
+
* recorders. On a server, set it from the request with
|
|
10
|
+
* `detectPlatform(userAgent)`.
|
|
11
|
+
*/
|
|
12
|
+
platform?: HotkeyPlatform;
|
|
7
13
|
/**
|
|
8
14
|
* Defaults for every hotkey registered by `useHotkey` and `useHotkeys`.
|
|
9
15
|
* `requireReset` applies to chords and `timeout` applies to sequences.
|
|
@@ -51,8 +57,8 @@ export interface ProvideHotkeysContextOptions {
|
|
|
51
57
|
*
|
|
52
58
|
* Nest contexts to create hotkey scopes. A nested context inherits app
|
|
53
59
|
* hotkeys and merges default options. With `scope`, its hotkeys fire only
|
|
54
|
-
* while the component is mounted and
|
|
55
|
-
* hotkeys fire.
|
|
60
|
+
* while the component is mounted, enabled, and not hidden by `<KeepAlive>`;
|
|
61
|
+
* with `exclusive`, only its hotkeys fire.
|
|
56
62
|
*
|
|
57
63
|
* @example
|
|
58
64
|
* ```ts
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useLive } from "./_useLive.js";
|
|
1
2
|
import { publishAppHotkeysStore } from "@tanstack/hotkeys";
|
|
2
3
|
import { computed, hasInjectionContext, inject, onMounted, onScopeDispose, provide, toValue, watch } from "vue";
|
|
3
4
|
import { activateHotkeysProviderScope, createAppHotkeysStore, getHotkeysProviderScopeKey, mergeHotkeysProviderDefaults } from "@tanstack/hotkeys/adapter";
|
|
@@ -12,8 +13,8 @@ const DEFAULT_OPTIONS = {};
|
|
|
12
13
|
*
|
|
13
14
|
* Nest contexts to create hotkey scopes. A nested context inherits app
|
|
14
15
|
* hotkeys and merges default options. With `scope`, its hotkeys fire only
|
|
15
|
-
* while the component is mounted and
|
|
16
|
-
* hotkeys fire.
|
|
16
|
+
* while the component is mounted, enabled, and not hidden by `<KeepAlive>`;
|
|
17
|
+
* with `exclusive`, only its hotkeys fire.
|
|
17
18
|
*
|
|
18
19
|
* @example
|
|
19
20
|
* ```ts
|
|
@@ -39,7 +40,8 @@ function provideHotkeysContext(options = {}) {
|
|
|
39
40
|
watch(() => toValue(options.customHotkeys), (customHotkeys) => store.setOptions({ customHotkeys }), { deep: true });
|
|
40
41
|
if (typeof document !== "undefined") onScopeDispose(publishAppHotkeysStore(store));
|
|
41
42
|
}
|
|
42
|
-
const
|
|
43
|
+
const live = useLive();
|
|
44
|
+
const active = computed(() => live.value && (parent?.enabled ?? true) && toValue(options.enabled) !== false);
|
|
43
45
|
const defaultOptions = computed(() => mergeHotkeysProviderDefaults(parent?.defaultOptions, toValue(options.defaultOptions), toValue(options.scope)));
|
|
44
46
|
const scopeKey = computed(() => getHotkeysProviderScopeKey({
|
|
45
47
|
scope: toValue(options.scope),
|
package/dist/_useLive.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getCurrentInstance, onActivated, onDeactivated, ref } from "vue";
|
|
2
|
+
|
|
3
|
+
//#region src/_useLive.ts
|
|
4
|
+
/**
|
|
5
|
+
* Whether the component is shown. A component in a page cached by
|
|
6
|
+
* `<KeepAlive>` is not live while the page is hidden. Always true outside a
|
|
7
|
+
* component, where the hooks would warn.
|
|
8
|
+
*/
|
|
9
|
+
function useLive() {
|
|
10
|
+
const live = ref(true);
|
|
11
|
+
if (getCurrentInstance()) {
|
|
12
|
+
onActivated(() => live.value = true);
|
|
13
|
+
onDeactivated(() => live.value = false);
|
|
14
|
+
}
|
|
15
|
+
return live;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { useLive };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { VueHotkeyRecorder, useHotkeyRecorder } from "./useHotkeyRecorder.js";
|
|
|
9
9
|
import { useHotkeyRegistrations } from "./useHotkeyRegistrations.js";
|
|
10
10
|
import { useHotkeyScopesState } from "./useHotkeyScopesState.js";
|
|
11
11
|
import { useHotkeyHint } from "./useHotkeyHint.js";
|
|
12
|
+
import { useFormatForDisplay } from "./useFormatForDisplay.js";
|
|
12
13
|
import { UseCustomHotkeysResult, useAppHotkeyList, useAppHotkeys, useCustomHotkeys } from "./useAppHotkeys.js";
|
|
13
14
|
export * from "@tanstack/hotkeys";
|
|
14
|
-
export { HotkeysProvider, HotkeysProviderOptions, ProvideHotkeysContextOptions, UseAppHotkeyOptions, UseCustomHotkeysResult, UseHotkeyChordOptions, UseHotkeyCommonOptions, UseHotkeyDefinition, UseHotkeyOptions, UseHotkeyOptionsFor, UseHotkeySequenceOptions, UseHotkeyTarget, VueHotkeyRecorder, provideHotkeysContext, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
|
|
15
|
+
export { HotkeysProvider, HotkeysProviderOptions, ProvideHotkeysContextOptions, UseAppHotkeyOptions, UseCustomHotkeysResult, UseHotkeyChordOptions, UseHotkeyCommonOptions, UseHotkeyDefinition, UseHotkeyOptions, UseHotkeyOptionsFor, UseHotkeySequenceOptions, UseHotkeyTarget, VueHotkeyRecorder, provideHotkeysContext, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useFormatForDisplay, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,9 @@ import { useHotkeyRecorder } from "./useHotkeyRecorder.js";
|
|
|
9
9
|
import { useHotkeyRegistrations } from "./useHotkeyRegistrations.js";
|
|
10
10
|
import { useHotkeyScopesState } from "./useHotkeyScopesState.js";
|
|
11
11
|
import { useHotkeyHint } from "./useHotkeyHint.js";
|
|
12
|
+
import { useFormatForDisplay } from "./useFormatForDisplay.js";
|
|
12
13
|
import { useAppHotkeyList, useAppHotkeys, useCustomHotkeys } from "./useAppHotkeys.js";
|
|
13
14
|
|
|
14
15
|
export * from "@tanstack/hotkeys"
|
|
15
16
|
|
|
16
|
-
export { HotkeysProvider, provideHotkeysContext, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
|
|
17
|
+
export { HotkeysProvider, provideHotkeysContext, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useFormatForDisplay, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { formatForDisplay } from "@tanstack/hotkeys";
|
|
2
|
+
//#region src/useFormatForDisplay.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Returns `formatForDisplay` with the provider's `platform` as the default,
|
|
5
|
+
* so labels match the user's platform. Call in `setup`; the returned function
|
|
6
|
+
* works anywhere, and templates update when the provider's platform changes.
|
|
7
|
+
* An explicit `platform` option wins.
|
|
8
|
+
*
|
|
9
|
+
* Server-rendered apps should set the provider's `defaultOptions.platform`
|
|
10
|
+
* from the request user agent with `detectPlatform(userAgent)`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```vue
|
|
14
|
+
* <script setup lang="ts">
|
|
15
|
+
* const format = useFormatForDisplay()
|
|
16
|
+
* </script>
|
|
17
|
+
*
|
|
18
|
+
* <template>
|
|
19
|
+
* <kbd>{{ format('Mod+S') }}</kbd>
|
|
20
|
+
* </template>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function useFormatForDisplay(): typeof formatForDisplay;
|
|
24
|
+
//#endregion
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useDefaultHotkeysOptionsSource } from "./defaultOptions.js";
|
|
2
|
+
import { formatForDisplay } from "@tanstack/hotkeys";
|
|
3
|
+
|
|
4
|
+
//#region src/useFormatForDisplay.ts
|
|
5
|
+
/**
|
|
6
|
+
* Returns `formatForDisplay` with the provider's `platform` as the default,
|
|
7
|
+
* so labels match the user's platform. Call in `setup`; the returned function
|
|
8
|
+
* works anywhere, and templates update when the provider's platform changes.
|
|
9
|
+
* An explicit `platform` option wins.
|
|
10
|
+
*
|
|
11
|
+
* Server-rendered apps should set the provider's `defaultOptions.platform`
|
|
12
|
+
* from the request user agent with `detectPlatform(userAgent)`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```vue
|
|
16
|
+
* <script setup lang="ts">
|
|
17
|
+
* const format = useFormatForDisplay()
|
|
18
|
+
* <\/script>
|
|
19
|
+
*
|
|
20
|
+
* <template>
|
|
21
|
+
* <kbd>{{ format('Mod+S') }}</kbd>
|
|
22
|
+
* </template>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
function useFormatForDisplay() {
|
|
26
|
+
const defaultOptions = useDefaultHotkeysOptionsSource();
|
|
27
|
+
return ((hotkey, options) => formatForDisplay(hotkey, {
|
|
28
|
+
...options,
|
|
29
|
+
platform: options?.platform ?? defaultOptions().platform
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { useFormatForDisplay };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { useLive } from "./_useLive.js";
|
|
1
2
|
import { useStoreSelector } from "./useStoreSelector.js";
|
|
2
3
|
import { useDefaultHotkeysOptionsSource } from "./defaultOptions.js";
|
|
3
4
|
import { HotkeyRecorder } from "@tanstack/hotkeys";
|
|
4
|
-
import { onScopeDispose, toValue, watch } from "vue";
|
|
5
|
+
import { getCurrentInstance, onScopeDispose, toValue, watch } from "vue";
|
|
5
6
|
import { withDefaults } from "@tanstack/hotkeys/adapter";
|
|
6
7
|
|
|
7
8
|
//#region src/useHotkeyRecorder.ts
|
|
@@ -13,6 +14,12 @@ function useHotkeyRecorder(options) {
|
|
|
13
14
|
const steps = useStoreSelector(recorder.store, (state) => state.steps);
|
|
14
15
|
const recordedHotkey = useStoreSelector(recorder.store, (state) => state.recordedHotkey);
|
|
15
16
|
const stopWatcher = watch(resolve, (resolved) => recorder.setOptions(resolved));
|
|
17
|
+
const instance = getCurrentInstance();
|
|
18
|
+
const hidden = () => {
|
|
19
|
+
for (let i = instance; i; i = i.parent) if (i.isDeactivated) return true;
|
|
20
|
+
return false;
|
|
21
|
+
};
|
|
22
|
+
watch(useLive(), (live) => live || recorder.store.state.isRecording && recorder.stop());
|
|
16
23
|
onScopeDispose(() => {
|
|
17
24
|
stopWatcher();
|
|
18
25
|
recorder.destroy();
|
|
@@ -21,7 +28,9 @@ function useHotkeyRecorder(options) {
|
|
|
21
28
|
isRecording,
|
|
22
29
|
steps,
|
|
23
30
|
recordedHotkey,
|
|
24
|
-
startRecording: () =>
|
|
31
|
+
startRecording: () => {
|
|
32
|
+
if (!hidden()) recorder.start();
|
|
33
|
+
},
|
|
25
34
|
stopRecording: () => recorder.stop(),
|
|
26
35
|
cancelRecording: () => recorder.cancel(),
|
|
27
36
|
commitRecording: () => recorder.commit()
|
package/dist/useHotkeys.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useLive } from "./_useLive.js";
|
|
1
2
|
import { useAppHotkeysStoreSource, useDefaultHotkeysOptionsSource } from "./defaultOptions.js";
|
|
2
3
|
import { onScopeDispose, toValue, watch } from "vue";
|
|
3
4
|
import { createHotkeyBindings, prepareHotkeyDefinitions } from "@tanstack/hotkeys/adapter";
|
|
@@ -34,7 +35,9 @@ function useHotkeys(hotkeys, commonOptions = {}) {
|
|
|
34
35
|
const defaultOptions = useDefaultHotkeysOptionsSource();
|
|
35
36
|
const appHotkeys = useAppHotkeysStoreSource();
|
|
36
37
|
const bindings = createHotkeyBindings();
|
|
38
|
+
const live = useLive();
|
|
37
39
|
const stopWatcher = watch(() => {
|
|
40
|
+
if (!live.value) return [];
|
|
38
41
|
appHotkeys.state.value;
|
|
39
42
|
const definitions = toValue(hotkeys).map((definition) => ({
|
|
40
43
|
hotkey: toValue(definition.hotkey),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/vue-hotkeys",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Vue adapter for TanStack Hotkeys",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"skills"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@tanstack/hotkeys": "0.
|
|
41
|
+
"@tanstack/hotkeys": "0.23.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@vitejs/plugin-vue": "^6.0.9",
|
|
@@ -60,6 +60,7 @@ useHotkey('Escape', () => closePanel(), { target: panel })
|
|
|
60
60
|
| `provideHotkeysContext(options)` | Provide the same options from a component's setup instead of rendering `HotkeysProvider`; they apply to its children. |
|
|
61
61
|
| `useHotkeysContext()` | Read the nearest provider's merged defaults and enabled state, or `null` outside a provider. |
|
|
62
62
|
| `useDefaultHotkeysOptions()` | Read the default options merged from every provider above. |
|
|
63
|
+
| `useFormatForDisplay()` | Get `formatForDisplay` with the provider's `platform` filled in, for labels in server-rendered apps. Call it in `setup`. |
|
|
63
64
|
| `useAppHotkeys()` | Get a computed ref of the declared app hotkeys with the user's custom hotkeys applied. |
|
|
64
65
|
| `useAppHotkeyList()` | Get a computed ref listing every app hotkey with its status, for a cheat sheet or settings screen. |
|
|
65
66
|
| `useCustomHotkeys()` | Read, change, and reset the user's custom hotkeys, and check a new one for conflicts. |
|
|
@@ -82,6 +83,7 @@ No provider is required. Call the composables synchronously in setup.
|
|
|
82
83
|
- **Destructure the recorder.** Templates unwrap only top-level refs, so `v-if="recorder.isRecording"` is always true. Use `const { isRecording, startRecording } = useHotkeyRecorder(...)`.
|
|
83
84
|
- **The callback isn't tracked.** Read refs and props inside it.
|
|
84
85
|
- **Call the composables directly.** A `useShortcut(keys: string)` wrapper has to cast strings to hotkeys, which turns off type checking and drops sequences, reactive options, and app hotkeys.
|
|
86
|
+
- **Server-rendered labels need the user's platform.** On the server, `formatForDisplay` can't see the user's OS, so it renders Linux labels that differ after hydration for Mac and Windows users. Set the provider's `defaultOptions.platform` to `detectPlatform(userAgent)` from the request's `User-Agent` header, and format labels with `const format = useFormatForDisplay()` in `setup`, then `format(hotkey)`. Keep plain `formatForDisplay` for labels that render only in the browser.
|
|
85
87
|
|
|
86
88
|
When declaring app hotkeys, building a cheat sheet, or letting users rebind shortcuts, load `@tanstack/hotkeys#app-hotkeys` and read [app hotkeys in Vue](references/app-hotkeys.md).
|
|
87
89
|
|