// Parse : texte saisi (espaces, virgule, caractères parasites) → chaîne numérique propre. export const normalizeAmount = (value: string): string => { const sanitizedValue = value .replace(/\s+/g, '') .replace(/,/g, '.') .replace(/[^\d.]/g, '') const [integerPartRaw = '', ...decimalParts] = sanitizedValue.split('.') const integerPart = integerPartRaw.replace(/^0+(?=\d)/, '') const decimalPart = decimalParts.join('').slice(0, 2) if (sanitizedValue.includes('.')) { return `${integerPart || '0'}.${decimalPart}` } return integerPart } // Format : modèle propre (point décimal) → affichage groupé FR (espaces + virgule). export const formatGroupedAmount = (model: string): string => { if (model === '') return '' const hasDot = model.includes('.') const [integerPart = '', decimalPart = ''] = model.split('.') const groupedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ' ') return hasDot ? `${groupedInteger},${decimalPart}` : groupedInteger } // Nombre de caractères significatifs (hors espaces de groupement) à gauche d'une position. export const countSignificant = (str: string, upTo: number): number => str.slice(0, upTo).replace(/ /g, '').length // Position de curseur après le n-ième caractère significatif dans la chaîne affichée. export const caretFromSignificant = (display: string, sig: number): number => { if (sig <= 0) return 0 let seen = 0 for (let i = 0; i < display.length; i++) { if (display[i] !== ' ') seen++ if (seen >= sig) return i + 1 } return display.length }