Skip to content

Commit 1b82845

Browse files
ci: apply automated fixes
1 parent 05a6b3b commit 1b82845

File tree

8 files changed

+186
-51
lines changed

8 files changed

+186
-51
lines changed

docs/framework/react/reference/functions/useHotkey.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,24 @@ function useHotkey(
1212
options): void;
1313
```
1414

15-
Defined in: [useHotkey.ts:71](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkey.ts#L71)
15+
Defined in: [useHotkey.ts:83](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkey.ts#L83)
1616

1717
React hook for registering a keyboard hotkey.
1818

1919
Uses the singleton HotkeyManager for efficient event handling.
2020
The callback receives both the keyboard event and a context object
2121
containing the hotkey string and parsed hotkey.
2222

23+
This hook syncs the callback and options on every render to avoid
24+
stale closures, similar to TanStack Pacer's pattern. This means
25+
callbacks that reference React state will always have access to
26+
the latest values.
27+
2328
## Parameters
2429

2530
### hotkey
2631

27-
The hotkey string (e.g., 'Mod+S', 'Escape')
32+
The hotkey string (e.g., 'Mod+S', 'Escape') or ParsedHotkey object
2833

2934
`Hotkey` | `ParsedHotkey`
3035

@@ -48,18 +53,21 @@ Options for the hotkey behavior
4853

4954
```tsx
5055
function SaveButton() {
51-
useHotkey('Mod+S', (event, { hotkey, parsedHotkey }) => {
52-
console.log(`${hotkey} was pressed`)
56+
const [count, setCount] = useState(0)
57+
58+
// Callback always has access to latest count value
59+
useHotkey('Mod+S', (event, { hotkey }) => {
60+
console.log(`Save triggered, count is ${count}`)
5361
handleSave()
5462
}, { preventDefault: true })
5563

56-
return <button>Save</button>
64+
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>
5765
}
5866
```
5967

6068
```tsx
6169
function Modal({ isOpen, onClose }) {
62-
// Only active when modal is open
70+
// enabled option is synced on every render
6371
useHotkey('Escape', () => {
6472
onClose()
6573
}, { enabled: isOpen })
@@ -71,11 +79,13 @@ function Modal({ isOpen, onClose }) {
7179

7280
```tsx
7381
function Editor() {
74-
// Prevent repeated triggering while holding
82+
const editorRef = useRef<HTMLDivElement>(null)
83+
84+
// Scoped to a specific element
7585
useHotkey('Mod+S', () => {
7686
save()
77-
}, { preventDefault: true, requireReset: true })
87+
}, { target: editorRef, preventDefault: true })
7888

79-
return <div>...</div>
89+
return <div ref={editorRef}>...</div>
8090
}
8191
```

docs/framework/react/reference/interfaces/UseHotkeyOptions.md

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,14 @@ title: UseHotkeyOptions
55

66
# Interface: UseHotkeyOptions
77

8-
Defined in: [useHotkey.ts:10](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkey.ts#L10)
8+
Defined in: [useHotkey.ts:11](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkey.ts#L11)
99

1010
## Extends
1111

12-
- `Omit`\<`HotkeyOptions`, `"enabled"` \| `"target"`\>
12+
- `Omit`\<`HotkeyOptions`, `"target"`\>
1313

1414
## Properties
1515

16-
### enabled?
17-
18-
```ts
19-
optional enabled: boolean;
20-
```
21-
22-
Defined in: [useHotkey.ts:12](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkey.ts#L12)
23-
24-
Whether the hotkey is enabled. Defaults to true.
25-
26-
***
27-
2816
### target?
2917

3018
```ts
@@ -36,6 +24,8 @@ optional target:
3624
| null;
3725
```
3826

39-
Defined in: [useHotkey.ts:14](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkey.ts#L14)
27+
Defined in: [useHotkey.ts:17](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkey.ts#L17)
4028

41-
The DOM element or React ref to attach the event listener to. Defaults to document.
29+
The DOM element to attach the event listener to.
30+
Can be a React ref, direct DOM element, or null.
31+
Defaults to document.

docs/reference/classes/HotkeyManager.md

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: HotkeyManager
55

66
# Class: HotkeyManager
77

8-
Defined in: [manager.ts:40](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L40)
8+
Defined in: [manager.ts:56](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L56)
99

1010
Singleton manager for hotkey registrations.
1111

@@ -34,7 +34,7 @@ unregister()
3434
destroy(): void;
3535
```
3636

37-
Defined in: [manager.ts:459](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L459)
37+
Defined in: [manager.ts:526](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L526)
3838

3939
Destroys the manager and removes all listeners.
4040

@@ -50,7 +50,7 @@ Destroys the manager and removes all listeners.
5050
getRegistrationCount(): number;
5151
```
5252

53-
Defined in: [manager.ts:440](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L440)
53+
Defined in: [manager.ts:497](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L497)
5454

5555
Gets the number of registered hotkeys.
5656

@@ -63,10 +63,10 @@ Gets the number of registered hotkeys.
6363
### isRegistered()
6464

6565
```ts
66-
isRegistered(hotkey): boolean;
66+
isRegistered(hotkey, target?): boolean;
6767
```
6868
69-
Defined in: [manager.ts:447](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L447)
69+
Defined in: [manager.ts:508](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L508)
7070
7171
Checks if a specific hotkey is registered.
7272
@@ -76,10 +76,20 @@ Checks if a specific hotkey is registered.
7676
7777
[`Hotkey`](../type-aliases/Hotkey.md)
7878
79+
The hotkey string to check
80+
81+
##### target?
82+
83+
Optional target element to match (if provided, both hotkey and target must match)
84+
85+
`HTMLElement` | `Document` | `Window`
86+
7987
#### Returns
8088
8189
`boolean`
8290
91+
True if a matching registration exists
92+
8393
***
8494
8595
### register()
@@ -88,12 +98,15 @@ Checks if a specific hotkey is registered.
8898
register(
8999
hotkey,
90100
callback,
91-
options): () => void;
101+
options): HotkeyRegistrationHandle;
92102
```
93103
94-
Defined in: [manager.ts:89](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L89)
104+
Defined in: [manager.ts:122](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L122)
105+
106+
Registers a hotkey handler and returns a handle for updating the registration.
95107
96-
Registers a hotkey handler.
108+
The returned handle allows updating the callback and options without
109+
re-registering, which is useful for avoiding stale closures in React.
97110
98111
#### Parameters
99112
@@ -117,15 +130,24 @@ Options for the hotkey behavior
117130
118131
#### Returns
119132
120-
A function to unregister the hotkey
133+
[`HotkeyRegistrationHandle`](../interfaces/HotkeyRegistrationHandle.md)
134+
135+
A handle for managing the registration
136+
137+
#### Example
121138
122139
```ts
123-
(): void;
124-
```
140+
const handle = manager.register('Mod+S', callback, { preventDefault: true })
125141

126-
##### Returns
142+
// Update callback without re-registering (avoids stale closures)
143+
handle.callback = newCallback
127144

128-
`void`
145+
// Update options
146+
handle.setOptions({ enabled: false })
147+
148+
// Unregister when done
149+
handle.unregister()
150+
```
129151
130152
***
131153
@@ -135,7 +157,7 @@ A function to unregister the hotkey
135157
static getInstance(): HotkeyManager;
136158
```
137159
138-
Defined in: [manager.ts:64](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L64)
160+
Defined in: [manager.ts:80](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L80)
139161
140162
Gets the singleton instance of HotkeyManager.
141163
@@ -151,7 +173,7 @@ Gets the singleton instance of HotkeyManager.
151173
static resetInstance(): void;
152174
```
153175
154-
Defined in: [manager.ts:74](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L74)
176+
Defined in: [manager.ts:90](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L90)
155177
156178
Resets the singleton instance. Useful for testing.
157179

docs/reference/functions/getHotkeyManager.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ title: getHotkeyManager
99
function getHotkeyManager(): HotkeyManager;
1010
```
1111

12-
Defined in: [manager.ts:475](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L475)
12+
Defined in: [manager.ts:542](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L542)
1313

1414
Gets the singleton HotkeyManager instance.
1515
Convenience function for accessing the manager.

docs/reference/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ title: "@tanstack/keys"
1818
- [HotkeyCallbackContext](interfaces/HotkeyCallbackContext.md)
1919
- [HotkeyOptions](interfaces/HotkeyOptions.md)
2020
- [HotkeyRegistration](interfaces/HotkeyRegistration.md)
21+
- [HotkeyRegistrationHandle](interfaces/HotkeyRegistrationHandle.md)
2122
- [KeyStateTrackerState](interfaces/KeyStateTrackerState.md)
2223
- [ParsedHotkey](interfaces/ParsedHotkey.md)
2324
- [SequenceOptions](interfaces/SequenceOptions.md)
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
id: HotkeyRegistrationHandle
3+
title: HotkeyRegistrationHandle
4+
---
5+
6+
# Interface: HotkeyRegistrationHandle
7+
8+
Defined in: [types.ts:492](https://github.com/TanStack/keys/blob/main/packages/keys/src/types.ts#L492)
9+
10+
A handle returned from HotkeyManager.register() that allows updating
11+
the callback and options without re-registering the hotkey.
12+
13+
This pattern is similar to TanStack Pacer's Debouncer, where the function
14+
and options can be synced on every render to avoid stale closures.
15+
16+
## Example
17+
18+
```ts
19+
const handle = manager.register('Mod+S', callback, options)
20+
21+
// Update callback without re-registering (avoids stale closures)
22+
handle.callback = newCallback
23+
24+
// Update options without re-registering
25+
handle.setOptions({ enabled: false })
26+
27+
// Check if still active
28+
if (handle.isActive) {
29+
// ...
30+
}
31+
32+
// Unregister when done
33+
handle.unregister()
34+
```
35+
36+
## Properties
37+
38+
### callback
39+
40+
```ts
41+
callback: HotkeyCallback;
42+
```
43+
44+
Defined in: [types.ts:503](https://github.com/TanStack/keys/blob/main/packages/keys/src/types.ts#L503)
45+
46+
The callback function. Can be set directly to update without re-registering.
47+
This avoids stale closures when the callback references React state.
48+
49+
***
50+
51+
### id
52+
53+
```ts
54+
readonly id: string;
55+
```
56+
57+
Defined in: [types.ts:494](https://github.com/TanStack/keys/blob/main/packages/keys/src/types.ts#L494)
58+
59+
Unique identifier for this registration
60+
61+
***
62+
63+
### isActive
64+
65+
```ts
66+
readonly isActive: boolean;
67+
```
68+
69+
Defined in: [types.ts:512](https://github.com/TanStack/keys/blob/main/packages/keys/src/types.ts#L512)
70+
71+
Check if this registration is still active (not unregistered)
72+
73+
***
74+
75+
### setOptions()
76+
77+
```ts
78+
setOptions: (options) => void;
79+
```
80+
81+
Defined in: [types.ts:509](https://github.com/TanStack/keys/blob/main/packages/keys/src/types.ts#L509)
82+
83+
Update options (merged with existing options).
84+
Useful for updating `enabled`, `preventDefault`, etc. without re-registering.
85+
86+
#### Parameters
87+
88+
##### options
89+
90+
`Partial`\<[`HotkeyOptions`](HotkeyOptions.md)\>
91+
92+
#### Returns
93+
94+
`void`
95+
96+
***
97+
98+
### unregister()
99+
100+
```ts
101+
unregister: () => void;
102+
```
103+
104+
Defined in: [types.ts:497](https://github.com/TanStack/keys/blob/main/packages/keys/src/types.ts#L497)
105+
106+
Unregister this hotkey
107+
108+
#### Returns
109+
110+
`void`

packages/keys/src/manager.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ export class HotkeyManager {
130130

131131
// Resolve target: default to document if not provided or null
132132
const target =
133-
options.target ?? (typeof document !== 'undefined' ? document : ({} as Document))
133+
options.target ??
134+
(typeof document !== 'undefined' ? document : ({} as Document))
134135

135136
const registration: HotkeyRegistration = {
136137
id,
@@ -504,7 +505,10 @@ export class HotkeyManager {
504505
* @param target - Optional target element to match (if provided, both hotkey and target must match)
505506
* @returns True if a matching registration exists
506507
*/
507-
isRegistered(hotkey: Hotkey, target?: HTMLElement | Document | Window): boolean {
508+
isRegistered(
509+
hotkey: Hotkey,
510+
target?: HTMLElement | Document | Window,
511+
): boolean {
508512
for (const registration of this.registrations.values()) {
509513
if (registration.hotkey === hotkey) {
510514
// If target is specified, both must match

0 commit comments

Comments
 (0)