# EliInput

**Componente base de input do design system**

O EliInput unifica vários tipos de campo (v-text-field, v-textarea, v-select, v-radio-group, v-checkbox) em uma única API consistente. Ele encapsula comportamentos, máscaras e regras comuns (CPF/CNPJ, telefone, CEP, numéricos, formatação de moeda etc.) para manter coerência visual e de lógica em toda a aplicação.

> ⚠️ Nunca use os componentes Vuetify diretamente fora do design system para esses casos.
> Utilize sempre EliInput para garantir formatação, tipagem e repasse de atributos padronizados.

---

## Visão geral

EliInput foi projetado para:

* Centralizar formatação (máscaras) para tipos de entrada comuns (telefone, CPF/CNPJ, CEP, numéricos).
* Fornecer uma API única (type) que representa diferentes controles (text, textarea, select, radio, checkbox, etc.).
* Repassar atributos/props do pai para o componente Vuetify interno (v-bind="$attrs") mantendo inheritAttrs: false.
* Emitir eventos padronizados: update:modelValue, change, focus, blur.

---

## Principais decisões de implementação

* inheritAttrs: false — o componente controla explicitamente para onde os atributos são passados (v-bind="attrs" no elemento interno).
* Uso de um computed value que faz emit("update:modelValue", v) e emit("change", v) — assim qualquer v-model no pai funciona como esperado.
* Normalização de props.options para aceitar objetos { label, value, disabled } ou primitivos ('A', 1).
* Separação clara entre lógica de formatação (aplicada em onInput) e componentes que não devem ser formatados (ex.: v-select).

---

## Tipagem (TypeScript)

```ts
type ValorCampo = string | number | boolean | null;
type Option = { label: string; value: ValorCampo; disabled?: boolean };

type InputVariant = 'outlined' | 'filled' | 'plain' | 'solo' | 'solo-filled' | 'solo-inverted' | 'underlined';
type Density = 'default' | 'comfortable' | 'compact';
type TipoNumerico = 'numericoInteiro' | 'numericoDecimal' | 'numericoMoeda' | 'porcentagem';

type InputType =
  | 'text' | 'password' | 'email' | 'search' | 'url' | 'textarea'
  | 'radio' | 'checkbox' | 'telefone' | 'cpfCnpj' | 'cep' | 'select'
  | TipoNumerico;
```

---

## Props 

| Prop             | Tipo                        | Default         | Descrição                                              |
| ---------------- | --------------------------- | --------------- | ------------------------------------------------------ |
| `modelValue`     | `string \| number \| boolean \| (string \| number \| boolean \| null)[]` | `""`            | Valor controlado (use com `v-model`).                  |
| `type`           | `InputType`                 | `"text"`        | Tipo do controle (ver `InputType`).                    |
| `label`          | `string`                    | `-`             | Rótulo do campo.                                       |
| `placeholder`    | `string`                    | `-`             | Texto exibido quando o campo está vazio.               |
| `disabled`       | `boolean`                   | `false`         | Desabilita o campo.                                    |
| `error`          | `boolean`                   | `false`         | Força estado visual de erro.                           |
| `errorMessages`  | `string \| string[]`        | `[]`            | Mensagem ou lista de mensagens de erro.                |
| `hint`           | `string`                    | `-`             | Texto de ajuda exibido abaixo do campo.                |
| `persistentHint` | `boolean`                   | `false`         | Mantém o hint sempre visível.                          |
| `variant`        | `InputVariant`              | `"outlined"`    | Variante visual do Vuetify.                            |
| `density`        | `Density`                   | `"comfortable"` | Densidade visual do campo.                             |
| `color`          | `string`                    | `"primary"`     | Cor do campo quando focado (ou `error`, se aplicável). |
| `clearable`      | `boolean`                   | `false`         | Permite limpar o valor do campo.                       |


## Notas sobre props

* options: aceita arrays como ['Frontend','Backend'] ou { label:'São Paulo', value:'SP' }. O componente normaliza para { label, value, disabled? }.
* type determina quais comportamentos internos são aplicados. Tipos numéricos e máscara (telefone, cpfCnpj, cep) passam por formatação em onInput.
* multiple/chips: úteis para type="select". O v-select interno recebe item-title="label" e item-value="value" para compatibilidade com objetos.

---

## Emissões (events)

* update:modelValue — padrão v-model.
* change — emitido sempre que o valor muda (alinha com update:modelValue).
* focus — quando o campo interno recebe foco.
* blur — quando perde o foco.
* Observação: como value é um computed com getter/setter que emite ambos, v-model e listeners de mudança no pai funcionarão normalmente.

--- 

## Repasso de atributos e listeners

* O componente define inheritAttrs: false e usa v-bind="attrs" nos componentes internos (v-text-field, v-select, etc.). Isso implica que:
* Atributos HTML (ex.: type, aria-label, class, style) passados para <EliInput> são aplicados ao componente Vuetify interno apropriado.
* Listeners (ex.: @click, @keydown) também fazem parte de $attrs e serão repassados para o componente interno — use o EliInput como se estivesse ouvindo eventos diretamente no input.

## Exemplo:

```vue
<EliInput type="text" v-model="nome" aria-label="Nome completo" @keydown.enter="enviar" />
```

---

## Comportamentos de formatação importantes

* numericoInteiro — remove tudo que não for dígito.
* numericoDecimal — mantém separador decimal (aplica formatarDecimal).
* numericoMoeda — formata para moeda conforme util (formatarMoeda).
* porcentagem — aplica formatação decimal e exibe sufixo `%` automaticamente.
* telefone — aplica máscara/format formatTelefone.
* cpfCnpj — aplica formatarCpfCnpj.
* cep — aplica formatarCep.

**Importante: a formatação ocorre no onInput (campos text-like). O v-select não passa por onInput — ele usa v-model="value" e o computed que emite  o update. Se desejar formatação específica para itens do select (por exemplo, mostrar label formatado), trate nos options antes de passar.**

--- 

## Slot

* O componente não expõe slots customizados diretamente. Ele controla internamente o append para toggle de senha quando type === 'password' && showPasswordToggle (ícone de olho).
* Se você precisa de slots específicos do v-text-field/v-select, considere estender o componente ou criar uma variação que exponha os slots desejados.
