# 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`](./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:

```vue
<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:

```vue
<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:

```vue
<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:

```vue
<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:

```vue
<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`
