PathLogs UI
Русский

Hooks

useHotkeys

Keyboard shortcuts with sequences and modifiers.

Global keyboard shortcuts with support for sequences: press «g», then «d» — and you are on the dashboard.

Example

gdДашбордgmМои задачиdОтметить готовойmodkПоиск
  • Нажмите сочетание — сюда попадёт срабатывание

Key notation

Chords are separated by spaces; modifiers inside a chord, by a plus:

tsx
"k"            // a plain key
"g d"          // a sequence: g, then d
"mod+k"        // Ctrl on Windows/Linux, ⌘ on macOS
"mod+shift+p"  // several modifiers
"?"            // shift is implied
"escape"       // esc, up, down, left, right, enter, space, delete
modmodifier

Ctrl and ⌘ in one notation. Telling ctrl and cmd apart is rarely needed — what an app almost always means is «the system modifier».

shiftmodifier

Required only when written explicitly. «?» is typed with shift on most layouts, and demanding shift: false would break that notation.

altmodifier

Also known as option on macOS.

Options

keys*string

The key notation.

handler*(e: KeyboardEvent) => void

What to do. preventDefault is called for you.

labelstring

The caption for the help screen. Entries without one are treated as internal and stay out of the help.

groupstring

A section in the help: «Navigation», «Board».

allowInInputboolean

defaults to: false

Also fires while focus is in a text field. For mod+k and escape.

enabledboolean

defaults to: true

Temporarily disable an entry without removing it from the list.

The hook's second argument holds shared options: enabled switches off the whole set, timeout sets the window for the second key (1200ms by default), and target lets you listen on a specific element rather than window.

Text inputs

Ordinary keys inside a text field belong to the field, not to the application. Entries with allowInInput are the exception.

The help screen

The same array is handed to the HotkeysHelp component — it shows the help screen on «?» and calls useHotkeys itself:

tsx
import { HotkeysHelp } from "@toimetdev/pathlogs-core";

const hotkeys = [
  { keys: "g d", label: "Dashboard", group: "Navigation", handler: goDashboard },
];

// no separate useHotkeys call needed — HotkeysHelp does it for you
<HotkeysHelp hotkeys={hotkeys} hint="«g» is the leader: press g, then a second key." />

One list for both handling and help — there is nothing to drift apart.

The matcher, separately

Parsing and matching know nothing about the DOM and are covered by tests:

tsx
import {
  parseHotkey,        // "g d" → [{ key: "g" }, { key: "d" }]
  chordFromEvent,     // KeyboardEvent → a chord
  chordMatches,       // do two chords match
  createHotkeyMatcher // the state machine for sequences
} from "@toimetdev/pathlogs-hooks";

The matcher stores no buffer of presses, only an index inside an unfinished sequence: a buffer would have to be cleared on a timer, while an index need only be compared against the time of the last press. That is why a «g» pressed a minute ago does not turn a stray «d» into a navigation.