Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silent-console-logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/keys': patch
---

Add silent option to checkHotkey function to suppress console output in production
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ title: useHotkeyRecorder
function useHotkeyRecorder(options): ReactHotkeyRecorder;
```

Defined in: [useHotkeyRecorder.ts:60](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L60)
Defined in: [useHotkeyRecorder.ts:57](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L57)

React hook for recording keyboard shortcuts.

Expand Down
12 changes: 6 additions & 6 deletions docs/framework/react/reference/interfaces/ReactHotkeyRecorder.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: ReactHotkeyRecorder

# Interface: ReactHotkeyRecorder

Defined in: [useHotkeyRecorder.ts:9](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L9)
Defined in: [useHotkeyRecorder.ts:6](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L6)

## Properties

Expand All @@ -15,7 +15,7 @@ Defined in: [useHotkeyRecorder.ts:9](https://github.com/TanStack/keys/blob/main/
cancelRecording: () => void;
```

Defined in: [useHotkeyRecorder.ts:19](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L19)
Defined in: [useHotkeyRecorder.ts:16](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L16)

Cancel recording without saving

Expand All @@ -31,7 +31,7 @@ Cancel recording without saving
isRecording: boolean;
```

Defined in: [useHotkeyRecorder.ts:11](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L11)
Defined in: [useHotkeyRecorder.ts:8](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L8)

Whether recording is currently active

Expand All @@ -43,7 +43,7 @@ Whether recording is currently active
recordedHotkey: Hotkey | null;
```

Defined in: [useHotkeyRecorder.ts:13](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L13)
Defined in: [useHotkeyRecorder.ts:10](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L10)

The currently recorded hotkey (for live preview)

Expand All @@ -55,7 +55,7 @@ The currently recorded hotkey (for live preview)
startRecording: () => void;
```

Defined in: [useHotkeyRecorder.ts:15](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L15)
Defined in: [useHotkeyRecorder.ts:12](https://github.com/TanStack/keys/blob/main/packages/react-keys/src/useHotkeyRecorder.ts#L12)

Start recording a new hotkey

Expand All @@ -71,7 +71,7 @@ Start recording a new hotkey
stopRecording: () => void;
```

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

Stop recording (same as cancel)

Expand Down
12 changes: 6 additions & 6 deletions docs/reference/classes/HotkeyManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ unregister()
destroy(): void;
```

Defined in: [manager.ts:526](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L526)
Defined in: [manager.ts:520](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L520)

Destroys the manager and removes all listeners.

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

Defined in: [manager.ts:497](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L497)
Defined in: [manager.ts:491](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L491)

Gets the number of registered hotkeys.

Expand All @@ -66,7 +66,7 @@ Gets the number of registered hotkeys.
isRegistered(hotkey, target?): boolean;
```

Defined in: [manager.ts:508](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L508)
Defined in: [manager.ts:502](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L502)

Checks if a specific hotkey is registered.

Expand Down Expand Up @@ -101,7 +101,7 @@ register(
options): HotkeyRegistrationHandle;
```

Defined in: [manager.ts:122](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L122)
Defined in: [manager.ts:120](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L120)

Registers a hotkey handler and returns a handle for updating the registration.

Expand Down Expand Up @@ -157,7 +157,7 @@ handle.unregister()
static getInstance(): HotkeyManager;
```

Defined in: [manager.ts:80](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L80)
Defined in: [manager.ts:78](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L78)

Gets the singleton instance of HotkeyManager.

Expand All @@ -173,7 +173,7 @@ Gets the singleton instance of HotkeyManager.
static resetInstance(): void;
```

Defined in: [manager.ts:90](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L90)
Defined in: [manager.ts:88](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L88)

Resets the singleton instance. Useful for testing.

Expand Down
6 changes: 3 additions & 3 deletions docs/reference/classes/HotkeyRecorder.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Use this to subscribe to state changes or access current state.
cancel(): void;
```

