← Blog

Atalhos de teclado com useKeymap

Declare uma associação uma vez com useKeymap, e Text.js direciona a tecla, lista-a em uma tela de ajuda ?, exibe-a no rodapé e a adiciona a uma paleta de comandos Ctrl+K.

Adam

Até agora, um app Text.js tratava teclas em useInput e as listava uma segunda vez, manualmente, em um rodapé <KeyHint>. useKeymap substitui ambos por uma única declaração.

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

Pressionar j executa next. No macOS, <KeyHints> mostra j/↓ Next e ⌃S Save no rodapé, porque essas associações definem hint. ? abre uma tela de ajuda com as quatro associações, agrupadas em Navigation, e Ctrl+K abre uma paleta que permite buscá-las.

Sintaxe das teclas

SintaxeSignificado
ctrl+kModificadores: ctrl, alt, shift, meta e mod
mod+k⌘ ou Ctrl, conforme a tecla mantida pressionada
j, downAlternativas
g gUma sequência, com até 1 segundo entre as teclas
GMaiúscula implica Shift
?Teclas imprimíveis correspondem ao caractere

Uma associação é um handler ou um objeto com label, group, hint, command, disabled e noRepeat. command: false mantém uma associação com rótulo fora da paleta. Associações sem rótulo funcionam, mas ficam fora da tela de ajuda e da paleta.

Roteamento

Cada mapa de teclas registra um handler useInput, então as regras de entrada existentes se aplicam. Um <Input> com foco trata as teclas primeiro, porque os editores escutam na prioridade 10 e os mapas de teclas na 0. Uma tecla correspondente interrompe a propagação. Um <Modal> aberto desativa as associações fora dele, a menos que o mapa de teclas passe global: true.

As sequências são identificadas dentro desse handler. Uma tecla que inicia uma sequência fica pendente e interrompe a propagação, e a sequência é reiniciada quando a próxima tecla chega após mais de sequenceTimeout (1.000 ms por padrão):

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

Um registro por raiz

As associações com rótulo são publicadas em um registro que pertence à raiz do console. <KeyHelp>, <KeyHints> e <CommandPalette> leem esse registro, e seus próprios componentes também podem lê-lo por meio de useKeymapBindings(). Enquanto um modal está aberto, o registro retorna apenas as associações dentro dele, então a tela de ajuda lista as teclas que funcionam naquele momento.

Os mapas de teclas costumam ser escritos inline, o que cria um novo objeto a cada renderização. Para manter esse custo baixo, um mapa de teclas republica seus rótulos apenas quando sua forma visível muda:

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

Os handlers são lidos de uma ref quando uma tecla chega, então uma nova closure a cada renderização nunca fica desatualizada.

A tela de ajuda e a paleta

<KeyHelp> abre com ? e lista por grupo todas as associações ativas com rótulo. keys e title alteram o acionador e o título.

<CommandPalette> abre com Ctrl+K ou Ctrl+P. Ela faz uma busca aproximada em seus commands e em todas as associações com rótulo, e destaca as letras correspondentes. Ela fecha antes de executar um comando, então um comando pode abrir seu próprio modal.

formatKeys renderiza uma associação para exibição. formatKeys("ctrl+shift+p") retorna ⌃⇧P no macOS e ctrl+shift+P nos demais sistemas, e <Kbd> renderiza uma única tecla com a mesma formatação.

useKeymap, <KeyHelp>, <KeyHints>, <StatusBar> e <CommandPalette> estão incluídos no Text.js 1.0. A referência está em Teclado.