@tanstack/preact-hotkeys 0.15.1 → 0.17.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/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/useHotkeyHint.d.ts +6 -6
- package/dist/useHotkeyHint.js +11 -8
- package/dist/useHotkeyScopesState.d.ts +20 -0
- package/dist/useHotkeyScopesState.js +26 -0
- package/package.json +6 -4
- package/skills/preact-hotkeys/SKILL.md +113 -0
- package/skills/preact-hotkeys/references/app-hotkeys.md +80 -0
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,11 @@ import { HotkeysProvider, HotkeysProviderOptions, HotkeysProviderProps, useDefau
|
|
|
3
3
|
import { UseHotkeyDefinition, useHotkeys } from "./useHotkeys.js";
|
|
4
4
|
import { PreactHotkeyRecorder, useHotkeyRecorder } from "./useHotkeyRecorder.js";
|
|
5
5
|
import { useHotkeyRegistrations } from "./useHotkeyRegistrations.js";
|
|
6
|
+
import { useHotkeyScopesState } from "./useHotkeyScopesState.js";
|
|
6
7
|
import { useHotkeyHint } from "./useHotkeyHint.js";
|
|
7
8
|
import { UseCustomHotkeysResult, useAppHotkeyList, useAppHotkeys, useCustomHotkeys } from "./useAppHotkeys.js";
|
|
8
9
|
import { useHeldKeys } from "./useHeldKeys.js";
|
|
9
10
|
import { useHeldKeyCodes } from "./useHeldKeyCodes.js";
|
|
10
11
|
import { useKeyHold } from "./useKeyHold.js";
|
|
11
12
|
export * from "@tanstack/hotkeys";
|
|
12
|
-
export { HotkeysProvider, HotkeysProviderOptions, HotkeysProviderProps, PreactHotkeyRecorder, UseAppHotkeyOptions, UseCustomHotkeysResult, UseHotkeyChordOptions, UseHotkeyCommonOptions, UseHotkeyDefinition, UseHotkeyOptions, UseHotkeyOptionsFor, UseHotkeySequenceOptions, UseHotkeyTarget, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeys, useHotkeysContext, useKeyHold };
|
|
13
|
+
export { HotkeysProvider, HotkeysProviderOptions, HotkeysProviderProps, PreactHotkeyRecorder, UseAppHotkeyOptions, UseCustomHotkeysResult, UseHotkeyChordOptions, UseHotkeyCommonOptions, UseHotkeyDefinition, UseHotkeyOptions, UseHotkeyOptionsFor, UseHotkeySequenceOptions, UseHotkeyTarget, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { useHotkeys } from "./useHotkeys.js";
|
|
|
3
3
|
import { useHotkey } from "./useHotkey.js";
|
|
4
4
|
import { useHotkeyRecorder } from "./useHotkeyRecorder.js";
|
|
5
5
|
import { useHotkeyRegistrations } from "./useHotkeyRegistrations.js";
|
|
6
|
+
import { useHotkeyScopesState } from "./useHotkeyScopesState.js";
|
|
6
7
|
import { useHotkeyHint } from "./useHotkeyHint.js";
|
|
7
8
|
import { useAppHotkeyList, useAppHotkeys, useCustomHotkeys } from "./useAppHotkeys.js";
|
|
8
9
|
import { useHeldKeys } from "./useHeldKeys.js";
|
|
@@ -11,4 +12,4 @@ import { useKeyHold } from "./useKeyHold.js";
|
|
|
11
12
|
|
|
12
13
|
export * from "@tanstack/hotkeys"
|
|
13
14
|
|
|
14
|
-
export { HotkeysProvider, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeys, useHotkeysContext, useKeyHold };
|
|
15
|
+
export { HotkeysProvider, useAppHotkeyList, useAppHotkeys, useCustomHotkeys, useDefaultHotkeysOptions, useHeldKeyCodes, useHeldKeys, useHotkey, useHotkeyHint, useHotkeyRecorder, useHotkeyRegistrations, useHotkeyScopesState, useHotkeys, useHotkeysContext, useKeyHold };
|
package/dist/useHotkeyHint.d.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { AppHotkey, HeldModifierOptions, RegisterableHotkey } from "@tanstack/ho
|
|
|
2
2
|
//#region src/useHotkeyHint.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Returns a boolean indicating whether held modifiers reveal this shortcut.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* a shortcut
|
|
5
|
+
* The hint shows only while the hotkey can fire: some registration of it is
|
|
6
|
+
* enabled and in an active scope. An app hotkey matches its registrations by
|
|
7
|
+
* id and uses its effective hotkey (false while unbound).
|
|
8
|
+
* Uses the nonempty-subset/AltGr rules of `matchesHeldModifiers`; `exact`
|
|
9
|
+
* requires every modifier. A sequence reveals its hint from its first step.
|
|
10
|
+
* Only visibility changes cause a rerender. This helper does not register a shortcut. A hotkey on an element counts only while focus is inside it.
|
|
11
11
|
*/
|
|
12
12
|
export declare function useHotkeyHint(hotkey: RegisterableHotkey | AppHotkey, options?: HeldModifierOptions): boolean;
|
|
13
13
|
//#endregion
|
package/dist/useHotkeyHint.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { useAppHotkeysStoreState } from "./_appHotkeysStore.js";
|
|
2
|
-
import { getKeyStateTracker, isAppHotkey, matchesHeldModifiers, resolveAppHotkey } from "@tanstack/hotkeys";
|
|
2
|
+
import { getHotkeyManager, getKeyStateTracker, isAppHotkey, matchesHeldModifiers, resolveAppHotkey } from "@tanstack/hotkeys";
|
|
3
3
|
import { useSelector } from "@tanstack/preact-store";
|
|
4
4
|
|
|
5
5
|
//#region src/useHotkeyHint.ts
|
|
6
6
|
/**
|
|
7
7
|
* Returns a boolean indicating whether held modifiers reveal this shortcut.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* a shortcut
|
|
8
|
+
* The hint shows only while the hotkey can fire: some registration of it is
|
|
9
|
+
* enabled and in an active scope. An app hotkey matches its registrations by
|
|
10
|
+
* id and uses its effective hotkey (false while unbound).
|
|
11
|
+
* Uses the nonempty-subset/AltGr rules of `matchesHeldModifiers`; `exact`
|
|
12
|
+
* requires every modifier. A sequence reveals its hint from its first step.
|
|
13
|
+
* Only visibility changes cause a rerender. This helper does not register a shortcut. A hotkey on an element counts only while focus is inside it.
|
|
14
14
|
*/
|
|
15
15
|
function useHotkeyHint(hotkey, options = {}) {
|
|
16
16
|
const store = useAppHotkeysStoreState();
|
|
17
17
|
const resolved = isAppHotkey(hotkey) ? resolveAppHotkey(hotkey, store).hotkey : hotkey;
|
|
18
|
-
|
|
18
|
+
const manager = getHotkeyManager();
|
|
19
|
+
const active = useSelector(manager.registrations, () => resolved !== null && manager.hasActiveRegistration(hotkey));
|
|
20
|
+
const held = useSelector(getKeyStateTracker().store, (state) => resolved !== null && matchesHeldModifiers(resolved, state.heldKeys, options));
|
|
21
|
+
return active && held;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
//#endregion
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HotkeyScopesState } from "@tanstack/hotkeys";
|
|
2
|
+
//#region src/useHotkeyScopesState.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Preact hook that returns the hotkey manager's scope state: the active
|
|
5
|
+
* scopes, the exclusive scope that owns the keyboard, and the scopes it
|
|
6
|
+
* allows or suspends. Re-renders when scopes activate or release.
|
|
7
|
+
*
|
|
8
|
+
* @returns The current scope state
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* function KeyboardOwner() {
|
|
13
|
+
* const { exclusive } = useHotkeyScopesState()
|
|
14
|
+
*
|
|
15
|
+
* return exclusive ? <p>Shortcuts belong to {exclusive}</p> : null
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function useHotkeyScopesState(): HotkeyScopesState;
|
|
20
|
+
//#endregion
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getHotkeyManager } from "@tanstack/hotkeys";
|
|
2
|
+
import { useSelector } from "@tanstack/preact-store";
|
|
3
|
+
|
|
4
|
+
//#region src/useHotkeyScopesState.ts
|
|
5
|
+
/**
|
|
6
|
+
* Preact hook that returns the hotkey manager's scope state: the active
|
|
7
|
+
* scopes, the exclusive scope that owns the keyboard, and the scopes it
|
|
8
|
+
* allows or suspends. Re-renders when scopes activate or release.
|
|
9
|
+
*
|
|
10
|
+
* @returns The current scope state
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* function KeyboardOwner() {
|
|
15
|
+
* const { exclusive } = useHotkeyScopesState()
|
|
16
|
+
*
|
|
17
|
+
* return exclusive ? <p>Shortcuts belong to {exclusive}</p> : null
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
function useHotkeyScopesState() {
|
|
22
|
+
return useSelector(getHotkeyManager().scopes, (state) => state);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { useHotkeyScopesState };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/preact-hotkeys",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Preact adapter for TanStack Hotkeys",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"keywords": [
|
|
18
18
|
"preact",
|
|
19
19
|
"tanstack",
|
|
20
|
-
"keys"
|
|
20
|
+
"keys",
|
|
21
|
+
"tanstack-intent"
|
|
21
22
|
],
|
|
22
23
|
"type": "module",
|
|
23
24
|
"types": "./dist/index.d.ts",
|
|
@@ -30,10 +31,11 @@
|
|
|
30
31
|
"node": ">=20"
|
|
31
32
|
},
|
|
32
33
|
"files": [
|
|
33
|
-
"dist"
|
|
34
|
+
"dist",
|
|
35
|
+
"skills"
|
|
34
36
|
],
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@tanstack/hotkeys": "0.
|
|
38
|
+
"@tanstack/hotkeys": "0.18.0",
|
|
37
39
|
"@tanstack/preact-store": "^0.13.5"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: preact-hotkeys
|
|
3
|
+
description: >-
|
|
4
|
+
Use when adding or fixing keyboard shortcuts in a Preact app with
|
|
5
|
+
@tanstack/preact-hotkeys: useHotkey and useHotkeys, refs as targets,
|
|
6
|
+
HotkeysProvider defaults and dialog scopes, app hotkey hooks, recorders,
|
|
7
|
+
held-key and hint hooks, or replacing useEffect keydown listeners.
|
|
8
|
+
metadata:
|
|
9
|
+
purpose: >-
|
|
10
|
+
Preact bindings for TanStack Hotkeys: hooks, providers, refs, and the
|
|
11
|
+
Preact-specific mistakes to avoid.
|
|
12
|
+
type: framework
|
|
13
|
+
framework: preact
|
|
14
|
+
library: '@tanstack/preact-hotkeys'
|
|
15
|
+
library_version: '0.15.0'
|
|
16
|
+
sources:
|
|
17
|
+
- src/useHotkey.ts
|
|
18
|
+
- src/useHotkeys.ts
|
|
19
|
+
- src/HotkeysProvider.tsx
|
|
20
|
+
- src/useAppHotkeys.ts
|
|
21
|
+
- src/utils.ts
|
|
22
|
+
- TanStack/hotkeys:docs/framework/preact/quick-start.md
|
|
23
|
+
- TanStack/hotkeys:docs/framework/preact/guides/hotkeys-provider-and-scopes.md
|
|
24
|
+
requires:
|
|
25
|
+
- '@tanstack/hotkeys#hotkeys-core'
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# TanStack Hotkeys in Preact
|
|
29
|
+
|
|
30
|
+
Before starting, load the `@tanstack/hotkeys#hotkeys-core` skill (`npx @tanstack/intent@latest load @tanstack/hotkeys#hotkeys-core`).
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { formatForDisplay, useHotkey } from '@tanstack/preact-hotkeys'
|
|
34
|
+
|
|
35
|
+
export function SaveButton({ onSave }: { onSave: () => void }) {
|
|
36
|
+
useHotkey('Mod+S', () => onSave(), { meta: { name: 'Save' } })
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<button onClick={onSave}>
|
|
40
|
+
Save <kbd>{formatForDisplay('Mod+S')}</kbd>
|
|
41
|
+
</button>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API
|
|
47
|
+
|
|
48
|
+
| API | What it's for |
|
|
49
|
+
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
50
|
+
| `useHotkey(hotkey, callback, options?)` | Register one chord, sequence, or app hotkey while the component is mounted. |
|
|
51
|
+
| `useHotkeys(definitions, commonOptions?)` | Register several hotkeys, or a list built from data, in one call. |
|
|
52
|
+
| `<HotkeysProvider>` | Set default options, a scope (`exclusive` for dialogs), `enabled`, and app hotkeys for the components inside it. |
|
|
53
|
+
| `useHotkeysContext()` | Read the nearest provider's merged defaults and enabled state, or `null` outside a provider. |
|
|
54
|
+
| `useDefaultHotkeysOptions()` | Read the default options merged from every provider above. |
|
|
55
|
+
| `useAppHotkeys()` | Get the declared app hotkeys with the user's custom hotkeys applied, to pass to the register API. |
|
|
56
|
+
| `useAppHotkeyList()` | List every app hotkey with its status, including ones whose components aren't mounted, for a cheat sheet or settings screen. |
|
|
57
|
+
| `useCustomHotkeys()` | Read, change, and reset the user's custom hotkeys, and check a new one for conflicts. |
|
|
58
|
+
| `useHotkeyRecorder(options)` | Record a chord or sequence the user presses, for a settings screen. |
|
|
59
|
+
| `useHotkeyRegistrations()` | List every registered hotkey with its options, `meta`, and `status` (whether it's enabled and in an active scope), for a cheat sheet of what's mounted. |
|
|
60
|
+
| `useHotkeyScopesState()` | Get the active scopes and the exclusive scope that owns the keyboard. |
|
|
61
|
+
| `useHotkeyHint(hotkey, options?)` | Get whether held modifiers should reveal a shortcut's hint, such as labels that appear while Mod is held. False unless a registration of the hotkey can fire: enabled, in an active scope, and with focus inside its element target. |
|
|
62
|
+
| `useKeyHold(key)` | Get whether one key is held, such as Shift for a range-select mode. |
|
|
63
|
+
| `useHeldKeys()` | Get every key that's held right now. |
|
|
64
|
+
| `useHeldKeyCodes()` | Map each held key to its physical `event.code`. |
|
|
65
|
+
|
|
66
|
+
The package also re-exports `@tanstack/hotkeys`, such as `formatForDisplay`, `matchesKeyboardEvent`, and `defineAppHotkeys`.
|
|
67
|
+
|
|
68
|
+
No provider is required.
|
|
69
|
+
|
|
70
|
+
## A dialog that owns the keyboard
|
|
71
|
+
|
|
72
|
+
```tsx no-check
|
|
73
|
+
import { useId } from 'preact/hooks'
|
|
74
|
+
import type { ComponentChildren } from 'preact'
|
|
75
|
+
import { HotkeysProvider, useHotkey } from '@tanstack/preact-hotkeys'
|
|
76
|
+
|
|
77
|
+
export function Dialog(props: {
|
|
78
|
+
onClose: () => void
|
|
79
|
+
children: ComponentChildren
|
|
80
|
+
}) {
|
|
81
|
+
return (
|
|
82
|
+
<HotkeysProvider scope={`dialog-${useId()}`} exclusive>
|
|
83
|
+
<DialogBody {...props} />
|
|
84
|
+
</HotkeysProvider>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function DialogBody({
|
|
89
|
+
onClose,
|
|
90
|
+
children,
|
|
91
|
+
}: {
|
|
92
|
+
onClose: () => void
|
|
93
|
+
children: ComponentChildren
|
|
94
|
+
}) {
|
|
95
|
+
useHotkey('Escape', onClose)
|
|
96
|
+
return <div role="dialog">{children}</div>
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
A hook uses the nearest `HotkeysProvider` above its component. Registering `Escape` in `Dialog` itself would put it in the outer scope, which the exclusive scope suspends, so the dialog couldn't close. `useId` (Preact 10.11 or newer) gives each open dialog its own scope.
|
|
101
|
+
|
|
102
|
+
## Pitfalls
|
|
103
|
+
|
|
104
|
+
- **Pass the ref, not `ref.current`.** `target: listRef.current` is `null` on the first render, and a `null` target means `document`, so the hotkey works page-wide. Pass `target: listRef`; a ref that is still empty waits for its element.
|
|
105
|
+
- **No dependency arrays or `useCallback`.** The hooks read the hotkey, callback, and options on every render, so inline callbacks always see current state.
|
|
106
|
+
- **Call the hooks directly.** A `useShortcut(keys: string)` wrapper has to cast strings to hotkeys, which turns off type checking and drops sequences, options, app hotkeys, and the typed callback context.
|
|
107
|
+
- **In tests,** set `<HotkeysProvider defaultOptions={{ hotkey: { platform: 'mac' } }}>`.
|
|
108
|
+
|
|
109
|
+
When declaring app hotkeys, building a cheat sheet, or letting users rebind shortcuts, load `@tanstack/hotkeys#app-hotkeys` and read [app hotkeys in Preact](references/app-hotkeys.md).
|
|
110
|
+
|
|
111
|
+
## API discovery and docs
|
|
112
|
+
|
|
113
|
+
Signatures: `node_modules/@tanstack/preact-hotkeys/dist/*.d.ts`. Guides: `https://tanstack.com/hotkeys/latest/docs/framework/preact/guides/<page>.md`, such as `hotkeys`, `hotkeys-provider-and-scopes`, or `app-hotkeys`. Devtools: `hotkeysDevtoolsPlugin()` from `@tanstack/preact-hotkeys-devtools` in `@tanstack/preact-devtools`.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# App hotkeys in Preact
|
|
2
|
+
|
|
3
|
+
The `@tanstack/hotkeys#app-hotkeys` skill owns the rules. This is the Preact wiring.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
// app-hotkeys.ts
|
|
7
|
+
import { defineAppHotkeys } from '@tanstack/preact-hotkeys'
|
|
8
|
+
|
|
9
|
+
export const appHotkeys = defineAppHotkeys({
|
|
10
|
+
'doc.save': { hotkey: 'Mod+S', meta: { name: 'Save' } },
|
|
11
|
+
'help.shortcuts': { hotkey: 'Mod+/', meta: { name: 'Keyboard shortcuts' } },
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
declare module '@tanstack/preact-hotkeys' {
|
|
15
|
+
interface Register {
|
|
16
|
+
appHotkeys: typeof appHotkeys
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```tsx no-check
|
|
22
|
+
import type { ComponentChildren } from 'preact'
|
|
23
|
+
import { HotkeysProvider } from '@tanstack/preact-hotkeys'
|
|
24
|
+
import type { CustomHotkeys } from '@tanstack/preact-hotkeys'
|
|
25
|
+
import { appHotkeys } from './app-hotkeys'
|
|
26
|
+
|
|
27
|
+
const saved: CustomHotkeys = JSON.parse(localStorage.getItem('hotkeys') ?? '{}')
|
|
28
|
+
|
|
29
|
+
export function Root({ children }: { children: ComponentChildren }) {
|
|
30
|
+
return (
|
|
31
|
+
<HotkeysProvider
|
|
32
|
+
appHotkeys={appHotkeys}
|
|
33
|
+
customHotkeys={saved}
|
|
34
|
+
onCustomHotkeysChange={(custom) =>
|
|
35
|
+
localStorage.setItem('hotkeys', JSON.stringify(custom))
|
|
36
|
+
}
|
|
37
|
+
>
|
|
38
|
+
{children}
|
|
39
|
+
</HotkeysProvider>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Register with `useHotkey(appHotkeys['doc.save'], save)`, using the import or `useAppHotkeys()`. Build a cheat sheet from `useAppHotkeyList()`.
|
|
45
|
+
|
|
46
|
+
A settings row records with `useHotkeyRecorder` and saves through `useCustomHotkeys`:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import {
|
|
50
|
+
formatForDisplay,
|
|
51
|
+
useAppHotkeys,
|
|
52
|
+
useCustomHotkeys,
|
|
53
|
+
useHotkeyRecorder,
|
|
54
|
+
} from '@tanstack/preact-hotkeys'
|
|
55
|
+
import type { AppHotkeyId } from '@tanstack/preact-hotkeys'
|
|
56
|
+
|
|
57
|
+
export function ShortcutRow({ id }: { id: AppHotkeyId }) {
|
|
58
|
+
const appHotkey = useAppHotkeys()[id]
|
|
59
|
+
const { findConflicts, setCustomHotkey, resetCustomHotkey } =
|
|
60
|
+
useCustomHotkeys()
|
|
61
|
+
const recorder = useHotkeyRecorder({
|
|
62
|
+
maxSteps: Infinity,
|
|
63
|
+
validate: (hotkey) => {
|
|
64
|
+
const [conflict] = findConflicts(id, hotkey)
|
|
65
|
+
return conflict ? `Used by ${conflict.meta?.name ?? conflict.id}` : true
|
|
66
|
+
},
|
|
67
|
+
onRecord: (hotkey) => setCustomHotkey(id, hotkey),
|
|
68
|
+
onClear: () => setCustomHotkey(id, null),
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div>
|
|
73
|
+
{appHotkey.meta?.name}:{' '}
|
|
74
|
+
{appHotkey.hotkey ? formatForDisplay(appHotkey.hotkey) : 'Unassigned'}
|
|
75
|
+
<button onClick={recorder.startRecording}>Change</button>
|
|
76
|
+
<button onClick={() => resetCustomHotkey(id)}>Reset</button>
|
|
77
|
+
</div>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
```
|