@@ -31,10 +31,31 @@ export function parseRawValue(rawValue: string): number {
3131 return isNaN ( parsed ) ? 0 : parsed ;
3232}
3333
34+ function getGroupSeparator ( locale : SupportedLocale ) : string {
35+ const parts = new Intl . NumberFormat ( locale ) . formatToParts ( 10000 ) ;
36+ return parts . find ( ( p ) => p . type === "group" ) ?. value ?? "," ;
37+ }
38+
39+ function addThousandsSeparators (
40+ integerStr : string ,
41+ separator : string ,
42+ ) : string {
43+ let result = "" ;
44+ for ( let i = integerStr . length - 1 , count = 0 ; i >= 0 ; i -- , count ++ ) {
45+ if ( count > 0 && count % 3 === 0 ) {
46+ result = separator + result ;
47+ }
48+ result = integerStr [ i ] + result ;
49+ }
50+ return result ;
51+ }
52+
3453/**
3554 * Formats raw value (e.g., "123.45") to display string with currency.
3655 * When decimal separator is entered, always shows 2 decimal places
3756 * so placeholder zeros can be styled differently.
57+ * Uses string manipulation instead of parseFloat to avoid precision loss
58+ * with large numbers (> Number.MAX_SAFE_INTEGER).
3859 */
3960export function formatRawValueToDisplay (
4061 rawValue : string ,
@@ -49,14 +70,22 @@ export function formatRawValueToDisplay(
4970 if ( ! rawValue || rawValue === "" ) return "" ;
5071
5172 const hasDecimalSeparator = rawValue . includes ( "." ) || rawValue . includes ( "," ) ;
52- const numericValue = parseRawValue ( rawValue ) ;
73+ const normalized = rawValue . replace ( "," , "." ) ;
74+ const [ intPart , decPart ] = normalized . split ( "." ) ;
75+ const cleanInteger = ( intPart || "0" ) . replace ( / ^ 0 + / , "" ) || "0" ;
76+
77+ const groupSep = getGroupSeparator ( locale ) ;
78+ const decSep = getDecimalSeparator ( locale ) ;
79+ const formattedInteger = addThousandsSeparators ( cleanInteger , groupSep ) ;
5380
54- const formatter = new Intl . NumberFormat ( locale , {
55- minimumFractionDigits : hasDecimalSeparator ? 2 : 0 ,
56- maximumFractionDigits : 2 ,
57- } ) ;
81+ let formatted : string ;
82+ if ( hasDecimalSeparator ) {
83+ const paddedDecimal = ( decPart || "" ) . padEnd ( 2 , "0" ) . slice ( 0 , 2 ) ;
84+ formatted = `${ formattedInteger } ${ decSep } ${ paddedDecimal } ` ;
85+ } else {
86+ formatted = formattedInteger ;
87+ }
5888
59- const formatted = formatter . format ( numericValue ) ;
6089 return symbolPosition === "right"
6190 ? `${ formatted } ${ currency } `
6291 : `${ currency } ${ formatted } ` ;
0 commit comments