rafatoração de componentes de entrada
This commit is contained in:
parent
6aedf2469f
commit
27c9e4d5e2
45 changed files with 1295 additions and 2605 deletions
|
|
@ -1,6 +1,8 @@
|
|||
<template>
|
||||
<v-text-field
|
||||
v-model="localValue"
|
||||
:type="inputHtmlType"
|
||||
:inputmode="inputMode"
|
||||
:label="opcoes?.rotulo"
|
||||
:placeholder="opcoes?.placeholder"
|
||||
:counter="opcoes?.limiteCaracteres"
|
||||
|
|
@ -8,12 +10,16 @@
|
|||
v-bind="attrs"
|
||||
@focus="() => emit('focus')"
|
||||
@blur="() => emit('blur')"
|
||||
@input="onInput"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from "vue";
|
||||
import type { PadroesEntradas } from "./tiposEntradas";
|
||||
import { formatarCpfCnpj } from "./utils/cpfCnpj";
|
||||
import { formatTelefone } from "./utils/telefone";
|
||||
import { formatarCep } from "./utils/cep";
|
||||
|
||||
type EntradaTexto = PadroesEntradas["texto"];
|
||||
|
||||
|
|
@ -40,6 +46,8 @@ export default defineComponent({
|
|||
blur: () => true,
|
||||
},
|
||||
setup(props, { attrs, emit }) {
|
||||
const formato = computed(() => props.opcoes?.formato ?? "texto");
|
||||
|
||||
const localValue = computed<EntradaTexto["value"]>({
|
||||
get: () => props.value,
|
||||
set: (v) => {
|
||||
|
|
@ -49,7 +57,43 @@ export default defineComponent({
|
|||
},
|
||||
});
|
||||
|
||||
return { attrs, emit, localValue };
|
||||
const inputHtmlType = computed(() => {
|
||||
if (formato.value === "email") return "email";
|
||||
if (formato.value === "url") return "url";
|
||||
return "text";
|
||||
});
|
||||
|
||||
const inputMode = computed<string | undefined>(() => {
|
||||
if (formato.value === "telefone") return "tel";
|
||||
if (formato.value === "cpfCnpj" || formato.value === "cep") return "numeric";
|
||||
return undefined;
|
||||
});
|
||||
|
||||
function aplicarFormato(valor: string) {
|
||||
switch (formato.value) {
|
||||
case "telefone":
|
||||
return formatTelefone(valor);
|
||||
case "cpfCnpj":
|
||||
return formatarCpfCnpj(valor);
|
||||
case "cep":
|
||||
return formatarCep(valor);
|
||||
default:
|
||||
return valor;
|
||||
}
|
||||
}
|
||||
|
||||
function onInput(e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const resultado = aplicarFormato(target.value);
|
||||
|
||||
// garante que o input mostre o valor formatado
|
||||
target.value = resultado;
|
||||
|
||||
// regra do projeto: value sempre igual ao que aparece
|
||||
localValue.value = resultado;
|
||||
}
|
||||
|
||||
return { attrs, emit, localValue, inputHtmlType, inputMode, onInput };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -47,18 +47,24 @@ export type PadroesEntradas = {
|
|||
{
|
||||
/** Limite máximo de caracteres permitidos (se definido) */
|
||||
limiteCaracteres?: number
|
||||
|
||||
/**
|
||||
* Formato/máscara aplicada ao texto.
|
||||
* Obs: o `value` SEMPRE será o texto formatado (o que aparece no input).
|
||||
*/
|
||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep"
|
||||
}
|
||||
>
|
||||
|
||||
numero: tipoPadraoEntrada<
|
||||
number | null | undefined,
|
||||
{
|
||||
|
||||
|
||||
/** Unidade de medida (ex.: "kg", "m³") */
|
||||
|
||||
/** Unidade de medida (ex.: "kg", "m³") */
|
||||
sufixo?: string
|
||||
|
||||
/** Moéda (ex.: "R$") */
|
||||
/** Moéda (ex.: "R$") */
|
||||
prefixo?: string
|
||||
|
||||
/**
|
||||
|
|
|
|||
10
src/componentes/EliEntrada/utils/cep.ts
Normal file
10
src/componentes/EliEntrada/utils/cep.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
function somenteNumeros(valor: string) {
|
||||
return valor.replace(/\D+/g, "");
|
||||
}
|
||||
|
||||
/** Formata CEP no padrão 00000-000 */
|
||||
export function formatarCep(valor: string) {
|
||||
const digitos = somenteNumeros(valor);
|
||||
if (!digitos) return "";
|
||||
return digitos.replace(/^(\d{5})(\d)/, "$1-$2").slice(0, 9);
|
||||
}
|
||||
24
src/componentes/EliEntrada/utils/cpfCnpj.ts
Normal file
24
src/componentes/EliEntrada/utils/cpfCnpj.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
function somenteNumeros(v: string): string {
|
||||
return v.replace(/\D+/g, "");
|
||||
}
|
||||
|
||||
export function formatarCpfCnpj(v: string): string {
|
||||
const d = somenteNumeros(v);
|
||||
|
||||
// CPF
|
||||
if (d.length <= 11) {
|
||||
return d
|
||||
.replace(/(\d{3})(\d)/, "$1.$2")
|
||||
.replace(/(\d{3})(\d)/, "$1.$2")
|
||||
.replace(/(\d{3})(\d{1,2})$/, "$1-$2")
|
||||
.slice(0, 14);
|
||||
}
|
||||
|
||||
// CNPJ
|
||||
return d
|
||||
.replace(/^(\d{2})(\d)/, "$1.$2")
|
||||
.replace(/^(\d{2})\.(\d{3})(\d)/, "$1.$2.$3")
|
||||
.replace(/\.(\d{3})(\d)/, ".$1/$2")
|
||||
.replace(/(\d{4})(\d)/, "$1-$2")
|
||||
.slice(0, 18);
|
||||
}
|
||||
29
src/componentes/EliEntrada/utils/telefone.ts
Normal file
29
src/componentes/EliEntrada/utils/telefone.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* Remove tudo que não é número
|
||||
*/
|
||||
export function sanitizeTelefone(value: string): string {
|
||||
return value.replace(/\D+/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Aplica máscara dinâmica de telefone BR
|
||||
*/
|
||||
export function formatTelefone(value: string): string {
|
||||
const digits = sanitizeTelefone(value);
|
||||
|
||||
if (!digits) return "";
|
||||
|
||||
// (99) 9999-9999
|
||||
if (digits.length <= 10) {
|
||||
return digits
|
||||
.replace(/^(\d{2})(\d)/, "($1) $2")
|
||||
.replace(/(\d{4})(\d)/, "$1-$2")
|
||||
.slice(0, 14);
|
||||
}
|
||||
|
||||
// (99) 99999-9999
|
||||
return digits
|
||||
.replace(/^(\d{2})(\d)/, "($1) $2")
|
||||
.replace(/(\d{5})(\d)/, "$1-$2")
|
||||
.slice(0, 15);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue