# zidane-ui/keybindings/headless

Import: `import { … } from 'zidane-ui/keybindings/headless'`. Source: [ui/src/keybindings/headless/index.ts](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/index.ts).

## Functions

### `bindingAllowedIn`

Function.

Whether an app-level binding may fire under `scope`. In the editor,
`ctrl+<letter>` without shift belongs to the editor (movement and
editing chords), and so do `cmd+[` / `cmd+]` (indent). In the editor and
text fields, an arrow with ⌘ or ⌥ alone (shift or not) moves the caret.
Everything else with shift, meta or a non-letter key is an app intent
(settings, panels, zoom).

```ts
function bindingAllowedIn(
  scope: KeyScope,
  spec: ParsedBinding,
  action?: string,
): boolean
```

**Parameters**

- `scope` (`KeyScope`): Who owns the press.
- `spec` (`ParsedBinding`): The binding.
- `action?` (`string`): The binding's action (`closeTab` fires everywhere).

**Returns** `boolean`

Source: [ui/src/keybindings/headless/key-scope.ts:93](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/key-scope.ts#L93)

### `bindingAlternatives`

Function.

The app's keyboard actions: the catalog (`KEYBINDING_DEFS`, one default
spec, label and description per action) and the default map.

It shares the TUI's action names and spec grammar, and adds the desktop
app's own actions. The grammar (`parseBindingSpec`, aliases, `|`
alternatives) is core's, from `zidane/chat/pure`, so a `keybindings.json`
parses the same on both surfaces. The user's overrides come from the host
(`KeybindingsHost.overrides`); `getMergedKeybindings` layers them over
`DEFAULT_KEYBINDINGS`. The DOM matcher is `matchesBinding` (`zidane-ui/keybindings`).

```ts
function bindingAlternatives(spec: string | null | undefined): string[]
```

**Parameters**

- `spec` (`string | null | undefined`): Binding spec, possibly listing several chords separated by `|`.

**Returns** `string[]`

