matchEvent.ts38 lines · main
| 1 | import { getSequenceManager, matchesKeyboardEvent } from '@tanstack/react-hotkeys' |
| 2 | |
| 3 | import { SHORTCUT_DEFINITIONS } from './registry' |
| 4 | import type { RegistryDefinations } from './types' |
| 5 | |
| 6 | /** |
| 7 | * Returns true if the given keyboard event matches a shortcut that is both: |
| 8 | * |
| 9 | * 1. **In the target registry** (defaults to every known shortcut, but callers |
| 10 | * can pass a subset like `tableEditorRegistry` to scope the check) |
| 11 | * 2. **Currently active and enabled** — i.e. a `useShortcut` is mounted for it |
| 12 | * AND its `enabled` option is not `false` |
| 13 | * |
| 14 | * Chord sequences (e.g. `['G', 'T']`) match on any individual step, so |
| 15 | * pressing `G` counts as a match while the chord is in flight. |
| 16 | * |
| 17 | * Respecting the live `enabled` state matters: if a shortcut is registered but |
| 18 | * gated off (e.g. `enabled: !!snap.selectedCellPosition`), we must NOT suppress |
| 19 | * the default behavior on its behalf, because the shortcut won't actually fire. |
| 20 | */ |
| 21 | |
| 22 | export function eventMatchesAnyShortcut( |
| 23 | event: KeyboardEvent, |
| 24 | registry: RegistryDefinations<string> = SHORTCUT_DEFINITIONS |
| 25 | ): boolean { |
| 26 | const scopedSteps = new Set(Object.values(registry).flatMap((def) => def.sequence)) |
| 27 | const activeRegistrations = getSequenceManager().registrations.state.values() |
| 28 | |
| 29 | for (const view of activeRegistrations) { |
| 30 | if (view.options.enabled === false) continue |
| 31 | const matches = view.sequence.some( |
| 32 | (step) => scopedSteps.has(step) && matchesKeyboardEvent(event, step) |
| 33 | ) |
| 34 | if (matches) return true |
| 35 | } |
| 36 | |
| 37 | return false |
| 38 | } |