Arquitetura

Introdução

No coração do framework FormKit está o @formkit/core. Este pacote sem dependências é responsável por quase todas as funções críticas de baixo nível do FormKit, tais como:

  • Configuração
  • Entrada/saída de valores
  • Propagação de eventos
  • Gerenciamento de plugins
  • Rastreamento do estado da árvore
  • Gerenciamento de mensagens
  • Ganchos de ciclo de vida

Arquitetura

A funcionalidade do núcleo do FormKit não é exposta à sua aplicação por meio de uma instância centralizada, mas sim por um conjunto distribuído de "nós" (FormKitNode), onde cada nó representa uma única entrada.

Isso espelha o HTML — na verdade, a estrutura do DOM é realmente uma árvore geral e os nós do núcleo do FormKit refletem essa estrutura. Por exemplo, um formulário de login simples poderia ser representado pelo seguinte gráfico de árvore:

Passe o mouse sobre cada nó para ver suas opções iniciais.

Neste diagrama, um nó form é pai de três nós filhos — email, password e submit. Cada componente de entrada no gráfico "possui" um nó do núcleo do FormKit, e cada nó contém suas próprias opções, configurações, props, eventos, plugins, ganchos de ciclo de vida, etc. Esta arquitetura garante que os recursos primários do FormKit sejam desacoplados do framework de renderização (Vue) — chave para reduzir efeitos colaterais e manter um desempenho extremamente rápido.

Além disso, esta arquitetura descentralizada permite uma flexibilidade tremenda. Por exemplo — um formulário pode usar plugins diferentes de outros formulários no mesmo aplicativo, uma entrada de grupo pode modificar a configuração de suas subentradas, e regras de validação podem até ser escritas para usar props de outra entrada.

Cada componente <FormKit> possui um único nó central, e cada nó deve ser um dos três tipos:

Tipos de entrada vs tipos de nó

Os nós centrais são sempre um dos três tipos (input, list ou group). Estes não são os mesmos que tipos de entrada — dos quais pode haver variação ilimitada. Estritamente falando, todas as entradas têm 2 tipos: seu tipo de nó (como input), e seu tipo de entrada (como checkbox).

Input

A maioria das entradas nativas do FormKit tem um tipo de nó input — operam em um único valor. O valor em si pode ser de qualquer tipo, como objetos, arrays, strings e números — qualquer valor é aceitável. No entanto, nós do tipo input são sempre folhas — o que significa que não podem ter filhos.

import { createNode } from '@formkit/core'

const input = createNode({
  type: 'input', // assume 'input' como padrão se não especificado
  value: 'hello node world',
})

console.log(input.value)
// 'hello node world'

Lista

Uma lista é um nó que produz um valor de array. Os filhos de um nó de lista produzem um valor no array da lista. Os nomes dos filhos imediatos são ignorados — em vez disso, cada um é atribuído a um índice no array da lista.

import { createNode } from '@formkit/core'

const list = createNode({
  type: 'list',
  children: [
    createNode({ value: 'paprika@example.com' }),
    createNode({ value: 'bill@example.com' }),
    createNode({ value: 'jenny@example.com' }),
  ],
})

console.log(list.value)
// ['paprika@example.com', 'bill@example.com', 'jenny@example.com']

Grupo

Um grupo é um nó que produz um valor de objeto. Os filhos de um nó de grupo usam seu name para produzir uma propriedade de mesmo nome no objeto de valor do grupo — <FormKit type="form"> é uma instância de um grupo.

import { createNode } from '@formkit/core'

const group = createNode({
  type: 'group',
  children: [
    createNode({ name: 'meat', value: 'turkey' }),
    createNode({ name: 'greens', value: 'salad' }),
    createNode({ name: 'sweets', value: 'pie' }),
  ],
})

console.log(group.value)
// { meat: 'turkey', greens: 'salad', sweets: 'pie' }

Opções

Além de especificar o type de nó ao chamar createNode(), você pode passar qualquer uma das seguintes opções:

