API Reference
keybinds(commands, getContext?, options?)
Main entry point. Registers keyboard and mouse listeners.
function keybinds(
commands: Command[],
getContext?: () => Record<string, unknown>,
options?: { target?: EventTarget, onExecute?: (cmd, ctx) => void }
): () => voidReturns: Cleanup function to remove listeners.
const cleanup = keybinds(commands, () => ({ editing: false }))
// Later:
cleanup()searchCommands(commands, query, context?)
Search commands for palette display.
function searchCommands(
commands: Command[],
query: string,
context?: Record<string, unknown>
): ScoredCommand[]Returns commands matching query, sorted by relevance. Each result includes active (boolean) and score (number).
groupByCategory(commands, context?)
Group commands by category for cheatsheet display.
function groupByCategory(
commands: Command[],
context?: Record<string, unknown>
): Record<string, (Command & { active: boolean })[]>executeCommand(commands, id, context?)
Execute a command by ID.
function executeCommand(
commands: Command[],
id: string,
context?: Record<string, unknown>
): booleanReturns true if command was found and executed.
validateCommands(commands)
Validate all command bindings upfront.
function validateCommands(commands: Command[]): trueThrows if any binding is invalid. Call on init to catch typos early.
formatKey(key)
Format key binding for display.
function formatKey(key: string): stringformatKey('$mod+k') // "⌘K" on Mac, "CTRLK" on Windows
formatKey('Escape') // "ESC"defineSchema(schema)
Identity function for type inference when defining binding schemas.
function defineSchema<T extends Schema>(schema: T): Tconst schema = defineSchema({
save: { label: 'Save', keys: ['$mod+s'] },
})mergeBindings(schema, overrides)
Merge schema with user overrides.
function mergeBindings(
schema: Schema,
overrides: BindingOverrides
): SchemafromBindings(bindings, handlers, options?)
Create commands from bindings + handlers.
function fromBindings(
bindings: Schema,
handlers: Record<string, (ctx, event?) => unknown>,
options?: Record<string, { when?: (ctx) => boolean, captureInput?: boolean }>
): Command[]listBindings(schema)
Get all bindings as flat list for settings UI.
function listBindings(schema: Schema): Array<BindingSchema & { id: string }>BindingsStore
Reactive store with localStorage persistence.
class BindingsStore<T extends Schema> extends EventTarget {
constructor(schema: T, storageKey: string)
get(): T
getOverrides(): BindingOverrides
save(overrides: BindingOverrides): void
}Dispatches 'change' event when bindings are saved.
const store = new BindingsStore(schema, 'app:keybinds')
store.addEventListener('change', (e) => {
console.log(e.detail.bindings)
})
store.save({ save: { keys: ['$mod+Shift+s'] } })eventToBindingString(event)
Convert a KeyboardEvent to a canonical binding string.
function eventToBindingString(event: KeyboardEvent): string | nullReturns null for bare modifier presses and unknown keys.
// In a keydown handler:
const binding = eventToBindingString(event) // e.g. "$mod+shift+k"eventToMouseBindingString(event)
Convert a MouseEvent or WheelEvent to a canonical binding string.
function eventToMouseBindingString(event: MouseEvent): string | null// In a mousedown handler:
const binding = eventToMouseBindingString(event) // e.g. "$mod+click"
// Also works with WheelEvent:
const scroll = eventToMouseBindingString(wheelEvent) // e.g. "$mod+scrollup"findConflict(schema, bindingStr, type, excludeId?)
Check if a binding conflicts with any command in a schema.
function findConflict(
schema: Schema,
bindingStr: string,
type: 'keys' | 'mouse',
excludeId?: string
): { commandId: string, label: string } | nullconst conflict = findConflict(schema, '$mod+s', 'keys', 'save')
if (conflict) {
console.log(`Conflicts with ${conflict.label}`)
}Types
interface Command {
id: string
label: string
description?: string
category?: string
keys?: string[]
mouse?: string[]
when?: (ctx: Record<string, unknown>) => boolean
execute: (ctx: Record<string, unknown>, event?: Event) => unknown
hidden?: boolean
captureInput?: boolean
menu?: string | string[]
}
interface ScoredCommand extends Command {
active: boolean
score: number
}
interface BindingSchema {
label: string
description?: string
category?: string
keys?: string[]
mouse?: string[]
hidden?: boolean
}
type Schema = Record<string, BindingSchema>
type BindingOverrides = Record<string, { keys?: string[], mouse?: string[] }>