Cmd-K コマンドパレットを60行で再構築してみた
Linear、Raycast、VS Codeといったアプリでは、コマンドパレットが採用されています。⌘Kを押し、数文字入力してEnterを押すだけ。複雑に思えるかもしれませんが、実はわずか60行のJavaScriptで実現できます。
構築方法は以下の通りです:
- キーボードリスナー
グローバルなリスナーが必要です。ブラウザではCtrl+Kが検索機能に割り当てられているため、
preventDefaultを使ってこれを阻止する必要があります。
document.addEventListener("keydown", e => {
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
e.preventDefault();
openPalette();
}
});
- コマンドデータ すべての操作をオブジェクトとして保存します。これによりUIはシンプルに保たれます。UIはこれらのオブジェクトをリスト化し、選択された関数を実行します。新しい機能を追加するには、リストに1行追加するだけです。
const COMMANDS = [
{ icon: "🌙", label: "Toggle dark mode", group: "Theme", run: toggleDark },
{ icon: "📄", label: "New file", group: "File", run: newFile },
];
- ファジー検索 優れたパレットは、部分一致(subsequence matching)を利用します。これは、文字が順番に現れる必要があるものの、連続している必要はないという意味です。「tgldk」と入力すれば「Toggle dark mode」が見つかるようにします。
function fuzzy(q, text) {
let i = 0;
for (const ch of text.toLowerCase()) {
if (ch === q[i]) i++;
}
return i === q.length;
}
キーボードナビゲーション マウスを使わないことが目的です。矢印キーで選択インデックスを変更し、Enterでコマンドを実行、Escapeでメニューを閉じます。
即時性のある操作感 パレットが開いた瞬間に、入力フィールドにフォーカスを当てます。これにより、クリックの手間なくすぐにタイピングできます。
コマンドパレットに必要な要素は4つです:
- グローバルショートカット
- コマンドデータ
- ファジーフィルター
- オートフォーカス
モダンなパワーユーザー向けツールがどのように動作しているのかを理解するために、ぜひ一度作ってみてください。
ライブデモ: https://dev48v.infy.uk/design/day10-command-palette.html
ソース: https://dev.to/dev48v/i-rebuilt-the-cmd-k-command-palette-in-60-lines-of-javascript-3a1l