OpçõesPadrãoDescrição
children[]Instâncias de FormKitNode filhos.
config{}Opções de configuração. Estas se tornam os padrões do objeto props.
name{type}_{n}O nome do nó/entrada.
parentnullA instância de FormKitNode pai.
plugins[]Um array de funções de plugin.
props{}Um objeto de pares chave/valor que representam os detalhes da instância atual.
typeinputO tipo de FormKitNode a ser criado (list, group ou input).
valueundefinedO valor inicial da entrada.

Config & Props

O FormKit usa um sistema de configuração baseado em herança. Quaisquer valores declarados na opção config são automaticamente passados para os filhos (e todos os descendentes) daquele nó, mas não são passados para irmãos ou pais. Cada nó pode sobrescrever seus valores herdados fornecendo sua própria configuração, e esses valores serão por sua vez herdados por quaisquer filhos mais profundos e descendentes. Por exemplo:

const parent = createNode({
  type: 'group',
  config: {
    color: 'yellow',
  },
  children: [
    createNode({
      type: 'list',
      config: { color: 'pink' },
      children: [createNode(), createNode()],
    }),
    createNode(),
  ],
})

O código acima resultará em cada nó tendo a seguinte configuração:

Observe como a subárvore da lista é rosa.
Use props para ler config

É uma boa prática ler valores de configuração de node.props em vez de node.config. A próxima seção detalha esse recurso.

Props

Os objetos node.props e node.config são intimamente relacionados. node.config é melhor pensado como os valores iniciais para node.props. props é um objeto de forma arbitrária que contém detalhes sobre a atual instância do nó.

A melhor prática é sempre ler dados de configuração e propriedades de node.props, mesmo que o valor original seja definido usando node.config. Props explicitamente definidas têm precedência sobre opções de configuração.

const child = createNode({
  props: {
    flavor: 'cherry',
  },
})
const parent = createNode({
  type: 'group',
  config: {
    size: 'large',
    flavor: 'grape',
  },
  children: [child],
})
console.log(child.props.size)
// outputs: 'large'
console.log(child.props.flavor)
// outputs: 'cherry'
Props de componentes FormKit

Ao usar o componente <FormKit>, quaisquer props definidas para o tipo de entrada type são automaticamente definidas como propriedades de node.props. Por exemplo: <FormKit label="Email" /> resultaria em node.props.label sendo Email.

Definindo valores

Você pode definir o valor inicial de um nó fornecendo a opção value em createNode() — mas o FormKit é todo sobre interatividade, então como atualizamos o valor de um nó já definido? Usando node.input(value).

import { createNode } from '@formkit/core'

const username = createNode()
username.input('jordan-goat98')
console.log(username.value)
// undefined  👀 espera — o quê!?

No exemplo acima, username.value ainda está indefinido imediatamente após ser definido porque node.input() é assíncrono. Se você precisar ler o valor resultante após chamar node.input(), você pode aguardar a promessa retornada.

import { createNode } from '@formkit/core'

const username = createNode()
username.input('jordan-goat98').then(() => {
  console.log(username.value)
  // 'jordan-goat98'
})

Como node.input() é assíncrono, o restante do nosso formulário não precisa recalcular suas dependências a cada tecla pressionada. Isso também fornece uma oportunidade para realizar modificações no valor não confirmado antes de ser "comprometido" com o restante do formulário. No entanto — apenas para uso interno do nó — uma propriedade _value contendo o valor não confirmado da entrada também está disponível.

Não atribua valores

Você não pode atribuir diretamente o valor de uma entrada node.value = 'foo'. Em vez disso, você sempre deve usar node.input(value)

Liquidação de valor

Agora que entendemos que node.input() é assíncrono, vamos explorar como o FormKit resolve o problema da "árvore estabilizada". Imagine um usuário digitando rapidamente seu endereço de e-mail e pressionando "enter" muito rapidamente — submetendo o formulário. Como node.input() é assíncrono, é provável que dados incompletos sejam submetidos. Precisamos de um mecanismo para saber quando o formulário inteiro está "estabilizado".

