@@ -3,7 +3,13 @@ import { getFormatter } from '../../utils/formatNumber';
33
44const STEP_EPSILON_FACTOR = 1e-10 ;
55
6- function getFractionDigits ( format ?: Intl . NumberFormatOptions ) {
6+ // The repo's configured Intl types do not include the newer NumberFormat v3 rounding options yet.
7+ type NumberFormatOptionsWithRounding = Intl . NumberFormatOptions & {
8+ roundingIncrement ?: number | undefined ;
9+ roundingMode ?: string | undefined ;
10+ } ;
11+
12+ function getFractionDigits ( format ?: NumberFormatOptionsWithRounding ) {
713 const defaultOptions = getFormatter ( 'en-US' ) . resolvedOptions ( ) ;
814 const minimumFractionDigits =
915 format ?. minimumFractionDigits ?? defaultOptions . minimumFractionDigits ?? 0 ;
@@ -14,17 +20,39 @@ function getFractionDigits(format?: Intl.NumberFormatOptions) {
1420 return { maximumFractionDigits, minimumFractionDigits } ;
1521}
1622
17- function roundToFractionDigits ( value : number , maximumFractionDigits : number ) {
23+ export function roundToFractionDigits (
24+ value : number ,
25+ maximumFractionDigits : number ,
26+ format ?: NumberFormatOptionsWithRounding ,
27+ ) {
1828 if ( ! Number . isFinite ( value ) ) {
1929 return value ;
2030 }
2131 const digits = Math . min ( Math . max ( maximumFractionDigits , 0 ) , 20 ) ;
22- return Number ( value . toFixed ( digits ) ) ;
32+ const isPercentWithExplicitPrecision =
33+ format ?. style === 'percent' &&
34+ ( format . maximumFractionDigits != null || format . minimumFractionDigits != null ) ;
35+ const scale = isPercentWithExplicitPrecision ? 100 : 1 ;
36+ const valueToRound = value * scale ;
37+
38+ if ( format ?. roundingIncrement == null && format ?. roundingMode == null ) {
39+ return Number ( valueToRound . toFixed ( digits ) ) / scale ;
40+ }
41+
42+ const roundingFormatOptions : NumberFormatOptionsWithRounding = {
43+ useGrouping : false ,
44+ minimumFractionDigits : digits ,
45+ maximumFractionDigits : digits ,
46+ roundingIncrement : format ?. roundingIncrement ,
47+ roundingMode : format ?. roundingMode ,
48+ } ;
49+
50+ return Number ( getFormatter ( 'en-US' , roundingFormatOptions ) . format ( valueToRound ) ) / scale ;
2351}
2452
25- export function removeFloatingPointErrors ( value : number , format ?: Intl . NumberFormatOptions ) {
53+ export function removeFloatingPointErrors ( value : number , format ?: NumberFormatOptionsWithRounding ) {
2654 const { maximumFractionDigits } = getFractionDigits ( format ) ;
27- return roundToFractionDigits ( value , maximumFractionDigits ) ;
55+ return roundToFractionDigits ( value , maximumFractionDigits , format ) ;
2856}
2957
3058function snapToStep (
@@ -73,7 +101,7 @@ export function toValidatedNumber(
73101 minWithDefault : number ;
74102 maxWithDefault : number ;
75103 minWithZeroDefault : number ;
76- format : Intl . NumberFormatOptions | undefined ;
104+ format : NumberFormatOptionsWithRounding | undefined ;
77105 snapOnStep : boolean ;
78106 small : boolean ;
79107 clamp : boolean ;
0 commit comments