Defined in: [recorder.ts:212](https://github.com/TanStack/keys/blob/main/packages/keys/src/recorder.ts#L212)
Defined in: [recorder.ts:214](https://github.com/TanStack/keys/blob/main/packages/keys/src/recorder.ts#L214)

Cancel recording without saving.

Expand All @@ -106,7 +106,7 @@ the onCancel callback if provided.
destroy(): void;
```

Defined in: [recorder.ts:257](https://github.com/TanStack/keys/blob/main/packages/keys/src/recorder.ts#L257)
Defined in: [recorder.ts:259](https://github.com/TanStack/keys/blob/main/packages/keys/src/recorder.ts#L259)

Clean up event listeners and reset state.

Expand Down Expand Up @@ -168,7 +168,7 @@ a valid hotkey is recorded, Escape is pressed, or stop/cancel is called.
stop(): void;
```

Defined in: [recorder.ts:192](https://github.com/TanStack/keys/blob/main/packages/keys/src/recorder.ts#L192)
Defined in: [recorder.ts:194](https://github.com/TanStack/keys/blob/main/packages/keys/src/recorder.ts#L194)

Stop recording (same as cancel, but doesn't call onCancel).

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/functions/getHotkeyManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ title: getHotkeyManager
function getHotkeyManager(): HotkeyManager;
```

Defined in: [manager.ts:542](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L542)
Defined in: [manager.ts:536](https://github.com/TanStack/keys/blob/main/packages/keys/src/manager.ts#L536)

Gets the singleton HotkeyManager instance.
Convenience function for accessing the manager.
Expand Down
4 changes: 3 additions & 1 deletion packages/keys/src/recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ export class HotkeyRecorder {
// Validate: must have at least one non-modifier key
if (hasNonModifierKey(finalHotkey, this.#platform)) {
// Remove listener FIRST to prevent any additional events
const handlerToRemove = this.#keydownHandler as ((event: KeyboardEvent) => void) | null
const handlerToRemove = this.#keydownHandler as
| ((event: KeyboardEvent) => void)
| null
if (handlerToRemove) {
this.#removeListener(handlerToRemove)
this.#keydownHandler = null
Expand Down
23 changes: 17 additions & 6 deletions packages/keys/src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,24 +202,35 @@ export function assertValidHotkey(hotkey: Hotkey | (string & {})): void {
* Useful for development-time feedback.
*
* @param hotkey - The hotkey string to validate
* @param options - Optional configuration
* @param options.silent - If true, suppresses console output (default: false)
* @returns True if the hotkey is valid (may still have warnings)
*
* @example
* ```ts
* checkHotkey('Alt+C')
* // Console: Warning: Alt+C may not work reliably on macOS...
* // Returns: true
*
* checkHotkey('Alt+C', { silent: true })
* // No console output
* // Returns: true
* ```
*/
export function checkHotkey(hotkey: Hotkey | (string & {})): boolean {
export function checkHotkey(
hotkey: Hotkey | (string & {}),
options?: { silent?: boolean },
): boolean {
const result = validateHotkey(hotkey)

if (result.errors.length > 0) {
console.error(`Hotkey '${hotkey}' errors:`, result.errors.join('; '))
}
if (!options?.silent) {
if (result.errors.length > 0) {
console.error(`Hotkey '${hotkey}' errors:`, result.errors.join('; '))
}

if (result.warnings.length > 0) {
console.warn(`Hotkey '${hotkey}' warnings:`, result.warnings.join('; '))
if (result.warnings.length > 0) {
console.warn(`Hotkey '${hotkey}' warnings:`, result.warnings.join('; '))
}
}

return result.valid
Expand Down
25 changes: 25 additions & 0 deletions packages/keys/tests/validate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,29 @@ describe('checkHotkey', () => {

errorSpy.mockRestore()
})

it('should not log warnings when silent option is true', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})

checkHotkey('Alt+C', { silent: true })

expect(warnSpy).not.toHaveBeenCalled()

warnSpy.mockRestore()
})

it('should not log errors when silent option is true', () => {
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})

checkHotkey('', { silent: true })

expect(errorSpy).not.toHaveBeenCalled()

errorSpy.mockRestore()
})

it('should still return correct validation result when silent', () => {
expect(checkHotkey('Control+A', { silent: true })).toBe(true)
expect(checkHotkey('', { silent: true })).toBe(false)
})
})
8 changes: 2 additions & 6 deletions packages/react-keys/src/useHotkeyRecorder.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { useEffect, useRef } from 'react'
import { useStore } from '@tanstack/react-store'
import {

HotkeyRecorder

} from '@tanstack/keys'
import type {Hotkey, HotkeyRecorderOptions} from '@tanstack/keys';
import { HotkeyRecorder } from '@tanstack/keys'
import type { Hotkey, HotkeyRecorderOptions } from '@tanstack/keys'

export interface ReactHotkeyRecorder {
/** Whether recording is currently active */
Expand Down