Para resolver isso, os nós do FormKit rastreiam automaticamente a "perturbação" da árvore, subárvore e nó. Isso significa que o formulário (geralmente o nó raiz) sempre sabe o estado de estabilização de todos os inputs que contém.

O gráfico a seguir ilustra essa "contagem de perturbação". Clique em qualquer nó de input (azul) para simular a chamada de node.input() e perceba como o formulário inteiro está sempre ciente de quantos nós estão "perturbados" a qualquer momento. Quando o nó raiz tem uma contagem de perturbação de 0, o formulário está estabilizado e seguro para ser submetido.

Clique nos inputs (azul) para simular a chamada de um input de usuário.
import { createNode } from '@formkit/node'

const form = createNode({
  type: 'group',
  children: [
    createNode()
    createNode()
    createNode()
  ],
})
// ...
// interação do usuário:
async function someEvent () {
  await form.settled
  // agora sabemos que o formulário está completamente "estabilizado"
  // e que form.value é preciso.
}
O tipo de formulário

O input <FormKit type="form"> já incorpora esse comportamento de espera. Ele não chamará seu manipulador @submit até que seu formulário esteja completamente estabilizado. No entanto, ao construir inputs avançados, pode ser útil entender esses princípios subjacentes.

Obtendo o nó de um componente

Às vezes, pode ser útil obter a instância subjacente de um nó a partir do componente Vue <FormKit>. Existem três métodos principais para buscar o nó de um input.

  • Usando getNode() (ou o $formkit.get() do plugin Vue para a API de Opções)
  • Usando useFormKitNodeById
  • Usando o evento @node.
  • Usando um ref de template.

Usando getNode()

Ao usar o FormKit, você pode acessar um nó atribuindo-lhe um id e depois acessando-o por essa propriedade através da função getNode().

warning

Você deve atribuir um id ao input para usar este método.

Carregar exemplo ao vivo
API de Opções

Ao usar a API de Opções do Vue, você pode acessar o mesmo comportamento de getNode() usando this.$formkit.get().

Usando useFormKitNodeById()

A função de composição useFormKitNodeById permite que você acesse um nó pelo seu id de dentro de um componente Vue, retornando um ref do Vue que será preenchido com a instância do FormKitNode assim que ela for criada.

Para outras funções de composição similares, veja a documentação de composables.

warning

Você deve atribuir um id ao input para usar este método.

Carregar exemplo ao vivo

Usando o evento de nó

Outra maneira de obter o node subjacente é ouvir o evento @node, que é emitido apenas uma vez quando o componente inicializa o nó pela primeira vez.

Carregar exemplo ao vivo

Usando uma referência de template

Atribuir um componente <FormKit> a um ref também permite fácil acesso ao nó.

Carregar exemplo ao vivo

Traversal (Navegação)

Para navegar pelos nós dentro de um grupo ou lista, use node.at(address) — onde address é o name do nó que está sendo acessado (ou o caminho relativo até o nome). Por exemplo:

import { createNode } from '@formkit/core'

const group = createNode({
  type: 'group',
  children: [createNode({ name: 'email' }), createNode({ name: 'password' })],
})

// Retorna o nó de email
group.at('email')

Se o nó inicial tiver irmãos, ele tentará localizar uma correspondência nos irmãos (internamente, é isso que o FormKit usa para regras de validação como confirm:address).

import { createNode } from '@formkit/core'

const email = createNode({ name: 'email' })
const password = createNode({ name: 'password' })
const group = createNode({
  type: 'group',
  children: [email, password],
})

// Acessa o irmão para retornar o nó de senha
email.at('password')

Você pode ir mais fundo do que um nível usando um caminho relativo com sintaxe de ponto. Aqui está um exemplo mais complexo:

import { createNode } from '@formkit/core'

