useKeymapによるキーボードショートカット
useKeymapでキー割り当てを一度宣言すると、Text.jsがキー入力を振り分け、?ヘルプ画面に掲載し、フッターに表示し、Ctrl+Kコマンドパレットに追加します。
これまで、Text.jsアプリでは useInput でキーを処理し、同じキーを <KeyHint> フッターにも手作業で記載していました。useKeymap は、この両方を1つの宣言に置き換えます。
import { CommandPalette, KeyHelp, KeyHints, StatusBar, Text, useKeymap } from "@textjs/react";export default function Sessions() { useKeymap( { "j, down": { label: "Next", run: next, hint: true }, "k, up": { label: "Previous", run: previous }, "g g": { label: "Go to top", run: top }, "ctrl+s": { label: "Save", run: save, hint: true }, }, { group: "Navigation" }, ); return ( <> <StatusBar right={<Text color="subtle">main</Text>}> <KeyHints /> </StatusBar> <CommandPalette commands={commands} /> <KeyHelp /> </> );}j を押すと next が実行されます。macOSでは、これらのバインディングに hint が設定されているため、<KeyHints> がフッターに j/↓ Next と ⌃S Save を表示します。? は4つすべてをNavigationグループにまとめたヘルプ画面を開き、Ctrl+K はそれらを検索できるパレットを開きます。
キーの構文
| 構文 | 意味 |
|---|---|
ctrl+k | 修飾キー:ctrl、alt、shift、meta、mod |
mod+k | ⌘ または Ctrl のうち押されている方 |
j, down | いずれかのキー |
g g | キー間の間隔が最大1秒のシーケンス |
G | 大文字は Shift を含む指定 |
? | 入力可能なキーは文字と照合 |
バインディングは、ハンドラー、または label、group、hint、command、disabled、noRepeat を持つオブジェクトです。command: false を指定すると、ラベル付きのバインディングがパレットから除外されます。ラベルのないバインディングも動作しますが、ヘルプ画面とパレットには表示されません。
ルーティング
各キーマップは1つの useInput ハンドラーを登録するため、既存の入力ルールが適用されます。エディターは優先度10、キーマップは0で入力を受け取るため、フォーカスされた <Input> が先にキーを処理します。一致したキーは伝播を停止します。<Modal> が開いていると、その外側のバインディングは無効になります。ただし、キーマップが global: true を渡している場合は除きます。
シーケンスは、そのハンドラー内で照合されます。シーケンスを開始するキーは保留状態で保持され、伝播を停止し、次のキーが sequenceTimeout(デフォルトで1,000ms)を超えてから届くとシーケンスがリセットされます。
if (p.events.length > 0 && now - p.at > sequenceTimeout) p.events = [];ルートごとに1つのレジストリー
ラベル付きのバインディングは、コンソールのルートに属するレジストリーに公開されます。<KeyHelp>、<KeyHints>、<CommandPalette> はそこから読み取り、独自のコンポーネントでも useKeymapBindings() を通じて読み取れます。モーダルが開いている間、レジストリーはその内側のバインディングだけを返すため、ヘルプ画面にはその時点で使えるキーが表示されます。
キーマップは通常インラインで記述するため、レンダーのたびに新しいオブジェクトが作られます。このコストを抑えるため、キーマップは表示内容が変わったときだけラベルを再公開します。
// Publish labels only when the visible shape changes (inline keymap objects are fine).const signature = compiled .map((c) => `${c.keys}\u0000${c.binding.label ?? ""}\u0000${c.binding.group ?? ""}\u0000${c.binding.hint ? 1 : 0}${c.binding.command === false ? 0 : 1}\u0000${c.binding.disabled ? 1 : 0}`) .join("\u0001");キーが届いた時点でrefからハンドラーを読み取るため、レンダーごとに作られる新しいクロージャーが古くなることはありません。
ヘルプ画面とパレット
<KeyHelp> は ? で開き、有効なラベル付きバインディングをすべてグループ別に表示します。keys と title でトリガーと見出しを変更できます。
<CommandPalette> は Ctrl+K または Ctrl+P で開きます。commands とすべてのラベル付きバインディングをあいまい検索し、一致した文字を強調表示します。コマンドを実行する前に閉じるため、コマンドから独自のモーダルを開けます。
formatKeys は、バインディングを表示用に整形します。formatKeys("ctrl+shift+p") はmacOSでは ⌃⇧P、それ以外では ctrl+shift+P を返し、<Kbd> は同じ形式で単一のキーを表示します。
useKeymap、<KeyHelp>、<KeyHints>、<StatusBar>、<CommandPalette> はText.js 1.0に含まれています。リファレンスはキーボードにあります。