← Blog

Raccourcis clavier avec useKeymap

Déclarez une liaison une seule fois avec useKeymap, et Text.js achemine la touche, la répertorie dans un écran d’aide ?, l’affiche en pied de page et l’ajoute à une palette de commandes Ctrl+K.

Adam

Jusqu’ici, une application Text.js gérait les touches dans useInput et les listait une seconde fois, à la main, dans un pied de page <KeyHint>. useKeymap remplace les deux par une seule déclaration.

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 />    </>  );}

Appuyer sur j exécute next. Sur macOS, <KeyHints> affiche j/↓ Next et ⌃S Save dans le pied de page, car ces associations définissent hint. ? ouvre un écran d’aide avec les quatre associations, regroupées sous Navigation, et Ctrl+K ouvre une palette pour y effectuer des recherches.

Syntaxe des touches

SyntaxeSignification
ctrl+kModificateurs : ctrl, alt, shift, meta et mod
mod+k⌘ ou Ctrl, selon la touche maintenue
j, downAlternatives
g gUne séquence, avec au plus 1 seconde entre les touches
GUne majuscule implique Shift
?Les touches imprimables correspondent au caractère

Une association est un gestionnaire ou un objet avec label, group, hint, command, disabled et noRepeat. command: false exclut de la palette une association dotée d’un libellé. Les associations sans libellé fonctionnent, mais restent absentes de l’écran d’aide et de la palette.

Routage

Chaque keymap enregistre un gestionnaire useInput, les règles de saisie existantes s’appliquent donc. Un <Input> ayant le focus traite les touches en premier, car les éditeurs écoutent à la priorité 10 et les keymaps à la priorité 0. Une touche reconnue arrête la propagation. Un <Modal> ouvert désactive les associations à l’extérieur, sauf si le keymap transmet global: true.

Les séquences sont reconnues dans ce gestionnaire. Une touche qui commence une séquence est mise en attente et arrête la propagation, et la séquence est réinitialisée lorsque la touche suivante arrive après un délai supérieur à sequenceTimeout (1000 ms par défaut) :

if (p.events.length > 0 && now - p.at > sequenceTimeout) p.events = [];

Un registre par racine

Les associations dotées d’un libellé sont publiées dans un registre appartenant à la racine de la console. <KeyHelp>, <KeyHints> et <CommandPalette> le consultent, et vos propres composants peuvent aussi le faire via useKeymapBindings(). Tant qu’une fenêtre modale est ouverte, le registre ne renvoie que les associations qu’elle contient, pour que l’écran d’aide liste les touches utilisables à cet instant.

Les keymaps sont généralement écrits en ligne, ce qui crée un nouvel objet à chaque rendu. Pour limiter ce coût, un keymap ne republie ses libellés que lorsque leur forme visible change :

// 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");

Les gestionnaires sont lus depuis une ref lorsqu’une touche arrive, de sorte qu’une nouvelle fermeture à chaque rendu n’est jamais obsolète.

L’écran d’aide et la palette

<KeyHelp> s’ouvre avec ? et liste par groupe toutes les associations actives dotées d’un libellé. keys et title modifient le déclencheur et le titre.

<CommandPalette> s’ouvre avec Ctrl+K ou Ctrl+P. La recherche approximative porte sur vos commands et toutes les associations dotées d’un libellé, et met en évidence les lettres correspondantes. La palette se ferme avant d’exécuter une commande, pour qu’une commande puisse ouvrir sa propre fenêtre modale.

formatKeys met en forme une association pour l’affichage. formatKeys("ctrl+shift+p") renvoie ⌃⇧P sur macOS et ctrl+shift+P ailleurs, et <Kbd> affiche une touche unique avec la même mise en forme.

useKeymap, <KeyHelp>, <KeyHints>, <StatusBar> et <CommandPalette> sont inclus dans Text.js 1.0. La référence se trouve dans Clavier.