zidane-ui/ keybindings/ headless
import { … } from 'zidane-ui/keybindings/headless'ui/src/keybindings/headless/index.ts
Functions#
bindingAllowedInFunction#
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).
function bindingAllowedIn(
scope: KeyScope,
spec: ParsedBinding,
action?: string,
): booleanParameters
| Name | Type | Description |
|---|---|---|
| scope | KeyScope | Who owns the press. |
| spec | ParsedBinding | The binding. |
| action? | string | The binding's action ( |
Returns
booleanbindingAlternativesFunction#
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).
function bindingAlternatives(spec: string | null | undefined): string[]Parameters
| Name | Type | Description |
|---|---|---|
| spec | string | null | undefined | Binding spec, possibly listing several chords separated by |
Returns
string[]createKeybindingOverridesFunction#
The overrides store over a read: what a host's overrides and refresh are.
function createKeybindingOverrides(
read: () => Promise<unknown>,
): KeybindingOverridesStateParameters
| Name | Type | Description |
|---|---|---|
| read | () => Promise<unknown> | Reads the stored map (rejects or answers nothing when there is none). |
Returns
createKeyCommandRegistryFunction#
A registry with no parts: what the dispatcher reads until something registers.
function createKeyCommandRegistry(): KeyCommandRegistryReturns
filterOverridesFunction#
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.
function filterOverrides(raw: unknown): KeyOverridesParameters
| Name | Type | Description |
|---|---|---|
| raw | unknown | What was stored (anything). |
Returns
getMergedKeybindingsFunction#
The bindings in effect: DEFAULT_KEYBINDINGS with the host's overrides on top.
function getMergedKeybindings(
host?: { overrides: Readable<Readonly<Partial<Record<KeyAction, string>>>> } | null,
): KeyBindingsParameters
Returns
isTypingFocusedFunction#
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).
function isTypingFocused(): booleanReturns
booleanisTypingTargetFunction#
True when the key press belongs to a surface the user is typing in.
function isTypingTarget(event: Event): booleanParameters
| Name | Type | Description |
|---|---|---|
| event | Event | The key event. |
Returns
booleankeyScopeOfFunction#
parseBindingSpecFunction#
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).
function parseBindingSpec(spec: string | null | undefined): ParsedBinding | nullParameters
| Name | Type | Description |
|---|---|---|
| spec | string | null | undefined | Binding spec, possibly listing several chords separated by |
Returns
ParsedBinding | nullparseBindingSpecsFunction#
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).
function parseBindingSpecs(spec: string | null | undefined): ParsedBinding[]Parameters
| Name | Type | Description |
|---|---|---|
| spec | string | null | undefined | Binding spec, possibly listing several chords separated by |
Returns
Constants#
DEFAULT_KEYBINDINGSConstant#
The default spec per action.
const DEFAULT_KEYBINDINGS: KeyBindingsDEFAULT_KEYBINDINGS_LABELSConstant#
The default English strings of the keybindings components.
const DEFAULT_KEYBINDINGS_LABELS: { keyHintOr: string }KEYBINDING_DEF_BY_ACTIONConstant#
The catalog by action.
const KEYBINDING_DEF_BY_ACTION: Readonly<Record<KeyAction, KeyBindingDef>>KEYBINDING_DEFSConstant#
The catalog, in display order.
const KEYBINDING_DEFS: readonly KeyBindingDef[]KEYSCOPE_ATTRConstant#
The attribute an editor host sets (data-zg-keyscope="editor") to own its keys.
const KEYSCOPE_ATTR = 'data-zg-keyscope'Interfaces#
KeyBindingDefInterface#
One action of the catalog.
interface KeyBindingDefProperties
| Name | Type | Description |
|---|---|---|
| action | KeyAction | The action. |
| default | string | Its default spec ( |
| 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 ( |
KeybindingOverridesStateInterface#
A host's overrides store and the read that fills it.
interface KeybindingOverridesStateKeybindingsHostInterface#
The keybindings host.
interface KeybindingsHostProperties
| Name | Type | Description |
|---|---|---|
| overrides | Readable<Readonly<Partial<Record<KeyAction, string>>>> | The overrides: |
| 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. |
KeyCommandRegistryInterface#
The merged handlers of every registered part.
interface KeyCommandRegistry extends Readable<KeyCommands>Properties
| Name | Type | Description |
|---|---|---|
| actions | () => string | The bound actions, in merge order (the first action matching a chord wins). One string per set: compare it. |
getfrom Readable | () => T | 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. |
subscribefrom Readable | (onChange: () => void) => () => void | Registers a listener called after the value changes. Returns a function that removes the listener. |
KeyCommandSlotInterface#
One part's handlers in a KeyCommandRegistry.
interface KeyCommandSlotProperties
| Name | Type | Description |
|---|---|---|
| dispose | () => void | Removes this part's handlers. |
| set | (commands: KeyCommands) => void | Replaces this part's handlers. |
ParsedBindingInterface#
Parsed shape of a "ctrl+shift+o" spec.
interface ParsedBindingProperties
| Name | Type | Description |
|---|---|---|
| alt | boolean | Whether |
| ctrl | boolean | Whether |
| meta | boolean | Whether |
| name | string | The key name (e.g. |
| shift | boolean | Whether |
Types#
KeyActionType#
Every action a key binding can fire.
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'KeyBindingsType#
A spec per action.
type KeyBindings = Record<KeyAction, string>KeybindingsLabelsType#
The shape of the keybindings label dictionary.
type KeybindingsLabels = typeof DEFAULT_KEYBINDINGS_LABELSKeyCommandsType#
A handler per action.
type KeyCommands = Partial<Record<KeyAction, () => void>>KeyOverridesType#
The user's specs per action, over the defaults. Only known actions with a non-empty spec.
type KeyOverrides = Readonly<Partial<Record<KeyAction, string>>>KeyScopeType#
Who owns a key press: the code editor, a text field, an open menu, or the app.
type KeyScope = 'editor' | 'input' | 'menu' | 'app'