const group = createNode({
  type: 'group',
  children: [
    createNode({ name: 'team' }),
    createNode({
      type: 'list',
      name: 'users',
      children: [
        createNode({
          type: 'group',
          children: [
            createNode({ name: 'email' }),
            createNode({ name: 'password', value: 'foo' }),
          ],
        }),
        createNode({
          type: 'group',
          children: [
            createNode({ name: 'email' }),
            createNode({ name: 'password', value: 'fbar' }),
          ],
        }),
      ],
    }),
  ],
})

// saída: 'foo'
console.log(group.at('users.0.password').value)

Note como a navegação pela list usa chaves numéricas, isso porque o tipo list usa índices de array automaticamente.

Caminho de navegação de group.at('users.0.password') mostrado em vermelho.
Caminhos de array

Endereços de nós também podem ser expressos como arrays. Por exemplo, node.at('foo.bar') poderia ser expresso como node.at(['foo', 'bar']).

Tokens de travessia

Também estão disponíveis para uso em node.at() alguns "tokens" especiais:

TokenDescrição
$parentO ancestral imediato do nó atual.
$rootO nó raiz da árvore (o primeiro nó sem pai).
$selfO nó atual na travessia.
find()Uma função que realiza uma busca em largura por um valor e propriedade correspondentes. Por exemplo: node.at('$root.find(555, value)')

Esses tokens são usados em endereços de sintaxe de ponto assim como você usaria o nome de um nó:

import { createNode } from '@formkit/core'

const secondEmail = createNode({ name: 'email' })

createNode({
  type: 'group',
  children: [
    createNode({ name: 'team', value: 'charlie@factory.com' }),
    createNode({
      type: 'list',
      name: 'users',
      children: [
        createNode({
          type: 'group',
          children: [
            createNode({ name: 'email', value: 'james@peach.com' }),
            createNode({ name: 'password', value: 'foo' }),
          ],
        }),
        createNode({
          type: 'group',
          children: [
            secondEmail, // Vamos começar aqui.
            createNode({ name: 'password', value: 'fbar' }),
          ],
        }),
      ],
    }),
  ],
})

// Navegar do segundo email para o primeiro
console.log(secondEmail.at('$parent.$parent.0.email').value)
// exibe: charlie@factory.com
Caminho de travessia de secondEmail.at('$parent.$parent.0.email') mostrado em vermelho.

Eventos

Os nós têm seus próprios eventos que são emitidos durante o ciclo de vida do nó (não relacionados aos eventos do Vue).

Adicionar ouvinte

Para observar um evento específico, use node.on().

// Ouvir qualquer propriedade sendo definida ou alterada.
node.on('prop', ({ payload }) => {
  console.log(`prop ${payload.prop} foi definida para ${payload.value}`)
})

node.props.foo = 'bar'
// exibe: prop foo foi definida para bar

Os callbacks de manipuladores de eventos recebem um único argumento do tipo FormKitEvent, a estrutura do objeto é:

{
  // O conteúdo do evento — uma string, um objeto, etc.
  payload: { cause: 'sorvete', duration: 200 },
  // O nome do evento, isso corresponde ao primeiro argumento de node.on().
  name: 'brain-freeze',
  // Se este evento deve ou não borbulhar para o próximo pai.
  bubble: true,
  // O FormKitNode original que emitiu o evento.
  origin: node,
}

Os eventos de nó (por padrão) borbulham pela árvore de nós, mas node.on() responderá apenas aos eventos emitidos pelo mesmo nó. No entanto, se você quiser também capturar eventos que borbulham de descendentes, você pode acrescentar a string .deep ao final do nome do seu evento:

import { createNode } from '@formkit/core'

const group = createNode({ type: 'group' })

group.on('created.deep', ({ payload: child }) => {
  console.log('nó filho criado:', child.name)
})

const child = createNode({ parent: group, name: 'party-town-usa' })
// exibe: 'nó filho criado: party-town-usa'

Remover ouvinte

