vue-componentes/src/componentes/EliEntrada/README.md
2026-01-29 18:31:52 -03:00

6.3 KiB

EliEntrada (Padrão de Entradas)

Esta pasta define o padrão EliEntrada: um conjunto de componentes de entrada (inputs) com uma API uniforme.

TL;DR

  • Toda entrada recebe value (estado) e opcoes (configuração).
  • O padrão de uso é v-model:value.
  • Mantemos compatibilidade com Vue 2 via evento input.

Para humanos (uso no dia-a-dia)

Conceito

Um componente EliEntrada recebe duas propriedades:

  • value: o valor atual do campo (entrada e saída)
  • opcoes: um objeto que configura o componente (rótulo, placeholder e opções específicas do tipo)

Essa padronização facilita:

  • gerar formulários dinamicamente
  • trocar tipos de entrada com o mínimo de refactor
  • documentar e tipar de forma previsível

Tipos e contratos

Os contratos ficam em: tiposEntradas.ts

  • PadroesEntradas: mapa de tipos suportados (ex.: texto, numero, dataHora)
  • TipoEntrada: união das chaves do mapa (ex.: "texto" | "numero" | "dataHora")

Componentes disponíveis

1) EliEntradaTexto

Value: string | null | undefined

Opções (além de rotulo/placeholder):

  • limiteCaracteres?: number

Exemplo:

<template>
  <EliEntradaTexto
    v-model:value="nome"
    :opcoes="{ rotulo: 'Nome', placeholder: 'Digite seu nome', limiteCaracteres: 50 }"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { EliEntradaTexto } from '@/index'

const nome = ref<string | null>(null)
</script>

2) EliEntradaNumero

Value: number | null | undefined

Opções:

  • precisao?: number
    • 1 => inteiro
    • 0.1 => 1 casa decimal
    • 0.01 => 2 casas decimais
  • prefixo?: string (ex.: "R$")
  • sufixo?: string (ex.: "kg")

Comportamento:

  • Quando precisao < 1 o componente entra em modo fixed-point: você digita números continuamente e ele insere a vírgula automaticamente.
  • O que é exibido sempre corresponde ao value emitido.

Exemplos:

<EliEntradaNumero
  v-model:value="quantidade"
  :opcoes="{ rotulo: 'Quantidade', placeholder: 'Ex: 10', precisao: 1, sufixo: 'kg' }"
/>

<EliEntradaNumero
  v-model:value="preco"
  :opcoes="{ rotulo: 'Preço', placeholder: 'Digite', precisao: 0.01, prefixo: 'R$' }"
/>

3) EliEntradaDataHora

Value: string | null | undefined (ISO 8601 com offset ou Z)

Opções:

  • modo?: "data" | "dataHora" (default: dataHora)
  • min?: string (ISO)
  • max?: string (ISO)
  • limpavel?: boolean
  • erro?: boolean
  • mensagensErro?: string | string[]
  • dica?: string
  • dicaPersistente?: boolean
  • densidade?: CampoDensidade
  • variante?: CampoVariante

Importante:

  • O input nativo datetime-local não carrega timezone.
  • O componente converte ISO (Z/offset) para local para exibir.
  • Ao alterar, emite ISO 8601 com o offset local.

Exemplo:

<EliEntradaDataHora
  v-model:value="agendamento"
  :opcoes="{ rotulo: 'Agendar', modo: 'dataHora', min, max, limpavel: true }"
/>

4) EliEntradaParagrafo

Entrada de texto multi-linha (equivalente a um textarea).

Value: string | null | undefined

Opções (além de rotulo/placeholder):

  • linhas?: number (default: 4)
  • limiteCaracteres?: number
  • limpavel?: boolean
  • erro?: boolean
  • mensagensErro?: string | string[]
  • dica?: string
  • dicaPersistente?: boolean
  • densidade?: CampoDensidade
  • variante?: CampoVariante

Exemplo:

<EliEntradaParagrafo
  v-model:value="descricao"
  :opcoes="{
    rotulo: 'Descrição',
    placeholder: 'Digite uma descrição mais longa...',
    linhas: 5,
    limiteCaracteres: 300,
    limpavel: true,
  }"
/>

5) EliEntradaSelecao

Entrada de seleção (select) com carregamento de itens via função.

Value: string | null | undefined (chave do item selecionado)

Opções (além de rotulo/placeholder):

  • itens: () => {chave: string; rotulo: string}[] | Promise<{chave: string; rotulo: string}[]>
  • limpavel?: boolean
  • erro?: boolean
  • mensagensErro?: string | string[]
  • dica?: string
  • dicaPersistente?: boolean
  • densidade?: CampoDensidade
  • variante?: CampoVariante

Comportamento:

  • Ao montar, o componente chama opcoes.itens().
  • Enquanto carrega, o select fica em loading e desabilitado.

Exemplo:

<EliEntradaSelecao
  v-model:value="categoria"
  :opcoes="{
    rotulo: 'Categoria',
    placeholder: 'Selecione...',
    limpavel: true,
    itens: async () => {
      await new Promise((r) => setTimeout(r, 300));
      return [
        { chave: 'a', rotulo: 'Categoria A' },
        { chave: 'b', rotulo: 'Categoria B' },
      ];
    },
  }"
/>

Compatibilidade Vue 2 / Vue 3

Padrão recomendado (Vue 3):

  • v-model:value

Compat Vue 2:

  • todos os EliEntradas também emitem input.
  • isso permite consumir com o padrão value + input quando necessário.

Playground

  • Entradas: src/playground/entradas.playground.vue
  • Data/hora: src/playground/data_hora.playground.vue

Para IA (contratos, invariantes e padrões de evolução)

Contratos (não quebrar)

  1. Todo EliEntrada tem:

    • prop value
    • prop opcoes
    • evento update:value
  2. Compatibilidade:

    • emitir input (compat Vue 2) é obrigatório
  3. Tipagem:

    • PadroesEntradas é a fonte única do contrato (value/opcoes)
    • TipoEntrada = keyof PadroesEntradas
  4. Sanitização/Normalização:

    • EliEntradaNumero deve bloquear caracteres inválidos e manter display coerente com value
    • EliEntradaDataHora deve receber/emitir ISO e converter para local apenas para exibição

Como adicionar uma nova entrada (checklist)

  1. Adicionar chave em PadroesEntradas em tiposEntradas.ts
  2. Criar EliEntradaX.vue seguindo o padrão:
    • value + opcoes
    • emite update:value, input, change
  3. Exportar no src/componentes/EliEntrada/index.ts
  4. Registrar no src/componentes/EliEntrada/registryEliEntradas.ts
  5. Criar/atualizar playground (src/playground/*.playground.vue)
  6. Validar pnpm -s run build:types e pnpm -s run build

Padrões de mudança (refactors seguros)

  • Se precisar mudar o contrato, faça migração incremental:
    • manter props/eventos antigos como fallback temporário
    • atualizar playground e exemplos
    • rodar build:types para garantir geração de .d.ts