Criar uma entrada personalizada

Neste guia, vamos percorrer o processo de criação, registro e uso de uma entrada personalizada. Especificamente, vamos criar uma entrada de "senha de uso único" ("OTP" para abreviar). As OTPs são comumente usadas para autenticação de dois fatores quando um usuário precisa digitar um código enviado via SMS ou aplicativo autenticador. Vamos começar!

Ferramenta de construção SFC

Este guia pressupõe que você está usando uma ferramenta de construção Vue 3 padrão como Vite, Nuxt 3 ou Vue CLI que permitirá que você importe componentes de arquivo único .vue.

Criando um componente

Para começar, vamos criar o arquivo de componente da nossa entrada. Vamos chamá-lo de OneTimePassword.vue:

<script setup>
  const props = defineProps({
    context: Object,
  })
</script>

<template>
  <div>Mais por vir aqui...</div>
</template>

O FormKit fornece muitos recursos de entrada prontos para uso que vamos querer preservar - como rótulos, texto de ajuda e exibição de mensagens de erro. Tudo o que realmente queremos modificar é a seção de entrada da nossa entrada. Podemos preservar esses recursos padrão do FormKit usando a função utilitária createInput do pacote @formkit/vue.

Conforme construímos nossa entrada, vamos querer visualizar seu progresso, então vamos criar um formulário de amostra para:

  1. Importar OneTimePassword.vue
  2. Passar esse componente importado para createInput()
  3. Usar o valor de retorno (uma definição de entrada) como a prop type de um componente <FormKit>.

Vamos chamar este formulário de amostra de Register.vue:

Carregar exemplo ao vivo

Excelente! Agora podemos iterar em nosso arquivo OneTimePassword.vue e ver os resultados. Uma das primeiras coisas a notar é como nossa entrada já suporta rótulos, texto de ajuda, validação e outras props universais do FormKit. Esses recursos são cortesia de createInput().

Além disso, notou aquela tag <pre> no exemplo acima? Ela está exibindo o estado atual dos dados do formulário. Vamos usar isso para visualizar o valor da nossa entrada personalizada. Como nossa entrada atualmente não tem valor, ela não aparece nos dados do formulário. Hora de mudar isso!

Entrada & saída

Vamos abrir OneTimePassword.vue novamente e mudar nossa tag <div> para uma tag <input>. Vamos começar com uma única entrada de texto e evoluir a partir daí. Mas como realmente definimos e exibimos o valor da nossa entrada personalizada?

Todas as entradas personalizadas recebem o todo-poderoso objeto de contexto como a prop context. Para que nossa entrada possa definir seu valor, ela precisa chamar context.node.input(value). Para exibir corretamente o valor da nossa entrada, devemos definir o atributo :value da entrada para context._value.

Carregar exemplo ao vivo

Nossa pequena entrada cresceu! Pode não parecer bonita, mas agora lê e escreve valores. Como prova, tente definir o valor inicial do objeto values do formulário para { two_factor_code: '12345' } e você verá que a entrada é preenchida automaticamente com o valor.

Requisitos para nossa entrada

Ok, agora que entendemos como criar uma entrada, como usá-la e como ler e escrever valores - vamos abordar a verdadeira "lógica de negócios" de nossa entrada de senha única. Aqui estão nossos requisitos:

  • Os usuários inserem uma série de dígitos, e cada dígito tem sua própria tag <input>.
  • O valor da entrada deve ser sempre todos os dígitos concatenados.
  • Só queremos que a entrada mude seu valor se todos os dígitos estiverem completos (não há necessidade de confirmar e validar a cada tecla pressionada se o usuário não terminou).
  • Deve permitir que um usuário clique em um dígito específico para editá-lo.
  • Quando um usuário digita um número, deve focar automaticamente na próxima entrada.
  • Deve suportar copiar/colar.

Adicionando uma prop

Para nosso primeiro requisito, precisamos de n tags <input>. Talvez seja melhor expor o número de dígitos como uma prop. Para fazer isso, precisamos informar à nossa função createInput que queremos aceitar uma nova prop:

createInput(OneTimePassword, {
  props: ['digits'],
})

Agora temos acesso a context.digits. De volta em OneTimePassword.vue, vamos usar isso para gerar o número correto de tags <input>.

Carregar exemplo ao vivo

OK — temos várias entradas! Nosso primeiro requisito está completo:

  • Os usuários inserem uma série de dígitos, e cada dígito tem sua própria tag <input>.