Cada chamada para registrar um observador com node.on() retorna um "recibo" — uma chave gerada aleatoriamente — que pode ser usada mais tarde para parar de observar aquele evento (similar a setTimeout() e clearTimeout()) usando node.off(recibo).

const recibo = node.on('input', ({ payload }) => {
  console.log('recebido input: ', payload)
})
node.input('foobar')
// saída: 'recebido input: foobar'
node.off(recibo)
node.input('fizz buzz')
// sem saída

Eventos principais

A seguir está uma lista abrangente de todos os eventos emitidos por @formkit/core. Códigos de terceiros podem emitir eventos adicionais não incluídos aqui.

NomePayloadBubblesDescrição
commitqualquersimEmitido quando o valor de um nó é confirmado, mas antes de ser transmitido para o restante do formulário.
config:{property}qualquer (o valor)simEmitido sempre que uma opção de configuração específica é definida ou alterada.
count:{property}qualquer (o valor)nãoEmitido sempre que o valor do contador de um livro-razão muda.
childFormKitNodesimEmitido quando um novo nó filho é adicionado, criado ou atribuído a um pai.
createdFormKitNodesimEmitido imediatamente antes do nó ser retornado ao chamar createNode() (plugins e recursos já foram executados).
definedFormKitTypeDefinitionsimEmitido quando o "tipo" de um nó é definido, isso geralmente acontece durante createNode().
destroyingFormKitNodesimEmitido quando o node.destroy() é chamado, depois de ter sido desanexado de quaisquer pais.
dom-input-eventEventsimEmitido quando o manipulador DOMInput é chamado, útil para obter o evento de entrada HTML original no core.
inputqualquer (o valor)simEmitido quando node.input() é chamado — após o hook input ter sido executado.
message-addedFormKitMessagesimEmitido quando uma nova mensagem node.store foi adicionada.
message-removedFormKitMessagesimEmitido quando uma mensagem node.store foi removida.
message-updatedFormKitMessagesimEmitido quando uma mensagem node.store foi alterada.
mountednenhumsimEmitido quando o componente <FormKit> que possui este nó é montado no dom.
prop:{propName}qualquer (o valor)simEmitido sempre que uma prop específica é definida ou alterada.
prop{ prop: string, value: any }simEmitido sempre que uma prop é definida ou alterada.
resetFormKitNodesimEmitido sempre que um formulário ou grupo é reiniciado.
settledbooleanonãoEmitido sempre que a contagem de perturbações de um nó se estabiliza ou desestabiliza.
settled:{counterName}booleanonãoEmitido sempre que um contador específico do livro-razão se estabiliza (volta a zero).
unsettled:{counterName}booleanonãoEmitido sempre que um contador específico do livro-razão se desestabiliza (sobe acima de zero).
textstring ou FormKitTextFragmentnãoEmitido após o hook text ter sido executado — geralmente quando processando texto de interface que pode ter sido traduzido.
Eventos de prop em mudanças de configuração

Quando uma opção de configuração muda, todos os nós herdeiros (incluindo o nó de origem) também emitirão eventos prop e prop:{propName}, desde que eles não substituam essa propriedade em seus próprios objetos props ou config.

Emitindo eventos

Eventos do Node são emitidos com node.emit(). Você pode aproveitar esse recurso para emitir seus próprios eventos sintéticos a partir de seus próprios plugins.

node.emit('myEvent', payloadGoesHere)

Um terceiro argumento opcional bubble também está disponível. Quando definido como false, ele impede que seu evento se propague pela árvore do formulário.

Hooks

Hooks são despachantes de middleware que são acionados durante operações predefinidas do ciclo de vida. Esses hooks permitem que o código externo estenda a funcionalidade interna do @formkit/core. A tabela a seguir detalha todos os hooks disponíveis:

HookValorDescrição
classes
{
property: string,
classes: Record<string, boolean>
}
Despachado após todas as operações de classe serem executadas, antes da conversão final para uma string.
commitanyDespachado ao definir o valor de um nó após o input e o debounce de node.input() ser chamado.
commitRawanyDespachado ao definir o valor de um nó após o input e o debounce de node.input() ser chamado.
errorstringDespachado ao processar um erro lançado — erros são geralmente entradas, e a saída final deve ser uma string.
initFormKitNodeDespachado após o nó ser inicialmente criado, mas antes de ser retornado em createNode().
inputanyDespachado de forma síncrona em cada evento de entrada (cada tecla pressionada) antes do commit.
messageFormKitMessageDespachado quando uma mensagem está sendo definida em node.store
prop
{
prop: string,
value: any
}
Despachado quando qualquer propriedade está sendo atribuída.
setErrors{ localErrors: ErrorMessages, childErrors?: ErrorMessages }Despachado quando erros explícitos estão sendo definidos em um nó (não erros de validação).
submitRecord<string, any>Despachado quando o formulário FormKit é submetido e passa pela validação. Esse hook permite que você modifique os valores do formulário (clonados) antes de serem passados para o manipulador de envio
textFormKitTextFragmentDespachado quando uma string gerada pelo FormKit precisa ser exibida — permitindo que i18n ou outros plugins interceptem.

Middleware de hook

Para utilizar esses hooks, você deve registrar um middleware de hook. Um middleware é simplesmente uma função que aceita 2 argumentos — o valor do hook e next — uma função que chama o próximo middleware na pilha e retorna o valor.

Para registrar um middleware, passe-o para o node.hook que você deseja usar:

import { createNode } from '@formkit/core'

const node = createNode()

// Isso transformaria todos os rótulos em "Rótulo Diferente!"
node.hook.prop((payload, next) => {
  if ((payload.prop = 'label')) {
    payload.value = 'Rótulo Diferente!'
  }
  return next(payload)
})
Use com plugins

Hooks podem ser registrados em qualquer lugar da sua aplicação, mas o local mais comum onde os hooks são usados é em um plugin.

Plugins

Plugins são o mecanismo principal para estender a funcionalidade do FormKit. O conceito é simples — um plugin é apenas uma função que aceita um nó. Essas funções são então automaticamente chamadas quando um nó é criado ou quando o plugin é adicionado ao nó. Plugins funcionam de maneira semelhante às opções de configuração — eles são automaticamente herdados por filhos e descendentes.

import { createNode } from '@formkit/core'

// Um plugin para mudar o valor de uma propriedade.
const myPlugin = (node) => {
  if (node.type === 'group') {
    node.props.color = 'amarelo'
  } else {
    node.props.color = 'azul-petróleo'
  }
}

const node = createNode([
  plugins: [myPlugin],
  children: [createNode()]
])

No exemplo acima, o plugin é definido apenas no pai, mas o filho também herda o plugin. A função myPlugin será chamada duas vezes — uma para cada nó no gráfico (que só tem dois neste exemplo):

O plugin é herdado pelo filho, mas executado independentemente.

Biblioteca

Além de estender e modificar nós, os plugins têm um papel adicional — expor bibliotecas de entrada. Uma "biblioteca" é uma função atribuída à propriedade library de um plugin que aceita um nó e determina se sabe como "definir" esse nó. Se sim, ela chama node.define() com uma definição de entrada.

Por exemplo, se quiséssemos criar um plugin que expusesse algumas novas entradas: italy e france, poderíamos escrever um plugin para fazer isso:

Carregar exemplo ao vivo

Desenvolvedores experientes notarão algumas propriedades interessantes desse padrão de biblioteca de plugin:

  1. Múltiplas bibliotecas de entrada podem ser instaladas no mesmo projeto.
  2. Plugins (e bibliotecas) podem ser expostos localmente, por formulário, grupo ou globalmente.
  3. Um plugin pode agrupar novas entradas junto com a lógica do plugin, tornando a instalação simples para os usuários finais.
  4. A função da biblioteca tem controle total sobre quais condições resultam em uma chamada para node.define(). Frequentemente, isso é simplesmente verificar node.props.type, mas você pode definir diferentes entradas com base em outras condições, como se uma propriedade específica estiver definida.
Aprenda a criar suas próprias entradas personalizadasDocumentação de entrada personalizada

Armazenamento de mensagens

Cada nó possui seu próprio armazenamento de dados. Os objetos nestes armazenamentos são chamados de "mensagens" e essas mensagens são especialmente valiosas para três casos de uso principais:

  • Exibir informações sobre o nó para um usuário com suporte a i18n (o plugin de validação usa isso).
  • "Bloquear" o envio de formulários.
  • Armazenamento de dados geral para autores de plugins.

Cada mensagem (FormKitMessage em TypeScript) no armazenamento é um objeto com a seguinte estrutura:

{
  // Indica se esta mensagem bloqueia o envio do formulário (padrão: false).
  blocking: true,
  // Deve ser um valor de string único (padrão: string aleatória).
  key: 'yourkey',
  // (opcional) Objeto de metadados sobre esta mensagem (padrão: {}).
  meta: {
    // (opcional) Se definido, i18n usa isso em vez da chave para encontrar mensagens de localidade.
    messageKey: 'i18nKey',
    // (opcional) Se definido, esses argumentos serão espalhados para a função de localidade i18n.
    i18nArgs: [...any],
    // (opcional) Se definido como false, a mensagem verificará a localização.
    localize: true,
    // (opcional) A localidade da mensagem (padrão: node.config.locale)
    locale: 'en',
    // Qualquer outro metadado que você desejar.
    ...any
  },
  // Uma categoria arbitrária à qual esta mensagem pertence (para fins de filtragem).
  // Por exemplo: 'validation' ou 'success' (padrão: 'state')
  type: string,
  // (opcional) deve ser uma string, número ou booleano (padrão: undefined).
  value: 'Ops, nosso servidor está quebrado!',
  // Esta mensagem deve ser mostrada aos usuários finais? (padrão: true)
  visible: true
}
Função auxiliar de criação de mensagem

Uma função auxiliar createMessage({}) pode ser importada de @formkit/core para mesclar seus dados de mensagem com os valores padrão acima para criar um novo objeto de mensagem.

Ler e escrever mensagens

Para adicionar ou atualizar uma mensagem, use node.store.set(FormKitMessage). As mensagens são então disponibilizadas em node.store.{messageKey}

import { createMessage, createNode } from '@formkit/core'

const node = createNode()
const message = createMessage({
  key: 'clickHole',
  value: 'Por favor, clique 100 vezes.',
})

node.store.set(message)

console.log(node.store.clickHole.value)
// saída: 'Por favor, clique 100 vezes.'
Localidades de mensagens

As mensagens serão automaticamente traduzidas se o plugin @formkit/i18n estiver instalado e uma chave correspondente estiver disponível na localidade ativa. Leia a documentação de i18n.

Livro Razão

Uma das chaves para o desempenho do FormKit é sua capacidade de contar eficientemente mensagens que correspondem a um determinado critério (na loja), e então manter um total contínuo dessas mensagens à medida que mudanças são feitas (incluindo de nós filhos). Esses contadores são criados usando node.ledger.

Criando um contador

Vamos dizer que queremos contar quantas mensagens estão sendo exibidas atualmente. Poderíamos fazer isso contando mensagens com a propriedade visible definida como true.

Carregar exemplo ao vivo

Note que o segundo argumento de node.ledger.count() é uma função. Esta função aceita uma mensagem como argumento e espera que o valor de retorno seja um booleano, indicando se essa mensagem deve ser contada ou não. Isso permite que você crie contadores arbitrários para qualquer tipo de mensagem.

Ao usar um contador em um nó group ou list, o contador se propagará pela árvore somando o valor de todas as mensagens que passam pela função de critério e, em seguida, rastreando essa contagem para mudanças na loja.

Contador de validação

O plugin de validação já declara um contador chamado blocking que conta a propriedade de bloqueio de todas as mensagens. É assim que os formulários FormKit sabem se todos os seus filhos estão "válidos".