diff --git a/documentation/v5/docs/numeric_format.md b/documentation/v5/docs/numeric_format.md
index abc573b9..999aa0ff 100644
--- a/documentation/v5/docs/numeric_format.md
+++ b/documentation/v5/docs/numeric_format.md
@@ -130,6 +130,31 @@ import { NumericFormat } from 'react-number-format';
>
+### minDecimalScale `number`
+
+**default**: `undefined`
+
+If defined, it enforces a minimum number of digits after the decimal point.
+
+```js
+import { NumericFormat } from 'react-number-format';
+
+;
+```
+
+
+
+ Demo
+
+
+
+
+
### decimalSeparator `string`
**default**: '.'
diff --git a/src/numeric_format.tsx b/src/numeric_format.tsx
index 07c5485e..8b08c9b3 100644
--- a/src/numeric_format.tsx
+++ b/src/numeric_format.tsx
@@ -1,30 +1,30 @@
import React from 'react';
+import NumberFormatBase from './number_format_base';
+import {
+ ChangeMeta,
+ FormatInputValueFunction,
+ InputAttributes,
+ NumberFormatBaseProps,
+ NumericFormatProps,
+ RemoveFormattingFunction,
+ SourceType,
+} from './types';
import {
- escapeRegExp,
- splitDecimal,
- limitToScale,
applyThousandSeparator,
- getDefaultChangeMeta,
+ charIsNumber,
+ escapeRegExp,
fixLeadingZero,
- noop,
- useInternalValues,
+ getDefaultChangeMeta,
+ isNanValue,
isNil,
+ limitToScale,
+ noop,
roundToPrecision,
- isNanValue,
setCaretPosition,
+ splitDecimal,
toNumericString,
- charIsNumber,
+ useInternalValues,
} from './utils';
-import {
- NumericFormatProps,
- ChangeMeta,
- SourceType,
- InputAttributes,
- FormatInputValueFunction,
- RemoveFormattingFunction,
- NumberFormatBaseProps,
-} from './types';
-import NumberFormatBase from './number_format_base';
export function format(
numStr: string,
@@ -32,6 +32,7 @@ export function format(
) {
const {
decimalScale,
+ minDecimalScale,
fixedDecimalScale,
prefix = '',
suffix = '',
@@ -52,13 +53,15 @@ export function format(
* Or if decimalScale is > 0 and fixeDecimalScale is true (even if numStr has no decimal)
*/
const hasDecimalSeparator =
- (decimalScale !== 0 && numStr.indexOf('.') !== -1) || (decimalScale && fixedDecimalScale);
+ (decimalScale !== 0 && numStr.indexOf('.') !== -1) ||
+ (decimalScale && fixedDecimalScale) ||
+ (minDecimalScale && minDecimalScale !== 0);
let { beforeDecimal, afterDecimal, addNegation } = splitDecimal(numStr, allowNegative); // eslint-disable-line prefer-const
//apply decimal precision if its defined
- if (decimalScale !== undefined) {
- afterDecimal = limitToScale(afterDecimal, decimalScale, !!fixedDecimalScale);
+ if (decimalScale !== undefined || minDecimalScale !== undefined) {
+ afterDecimal = limitToScale(afterDecimal, decimalScale, minDecimalScale, !!fixedDecimalScale);
}
if (thousandSeparator) {
@@ -333,6 +336,7 @@ export function useNumericFormat(
onBlur = noop,
thousandSeparator,
decimalScale,
+ minDecimalScale,
fixedDecimalScale,
prefix = '',
defaultValue,
@@ -367,7 +371,7 @@ export function useNumericFormat(
* we don't need to do it for onChange events, as we want to prevent typing there
*/
if (_valueIsNumericString && typeof decimalScale === 'number') {
- return roundToPrecision(value, decimalScale, Boolean(fixedDecimalScale));
+ return roundToPrecision(value, decimalScale, minDecimalScale, Boolean(fixedDecimalScale));
}
return value;
@@ -449,8 +453,8 @@ export function useNumericFormat(
}
// apply fixedDecimalScale on blur event
- if (fixedDecimalScale && decimalScale) {
- _value = roundToPrecision(_value, decimalScale, fixedDecimalScale);
+ if ((fixedDecimalScale && decimalScale) || minDecimalScale) {
+ _value = roundToPrecision(_value, decimalScale, minDecimalScale, fixedDecimalScale);
}
if (_value !== numAsString) {
diff --git a/src/types.ts b/src/types.ts
index 8abef042..4d8aee7f 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -96,6 +96,7 @@ export type NumericFormatProps = NumberFormatProps<
allowedDecimalSeparators?: Array;
thousandsGroupStyle?: 'thousand' | 'lakh' | 'wan' | 'none';
decimalScale?: number;
+ minDecimalScale?: number;
fixedDecimalScale?: boolean;
allowNegative?: boolean;
allowLeadingZeros?: boolean;
diff --git a/src/utils.tsx b/src/utils.tsx
index e826a019..b01b18d8 100644
--- a/src/utils.tsx
+++ b/src/utils.tsx
@@ -1,5 +1,5 @@
import { useMemo, useRef, useState } from 'react';
-import { NumberFormatBaseProps, FormatInputValueFunction, OnValueChange } from './types';
+import { FormatInputValueFunction, NumberFormatBaseProps, OnValueChange } from './types';
// basic noop function
export function noop() {}
@@ -98,11 +98,20 @@ export function fixLeadingZero(numStr?: string) {
* limit decimal numbers to given scale
* Not used .fixedTo because that will break with big numbers
*/
-export function limitToScale(numStr: string, scale: number, fixedDecimalScale: boolean) {
+export function limitToScale(
+ numStr: string,
+ scale: number,
+ minDecimalScale: number,
+ fixedDecimalScale: boolean,
+) {
let str = '';
const filler = fixedDecimalScale ? '0' : '';
for (let i = 0; i <= scale - 1; i++) {
- str += numStr[i] || filler;
+ if (i < minDecimalScale) {
+ str += numStr[i] || '0';
+ } else {
+ str += numStr[i] || filler;
+ }
}
return str;
}
@@ -157,11 +166,17 @@ export function toNumericString(num: string | number) {
* This method is required to round prop value to given scale.
* Not used .round or .fixedTo because that will break with big numbers
*/
-export function roundToPrecision(numStr: string, scale: number, fixedDecimalScale: boolean) {
+export function roundToPrecision(
+ numStr: string,
+ scale: number,
+ minDecimalScale: number,
+ fixedDecimalScale: boolean,
+) {
//if number is empty don't do anything return empty string
if (['', '-'].indexOf(numStr) !== -1) return numStr;
- const shouldHaveDecimalSeparator = (numStr.indexOf('.') !== -1 || fixedDecimalScale) && scale;
+ const shouldHaveDecimalSeparator =
+ (numStr.indexOf('.') !== -1 || fixedDecimalScale || minDecimalScale) && scale;
const { beforeDecimal, afterDecimal, hasNegation } = splitDecimal(numStr);
const floatValue = parseFloat(`0.${afterDecimal || '0'}`);
const floatValueStr =
@@ -180,7 +195,12 @@ export function roundToPrecision(numStr: string, scale: number, fixedDecimalScal
return current + roundedStr;
}, roundedDecimalParts[0]);
- const decimalPart = limitToScale(roundedDecimalParts[1] || '', scale, fixedDecimalScale);
+ const decimalPart = limitToScale(
+ roundedDecimalParts[1] || '',
+ scale,
+ minDecimalScale,
+ fixedDecimalScale,
+ );
const negation = hasNegation ? '-' : '';
const decimalSeparator = shouldHaveDecimalSeparator ? '.' : '';
return `${negation}${intPart}${decimalSeparator}${decimalPart}`;
diff --git a/test/library/input_numeric_format.spec.js b/test/library/input_numeric_format.spec.js
index 7d565178..985755e1 100644
--- a/test/library/input_numeric_format.spec.js
+++ b/test/library/input_numeric_format.spec.js
@@ -215,6 +215,22 @@ describe('Test NumberFormat as input with numeric format options', () => {
expect(getInputValue(wrapper)).toEqual('4111.11');
});
+ it('should enforce a minimum decimal scale if specified', () => {
+ const wrapper = mount();
+ expect(getInputValue(wrapper)).toEqual('24.00');
+
+ const input = wrapper.find('input');
+ input.simulate('change', getCustomEvent('24.1234'));
+ expect(getInputValue(wrapper)).toEqual('24.1234');
+
+ input.simulate('change', getCustomEvent('24.1234567890'));
+ expect(getInputValue(wrapper)).toEqual('24.12345678');
+
+ // Rounding logic
+ wrapper.setProps({ value: 24.123456789 });
+ expect(getInputValue(wrapper)).toEqual('24.12345679');
+ });
+
it('should not add zeros to fixedDecimalScale is not set', () => {
const wrapper = mount();
expect(getInputValue(wrapper)).toEqual('24.45');