Estilização

Adicionamos um toque de CSS no exemplo acima, mas em geral não vamos nos aprofundar em estilização neste guia. É recomendado usar context.classes.yourKey como o nome da classe dos elementos em sua entrada.

Interatividade

Perceba no exemplo acima que quando você digita em uma entrada, todas as outras entradas são sincronizadas com o mesmo valor? Bem legal, mas não é o que queremos. Isso ocorre porque ainda estamos usando o mesmo manipulador de entrada e :value. Aqui está um plano para melhorar nossa entrada:

  • Cada entrada deve modificar apenas o caractere em seu respectivo índice na string final.
  • O manipulador de entrada deve chamar focus() na próxima entrada.
  • Quando a string tem o mesmo comprimento que digits, atualizamos o valor da entrada chamando context.node.input().
Carregar exemplo ao vivo

Ótimo! Isso está começando a funcionar como esperamos. Vamos verificar nossos requisitos novamente:

  • Os usuários inserem uma série de dígitos, e cada dígito tem sua própria tag <input>.
  • O valor da entrada deve ser sempre todos os dígitos concatenados.
  • Só queremos que a entrada mude seu valor se todos os dígitos estiverem completos (não há necessidade de confirmar e validar a cada tecla pressionada se o usuário não terminou).
  • Deve permitir que um usuário clique em um dígito específico para editá-lo.
  • Quando um usuário digita um número, deve focar automaticamente na próxima entrada.
  • Deve suportar copiar/colar.

Copiar & colar

Parece que só temos uma coisa a fazer — suporte para copiar & colar. Felizmente, os navegadores possuem um evento paste. Para garantir que nossa experiência do usuário seja de primeira linha, faremos uma suposição: se um usuário está copiando/colando, ele está tentando copiar e colar todo o código. Não um único dígito do código. Parece razoável.

Tudo o que precisamos fazer é capturar o evento de copiar/colar em qualquer uma de nossas tags de entrada, obter o texto que está sendo colado e definir o valor tmp para essa sequência de dígitos. Vamos criar outro manipulador de eventos:

handlePaste(e) {
  const paste = e.clipboardData.getData('text')
  if (typeof paste === 'string') {
    // Se for do tamanho certo, cole.
    this.tmp = paste.substr(0, this.max)
    const inputs = e.target.parentElement.querySelectorAll('input')
    // Foca no último caractere
    inputs.item(this.tmp.length - 1).focus()
  }
}
Carregar exemplo ao vivo

Nossos requisitos estão todos completos!

Registro

Agora que criamos uma excelente entrada, vamos registrá-la em nossa aplicação para que possamos usá-la em qualquer lugar apenas usando a string otp. Abra o arquivo principal da sua aplicação Vue (onde app.use(formKit) está). Vamos apenas adicionar a ele:

import { createApp } from 'Vue'
import App from 'App.vue'
import OneTimePassword from './OneTimePassword.vue'
import { plugin, defaultConfig, createInput } from '@formkit/vue'

const app = createApp(App)
app.use(
  plugin,
  defaultConfig({
    inputs: {
      otp: createInput(OneTimePassword, {
        props: ['digits'],
      }),
    },
  })
)
app.mount('#app')

Pronto! Agora você pode usar sua entrada em qualquer lugar da sua aplicação:

<FormKit type="otp" digits="4" />

Próximos passos

Nossa entrada de senha de uso único está funcionando muito bem! Aqui estão algumas ideias para recursos adicionais que poderíamos desenvolver ainda mais:

  • Uma regra de validação acompanhante para realizar uma chamada de autenticação de dois fatores para o backend.
  • Estilos adicionais para realmente fazê-lo se destacar.
  • Se o formulário contiver apenas uma entrada de senha de uso único, você poderia enviar automaticamente o formulário!
  • Complete a lista de verificação de entrada personalizada.
  • Publique! Se esta entrada (ou qualquer outra que você faça) for útil para você, provavelmente será útil para outras pessoas também. Você pode considerar torná-la open-source!

Esperamos que este guia tenha ajudado você a entender como as entradas personalizadas são declaradas, escritas e registradas. Se você quiser se aprofundar mais, tente ler sobre os princípios internos do FormKit e criando entradas personalizadas!

Quer mais? Comece lendo sobre o núcleo do FormKit.Aprofunde-se