diff --git a/src/componentes/EliInput/EliInput.vue b/src/componentes/EliInput/EliInput.vue
index 96c1b91..4a9827b 100644
--- a/src/componentes/EliInput/EliInput.vue
+++ b/src/componentes/EliInput/EliInput.vue
@@ -47,6 +47,28 @@
v-bind="attrs"
/>
+
+
+
{
+ // Normaliza options para [{ label, value, disabled? }]
+ return (props.options || []).map((o: any) =>
+ o && typeof o === "object" && ("label" in o || "value" in o)
+ ? { label: o.label ?? String(o.value), value: o.value, disabled: o.disabled }
+ : { label: String(o), value: o }
+ );
+ });
+
+ function optLabel(opt: any) {
+ if (opt && typeof opt === "object") return opt.label ?? String(opt.value);
+ return String(opt);
+ }
+
+ function optValue(opt: any) {
+ if (opt && typeof opt === "object") return opt.value;
+ return opt;
+ }
+
+
return {
attrs,
value,
@@ -234,6 +287,9 @@ export default defineComponent({
onInput,
onFocus: () => emit("focus"),
onBlur: () => emit("blur"),
+ computedItems,
+ optLabel,
+ optValue,
};
},
});
diff --git a/src/componentes/EliInput/README.md b/src/componentes/EliInput/README.md
index e69de29..5c4244b 100644
--- a/src/componentes/EliInput/README.md
+++ b/src/componentes/EliInput/README.md
@@ -0,0 +1,116 @@
+# 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 Option = { label: string; value: any; disabled?: boolean };
+
+type InputVariant = 'outlined' | 'filled' | 'plain' | 'solo' | 'solo-filled' | 'solo-inverted' | 'underlined';
+type Density = 'default' | 'comfortable' | 'compact';
+type TipoNumerico = 'numericoInteiro' | 'numericoDecimal' | 'numericoMoeda';
+
+type InputType =
+ | 'text' | 'password' | 'email' | 'search' | 'url' | 'textarea'
+ | 'radio' | 'checkbox' | 'telefone' | 'cpfCnpj' | 'cep' | 'select'
+ | TipoNumerico;
+```
+
+---
+
+## Props
+
+| Prop | Tipo | Default | Descrição |
+| ---------------- | --------------------------- | --------------- | ------------------------------------------------------ |
+| `modelValue` | `string \| number \| any[]` | `""` | 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 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
+
+```
+
+---
+
+## 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).
+* 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.
\ No newline at end of file
diff --git a/src/componentes/EliInput/utils/cep.ts b/src/componentes/EliInput/utils/cep.ts
new file mode 100644
index 0000000..701fd34
--- /dev/null
+++ b/src/componentes/EliInput/utils/cep.ts
@@ -0,0 +1,9 @@
+import { somenteNumeros } from "./numerico";
+
+export function formatarCep(v: string): string {
+ const d = somenteNumeros(v).slice(0, 8);
+
+ if (d.length <= 5) return d;
+
+ return d.replace(/^(\d{5})(\d{1,3})$/, "$1-$2");
+}
diff --git a/src/componentes/EliOlaMundo/EliOlaMundo.vue b/src/componentes/EliOlaMundo/EliOlaMundo.vue
index f947815..f100efb 100644
--- a/src/componentes/EliOlaMundo/EliOlaMundo.vue
+++ b/src/componentes/EliOlaMundo/EliOlaMundo.vue
@@ -18,20 +18,44 @@
density="compact"
/>
-
+
-
+
+
+
+
+
([]);
return {
nome,
email,
documento,
+ estado,
telefone,
mensagem,
senha,
@@ -129,6 +156,7 @@ export default defineComponent({
habilidades,
idade,
altura,
+ cep,
valor,
};
},