Source: [dist/index-Bq87OcGy.d.ts:24915](https://github.com/Tahul/zidane/blob/main/dist/index-Bq87OcGy.d.ts#L24915)

### `createKeybindingOverrides`

Function.

The overrides store over a read: what a host's `overrides` and `refresh` are.

```ts
function createKeybindingOverrides(
  read: () => Promise<unknown>,
): KeybindingOverridesState
```

**Parameters**

- `read` (`() => Promise<unknown>`): Reads the stored map (rejects or answers nothing when there is none).

**Returns** `KeybindingOverridesState`

Source: [ui/src/keybindings/headless/overrides.ts:40](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/overrides.ts#L40)

### `createKeyCommandRegistry`

Function.

A registry with no parts: what the dispatcher reads until something registers.

```ts
function createKeyCommandRegistry(): KeyCommandRegistry
```

**Returns** `KeyCommandRegistry`

Source: [ui/src/keybindings/headless/commands.ts:37](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/commands.ts#L37)

### `filterOverrides`

Function.

The known actions of a stored map, each with a non-empty spec. Entries a future build wrote are dropped, so the
matcher never parses them.

```ts
function filterOverrides(raw: unknown): KeyOverrides
```

**Parameters**

- `raw` (`unknown`): What was stored (anything).

**Returns** `KeyOverrides`

Source: [ui/src/keybindings/headless/overrides.ts:15](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/overrides.ts#L15)

### `getMergedKeybindings`

Function.

The bindings in effect: `DEFAULT_KEYBINDINGS` with the host's overrides on top.

```ts
function getMergedKeybindings(
  host?: { overrides: Readable<Readonly<Partial<Record<KeyAction, string>>>> } | null,
): KeyBindings
```

**Parameters**

- `host?` (`{ overrides: Readable<Readonly<Partial<Record<KeyAction, string>>>> } | null`): The host whose overrides apply; none: the defaults.

**Returns** `KeyBindings`

Source: [ui/src/keybindings/headless/overrides.ts:62](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/overrides.ts#L62)

### `isTypingFocused`

Function.

True when the focused element takes the user's typing, so moving focus
would swallow keystrokes. Walks into shadow roots (the editor's host is
`document.activeElement` while its inner content holds the caret).

```ts
function isTypingFocused(): boolean
```

**Returns** `boolean`

Source: [ui/src/keybindings/headless/key-scope.ts:63](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/key-scope.ts#L63)

### `isTypingTarget`

Function.

True when the key press belongs to a surface the user is typing in.

```ts
function isTypingTarget(event: Event): boolean
```

**Parameters**

- `event` (`Event`): The key event.

**Returns** `boolean`

Source: [ui/src/keybindings/headless/key-scope.ts:50](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/key-scope.ts#L50)

### `keyScopeOf`

Function.

Who owns a key press, from its composed path.

```ts
function keyScopeOf(event: Event): KeyScope
```

**Parameters**

- `event` (`Event`): The key event.

**Returns** `KeyScope`

Source: [ui/src/keybindings/headless/key-scope.ts:29](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/key-scope.ts#L29)

### `parseBindingSpec`

Function.

The app's keyboard actions: the catalog (`KEYBINDING_DEFS`, one default
spec, label and description per action) and the default map.

It shares the TUI's action names and spec grammar, and adds the desktop
app's own actions. The grammar (`parseBindingSpec`, aliases, `|`
alternatives) is core's, from `zidane/chat/pure`, so a `keybindings.json`
parses the same on both surfaces. The user's overrides come from the host
(`KeybindingsHost.overrides`); `getMergedKeybindings` layers them over
`DEFAULT_KEYBINDINGS`. The DOM matcher is `matchesBinding` (`zidane-ui/keybindings`).

```ts
function parseBindingSpec(spec: string | null | undefined): ParsedBinding | null
```

**Parameters**

- `spec` (`string | null | undefined`): Binding spec, possibly listing several chords separated by `|`.

**Returns** `ParsedBinding | null`

Source: [dist/index-Bq87OcGy.d.ts:24928](https://github.com/Tahul/zidane/blob/main/dist/index-Bq87OcGy.d.ts#L24928)

### `parseBindingSpecs`

Function.

The app's keyboard actions: the catalog (`KEYBINDING_DEFS`, one default
spec, label and description per action) and the default map.

It shares the TUI's action names and spec grammar, and adds the desktop
app's own actions. The grammar (`parseBindingSpec`, aliases, `|`
alternatives) is core's, from `zidane/chat/pure`, so a `keybindings.json`
parses the same on both surfaces. The user's overrides come from the host
(`KeybindingsHost.overrides`); `getMergedKeybindings` layers them over
`DEFAULT_KEYBINDINGS`. The DOM matcher is `matchesBinding` (`zidane-ui/keybindings`).

```ts
function parseBindingSpecs(spec: string | null | undefined): ParsedBinding[]
```

**Parameters**

- `spec` (`string | null | undefined`): Binding spec, possibly listing several chords separated by `|`.

**Returns** `ParsedBinding[]`

Source: [dist/index-Bq87OcGy.d.ts:24921](https://github.com/Tahul/zidane/blob/main/dist/index-Bq87OcGy.d.ts#L24921)

## Constants

### `DEFAULT_KEYBINDINGS`

Constant.

The default spec per action.

```ts
const DEFAULT_KEYBINDINGS: KeyBindings
```

Source: [ui/src/keybindings/headless/catalog.ts:370](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/catalog.ts#L370)

### `DEFAULT_KEYBINDINGS_LABELS`

Constant.

The default English strings of the keybindings components.

```ts
const DEFAULT_KEYBINDINGS_LABELS: { keyHintOr: string }
```

Source: [ui/src/keybindings/headless/labels.ts:8](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/labels.ts#L8)

### `KEYBINDING_DEF_BY_ACTION`

Constant.

The catalog by action.

```ts
const KEYBINDING_DEF_BY_ACTION: Readonly<Record<KeyAction, KeyBindingDef>>
```

Source: [ui/src/keybindings/headless/catalog.ts:376](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/catalog.ts#L376)

### `KEYBINDING_DEFS`

Constant.

The catalog, in display order.

```ts
const KEYBINDING_DEFS: readonly KeyBindingDef[]
```

Source: [ui/src/keybindings/headless/catalog.ts:75](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/catalog.ts#L75)

### `KEYSCOPE_ATTR`

Constant.

The attribute an editor host sets (`data-zg-keyscope="editor"`) to own its keys.

```ts
const KEYSCOPE_ATTR = 'data-zg-keyscope'
```

Source: [ui/src/keybindings/headless/key-scope.ts:20](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/key-scope.ts#L20)

## Interfaces

### `KeyBindingDef`

Interface.

One action of the catalog.

```ts
interface KeyBindingDef
```

**Properties**

- `action` (`KeyAction`): The action.
- `default` (`string`): Its default spec (`cmd+k`, `ctrl+w | cmd+w`); `''` for unbound.
- `description` (`string`): What it does.
- `label` (`string`): Its short name.
- `urgent?` (`true`): Its state updates render before the next key. Without it they render as a transition (`bindKeyListeners`), so a
  shortcut that redraws much of the window ends its keydown at once and never holds up a frame or a keystroke. Set
  it on an action that moves the focus or opens what the next key goes to (a dialog, the palette, a terminal, a
  new chat's composer), since a key typed before that rendered would land where the focus was; and on a copy,
  which confirms at once.

Source: [ui/src/keybindings/headless/catalog.ts:55](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/catalog.ts#L55)

### `KeybindingOverridesState`

Interface.

A host's overrides store and the read that fills it.

```ts
interface KeybindingOverridesState
```

**Properties**

- `overrides` (`Readable<Readonly<Partial<Record<KeyAction, string>>>>`): The overrides: `{}` until read.
- `refresh` (`() => Promise<void>`): Reads them, keeps the known actions and announces them (also when unchanged). A failed read is none.

Source: [ui/src/keybindings/headless/overrides.ts:28](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/overrides.ts#L28)

### `KeybindingsHost`

Interface.

The keybindings host.

```ts
interface KeybindingsHost
```

**Properties**

- `overrides` (`Readable<Readonly<Partial<Record<KeyAction, string>>>>`): The overrides: `{}` until read.
- `location?` (`() => Promise<string>`): Where the overrides live, to show (a path). Absent: not shown.
- `openInEditor?` (`() => Promise<void>`): Opens the file the overrides live in with the user's editor. Absent: no such file.
- `refresh` (`() => Promise<void>`): Reads the overrides again and tells subscribers. Never rejects: missing or unreadable reads as none.
- `save?` (`(overrides: Readonly<Record<string, string>>) => Promise<void>`): Replaces the overrides (action → spec), then reads them back. Absent: read-only.

Source: [ui/src/keybindings/headless/host.ts:18](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/host.ts#L18)

### `KeyCommandRegistry`

Interface.

The merged handlers of every registered part.

```ts
interface KeyCommandRegistry extends Readable<KeyCommands>
```

**Properties**

- `actions` (`() => string`): The bound actions, in merge order (the first action matching a chord wins). One string per set: compare it.
- `get` (`() => T`, from `Readable`): Returns the current value.
- `register` (`(commands?: Partial<Record<KeyAction, () => void>>) => KeyCommandSlot`): Adds a part. Parts merge in the order they registered: an action an earlier part binds keeps its place, a later
  part's handler for it wins.
- `subscribe` (`(onChange: () => void) => () => void`, from `Readable`): Registers a listener called after the value changes. Returns a function that removes the listener.

Source: [ui/src/keybindings/headless/commands.ts:24](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/commands.ts#L24)

### `KeyCommandSlot`

Interface.

One part's handlers in a [`KeyCommandRegistry`](https://zidane.si/docs/reference/ui-keybindings-headless.md#KeyCommandRegistry).

```ts
interface KeyCommandSlot
```

**Properties**

- `dispose` (`() => void`): Removes this part's handlers.
- `set` (`(commands: KeyCommands) => void`): Replaces this part's handlers.

Source: [ui/src/keybindings/headless/commands.ts:16](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/commands.ts#L16)

### `ParsedBinding`

Interface.

Parsed shape of a `"ctrl+shift+o"` spec.

```ts
interface ParsedBinding
```

**Properties**

- `alt` (`boolean`): Whether `alt` (or `option`) is held.
- `ctrl` (`boolean`): Whether `ctrl` is held.
- `meta` (`boolean`): Whether `meta` (`cmd`, `super`, or `win`) is held.
- `name` (`string`): The key name (e.g. `'o'`, `'tab'`, `'escape'`). Always lowercase.
- `shift` (`boolean`): Whether `shift` is held.

Source: [dist/index-Bq87OcGy.d.ts:24890](https://github.com/Tahul/zidane/blob/main/dist/index-Bq87OcGy.d.ts#L24890)

## Types

### `KeyAction`

Type.

Every action a key binding can fire.

```ts
type KeyAction =
  | 'openSettings'
  | 'openSessionDetails'
  | 'openModelPicker'
  | 'openEffortPicker'
  | 'openTodos'
  | 'openArtifacts'
  | 'openMainSession'
  | 'openUsagePanel'
  | 'newSession'
  | 'openKeybindings'
  | 'openPalette'
  | 'cancelToolCall'
  | 'cycleAgent'
  | 'enterSelectTurnMode'
  | 'toggleSidebar'
  | 'navigateBack'
  | 'navigateForward'
  | 'sessionGenerateTitle'
  | 'sessionCompact'
  | 'sessionExportMarkdown'
  | 'sessionExportJson'
  | 'sessionDelete'
  | 'sessionCopyId'
  | 'sessionFavorite'
  | 'zoomIn'
  | 'zoomOut'
  | 'zoomReset'
  | 'panelNext'
  | 'panelPrev'
  | 'tabNext'
  | 'tabPrev'
  | 'closeTab'
  | 'toggleTerminal'
  | 'newTerminal'
  | 'annotatePage'
  | 'splitTabRight'
  | 'splitTabDown'
```

Source: [ui/src/keybindings/headless/catalog.ts:15](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/catalog.ts#L15)

### `KeyBindings`

Type.

A spec per action.

```ts
type KeyBindings = Record<KeyAction, string>
```

Source: [ui/src/keybindings/headless/catalog.ts:367](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/catalog.ts#L367)

### `KeybindingsLabels`

Type.

The shape of the keybindings label dictionary.

```ts
type KeybindingsLabels = typeof DEFAULT_KEYBINDINGS_LABELS
```

Source: [ui/src/keybindings/headless/labels.ts:14](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/labels.ts#L14)

### `KeyCommands`

Type.

A handler per action.

```ts
type KeyCommands = Partial<Record<KeyAction, () => void>>
```

Source: [ui/src/keybindings/headless/commands.ts:13](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/commands.ts#L13)

### `KeyOverrides`

Type.

The user's specs per action, over the defaults. Only known actions with a non-empty spec.

```ts
type KeyOverrides = Readonly<Partial<Record<KeyAction, string>>>
```

Source: [ui/src/keybindings/headless/host.ts:15](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/host.ts#L15)

### `KeyScope`

Type.

Who owns a key press: the code editor, a text field, an open menu, or the app.

```ts
type KeyScope = 'editor' | 'input' | 'menu' | 'app'
```

Source: [ui/src/keybindings/headless/key-scope.ts:17](https://github.com/Tahul/zidane/blob/main/ui/src/keybindings/headless/key-scope.ts#L17)
