melhorias em compoenentes de numero

This commit is contained in:
Luiz Silva 2026-04-30 12:19:36 -03:00
parent 5124844773
commit 303eda1b99
27 changed files with 3056 additions and 55 deletions

View file

@ -47,6 +47,13 @@ function casasDecimaisFromPrecisao(precisao: number): number {
return dec.length
}
/**
* Analisa a entrada de texto e converte em um valor numérico válido (float).
* Troca a vírgula brasileira por ponto antes de passar para o parser nativo.
*
* @param texto - O texto bruto digitado ou vindo do estado
* @returns O número processado ou `null` caso inválido ou vazio
*/
function parseNumero(texto: string): number | null {
const normalizado = (texto ?? "").trim().replace(/,/g, ".")
if (!normalizado) return null
@ -55,12 +62,20 @@ function parseNumero(texto: string): number | null {
return n
}
/**
* Formata um valor numérico para a exibição na interface (usando vírgula como separador).
* Em caso de precisão nula (modo livre), preserva a semântica de exibição direta sem forçar o preenchimento de zeros (toFixed).
*
* @param value - O valor numérico de fato emitido
* @param casas - Opcionalmente, o número exato de casas decimais para fixar
* @returns String formatada amigável para exibição em pt-BR
*/
function formatarNumero(
value: number | null | undefined,
casas: number | null,
) {
if (value === null || value === undefined) return ""
if (casas === null) return String(value)
if (casas === null) return String(value).replace(/\./g, ",")
// Garantimos que o texto visual corresponda ao value (fixed).
const fixed = Number(value).toFixed(Math.max(0, casas))
@ -68,10 +83,23 @@ function formatarNumero(
return fixed.replace(/\./g, ",")
}
/**
* Retira todo tipo de sujeira de uma string, devolvendo restritamente números (para inteiros).
*
* @param texto - String de entrada
* @returns Apenas dígitos de 0 a 9
*/
function somenteNumeros(texto: string) {
return (texto ?? "").replace(/\D+/g, "")
}
/**
* Higieniza o texto preservando apenas os dígitos e exatamente UM separador decimal.
* Colapsa múltiplos separadores e normaliza se o separador vier no início (",4" => "0,4").
*
* @param texto - Texto misto de entrada
* @returns String contendo número e (opcionalmente) uma vírgula ou ponto residual
*/
function somenteNumerosESeparadorDecimal(texto: string) {
// Mantém apenas números e UM separador decimal ("," ou "."), sem sinais.
// Implementação baseada em regex + colapso de separadores.
@ -103,6 +131,14 @@ function limitarCasasDecimais(texto: string, casas: number | null) {
return `${inteiro}${sep}${frac.slice(0, casas)}`
}
/**
* Resolve o edge-case de digitação transitória parcial terminada em separador (ex: "1,").
* Identifica se a string tem este formato pendente e retorna temporariamente sua base inteira
* sem permitir que o valor se torne nulo.
*
* @param texto - O texto já higienizado, tipicamente terminando em vírgula ou ponto
* @returns A conversão parcial estrita ou `null` caso falhe
*/
function valorParcialDecimal(texto: string): number | null {
// Regra (B): se o usuário digitou "1," ou "1." emite 1.
const m = texto.match(/^(\d+)[.,]$/)
@ -220,8 +256,12 @@ export default defineComponent({
emit("change", out)
// display deve sempre corresponder ao value final
// biome-ignore lint/suspicious/noExplicitAny: dynamic format
displayValue.value = formatarNumero(out as any, casasDecimais.value)
if (casasDecimais.value === null && textoFiltrado) {
displayValue.value = textoFiltrado.replace(/\./g, ",")
} else {
// biome-ignore lint/suspicious/noExplicitAny: dynamic format
displayValue.value = formatarNumero(out as any, casasDecimais.value)
}
}
return { attrs, emit, displayValue, isInteiro, onUpdateModelValue }