react-currency-input-field
Version:
React <input/> component for formatting currency and numbers.
86 lines (74 loc) • 2.68 kB
text/typescript
import { parseAbbrValue } from './parseAbbrValue';
import { removeSeparators } from './removeSeparators';
import { removeInvalidChars } from './removeInvalidChars';
import { escapeRegExp } from './escapeRegExp';
import { CurrencyInputProps } from '../CurrencyInputProps';
export type CleanValueOptions = Pick<
CurrencyInputProps,
| 'decimalSeparator'
| 'groupSeparator'
| 'allowDecimals'
| 'decimalsLimit'
| 'allowNegativeValue'
| 'disableAbbreviations'
| 'prefix'
| 'transformRawValue'
> & { value: string };
/**
* Remove prefix, separators and extra decimals from value
*/
export const cleanValue = ({
value,
groupSeparator = ',',
decimalSeparator = '.',
allowDecimals = true,
decimalsLimit = 2,
allowNegativeValue = true,
disableAbbreviations = false,
prefix = '',
transformRawValue = (rawValue) => rawValue,
}: CleanValueOptions): string => {
const transformedValue = transformRawValue(value);
if (transformedValue === '-') {
return transformedValue;
}
const abbreviations = disableAbbreviations ? [] : ['k', 'm', 'b'];
const reg = new RegExp(`((^|\\D)-\\d)|(-${escapeRegExp(prefix)})`);
const isNegative = reg.test(transformedValue);
// Is there a digit before the prefix? eg. 1$
const [prefixWithValue, preValue] = RegExp(`(\\d+)-?${escapeRegExp(prefix)}`).exec(value) || [];
const withoutPrefix = prefix
? prefixWithValue
? transformedValue.replace(prefixWithValue, '').concat(preValue)
: transformedValue.replace(prefix, '')
: transformedValue;
const withoutSeparators = removeSeparators(withoutPrefix, groupSeparator);
const withoutInvalidChars = removeInvalidChars(withoutSeparators, [
groupSeparator,
decimalSeparator,
...abbreviations,
]);
let valueOnly = withoutInvalidChars;
if (!disableAbbreviations) {
// disallow letter without number
if (
abbreviations.some(
(letter) => letter === withoutInvalidChars.toLowerCase().replace(decimalSeparator, '')
)
) {
return '';
}
const parsed = parseAbbrValue(withoutInvalidChars, decimalSeparator);
if (parsed) {
valueOnly = String(parsed);
}
}
const includeNegative = isNegative && allowNegativeValue ? '-' : '';
if (decimalSeparator && valueOnly.includes(decimalSeparator)) {
const [int, decimals] = withoutInvalidChars.split(decimalSeparator);
const trimmedDecimals = decimalsLimit && decimals ? decimals.slice(0, decimalsLimit) : decimals;
const includeDecimals = allowDecimals ? `${decimalSeparator}${trimmedDecimals}` : '';
return `${includeNegative}${int}${includeDecimals}`;
}
return `${includeNegative}${valueOnly}`;
};