TagsInput
Marcadores da nota
Enter fecha a ficha; apagar com o campo vazio tira a última.
import { TagsInput } from '@rivocode/ui'Quando usar
Lista de marcadores que a pessoa escreve: etiquetas de uma nota, palavras de um filtro, emails de um convite.
Três gestos que a peça resolve de uma vez, para não serem resolvidos cinco vezes diferentes: o Enter fecha a ficha, o Backspace com o campo vazio tira a última (é o gesto que todo mundo tenta primeiro) e a repetida não entra duas vezes, porque marcar duas vezes a mesma coisa nunca é o que se quis. Sair do campo também fecha o que estava escrito: texto digitado e não fechado some ao enviar o formulário, e ninguém entende por quê.
Guarda a própria lista quando recebe só defaultValue, e obedece à de fora
quando recebe value, o mesmo par das outras peças de formulário. Num
formulário que envia, controle: quem guarda a lista é o app, porque é ele que a
manda. Num filtro de tela, que não envia nada, defaultValue poupa o
useState.
<TagsInput defaultValue={['nf-e']} aria-label="Palavras do filtro" />
O rótulo
Embrulhe num Field com FieldLabel, como qualquer campo da casa. O campo de
escrever passa pelo Field.Control: é ele, e não a moldura das fichas, que
recebe o id do rótulo, o aria-describedby da ajuda e do erro, e o
aria-invalid. Clicar no rótulo foca o campo, e a moldura fica vermelha
quando o Field está inválido.
<Field>
<FieldLabel>Marcadores</FieldLabel>
<TagsInput value={tags} onValueChange={setTags} placeholder="Escreva e tecle Enter" />
<FieldDescription>Enter fecha a ficha.</FieldDescription>
</Field>
O placeholder não é rótulo: ele some no instante em que a pessoa digita, e
vários leitores de tela não o anunciam. Fora de um Field, dê aria-label.
O anel de foco é do campo de escrever, e não da moldura. O xis de cada ficha tem anel próprio, e os dois nunca acendem juntos.
O nome do xis
Cada ficha diz o que se remove: labels.remove recebe o texto dela e devolve o
nome que o leitor de tela ouve. Sem isso, uma fila de fichas se anuncia
"Remover, Remover, Remover", e quem depende do leitor não sabe qual botão é
qual.
<TagsInput
defaultValue={['nf-e']}
aria-label="Marcadores"
labels={{ remove: (tag) => `Tirar o marcador ${tag}` }}
/>
Movimento
Só a ficha que chega depois cresce ao entrar (animate-pop, --rc-duration-fast). As que já vinham no valor nascem paradas: elas são o formulário, e não algo que acabou de acontecer.
Quando não usar
Quando as opções já existem, use Combobox com multiple e as fichas: ele
mostra o catálogo antes de deixar escolher. O TagsInput é para quando a lista
nasce do que se digita e não há o que sugerir.
No React Native
Traduz, com um gesto a menos. O Enter fecha a ficha e o separador digitado também, mas ele é lido no texto, e não na tecla, porque o onKeyPress do Android não chega para o teclado do sistema. É esse mesmo evento que faltava para o Backspace com o campo vazio tirar a última ficha, e por isso ele não porta: no celular a ficha se tira pelo xis, que já precisava existir para o dedo. O resto é igual: a peça é controlada, a repetida não entra duas vezes e sair do campo fecha o que estava meio escrito.
API
| Prop | Tipo |
|---|---|
classNames0.5.0Classe por parte: `field`, `tag`, `remove`, `input`. | Partial<Record<"field""input""remove""tag", string>> |
defaultValueAs fichas do primeiro desenho, quando a peca guarda a propria lista. | string[] |
labelsO que o leitor de tela ouve nos botoes da peca. | { remove?: ((tag: string) => string) | undefined; } |
onValueChange0.5.0Avisado com a lista inteira a cada ficha que entra ou sai. | ((value: string[]) => void) |
separators0.5.0O que fecha uma ficha alem do Enter. | string[] |
value0.5.0As fichas de agora, quando quem usa guarda a lista. | string[] |
Além destas, a peça aceita className, style, id e children, repassados ao elemento de baixo.