From b70dee2b83d06db3cbfe6d364bf0e8cc5d58d1ad Mon Sep 17 00:00:00 2001 From: Sudhanshu Date: Sun, 5 Mar 2023 20:48:54 +0530 Subject: [PATCH] - Fix for 691. --- example/src/index.js | 1 - package.json | 2 +- src/numeric_format.tsx | 64 ++++++++++++++++++----- test/library/input_numeric_format.spec.js | 60 +++++++++++++++------ 4 files changed, 97 insertions(+), 30 deletions(-) diff --git a/example/src/index.js b/example/src/index.js index 3ffbff36..17e7402c 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -21,7 +21,6 @@ class App extends React.Component { return (
-

Prefix and thousand separator : Format currency as text

diff --git a/package.json b/package.json index 72a61c5c..5e280bd9 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-number-format", "description": "React component to format number in an input or as a text.", - "version": "5.1.3", + "version": "5.1.4", "main": "dist/react-number-format.cjs.js", "module": "dist/react-number-format.es.js", "types": "types/index.d.ts", diff --git a/src/numeric_format.tsx b/src/numeric_format.tsx index 47cd7e7a..07c5485e 100644 --- a/src/numeric_format.tsx +++ b/src/numeric_format.tsx @@ -35,7 +35,7 @@ export function format( fixedDecimalScale, prefix = '', suffix = '', - allowNegative = true, + allowNegative, thousandsGroupStyle = 'thousand', } = props; @@ -123,13 +123,25 @@ export function removeFormatting( changeMeta: ChangeMeta = getDefaultChangeMeta(value), props: NumericFormatProps, ) { - const { allowNegative = true, prefix = '', suffix = '', decimalScale } = props; + const { allowNegative, prefix = '', suffix = '', decimalScale } = props; const { from, to } = changeMeta; let { start, end } = to; const { allowedDecimalSeparators, decimalSeparator } = getSeparators(props); const isBeforeDecimalSeparator = value[end] === decimalSeparator; + /** + * If only a number is added on empty input which matches with the prefix or suffix, + * then don't remove it, just return the same + */ + if ( + charIsNumber(value) && + (value === prefix || value === suffix) && + changeMeta.lastValue === '' + ) { + return value; + } + /** Check for any allowed decimal separator is added in the numeric format and replace it with decimal separator */ if (end - start === 1 && allowedDecimalSeparators.indexOf(value[start]) !== -1) { const separator = decimalScale === 0 ? '' : decimalSeparator; @@ -138,18 +150,23 @@ export function removeFormatting( const stripNegation = (value: string, start: number, end: number) => { /** - * if prefix starts with - the number hast to have two - at the start + * if prefix starts with - we don't allow negative number to avoid confusion * if suffix starts with - and the value length is same as suffix length, then the - sign is from the suffix * In other cases, if the value starts with - then it is a negation */ let hasNegation = false; let hasDoubleNegation = false; - if (prefix.startsWith('-')) hasNegation = !value.startsWith('--'); - else if (value.startsWith('--')) { + + if (prefix.startsWith('-')) { + hasNegation = false; + } else if (value.startsWith('--')) { hasNegation = false; hasDoubleNegation = true; - } else if (suffix.startsWith('-') && value.length === suffix.length) hasNegation = false; - else if (value[0] === '-') hasNegation = true; + } else if (suffix.startsWith('-') && value.length === suffix.length) { + hasNegation = false; + } else if (value[0] === '-') { + hasNegation = true; + } let charsToRemove = hasNegation ? 1 : 0; if (hasDoubleNegation) charsToRemove = 2; @@ -267,8 +284,10 @@ export function getCaretBoundary( return boundaryAry; } -function validateProps(props: NumericFormatProps) { +function validateAndUpdateProps(props: NumericFormatProps) { const { thousandSeparator, decimalSeparator } = getSeparators(props); + // eslint-disable-next-line prefer-const + let { prefix = '', allowNegative = true } = props; if (thousandSeparator === decimalSeparator) { throw new Error(` @@ -277,11 +296,30 @@ function validateProps(props: NumericFormatProps( props: NumericFormatProps, ): NumberFormatBaseProps { + // validate props + props = validateAndUpdateProps(props); + const { decimalSeparator = '.', /* eslint-disable no-unused-vars */ @@ -304,9 +342,6 @@ export function useNumericFormat( ...restProps } = props; - // validate props - validateProps(props); - const _format: FormatInputValueFunction = (numStr) => format(numStr, props); const _removeFormatting: RemoveFormattingFunction = (inputValue, changeMeta) => @@ -359,7 +394,12 @@ export function useNumericFormat( } // if user hits backspace, while the cursor is before prefix, and the input has negation, remove the negation - if (key === 'Backspace' && value[0] === '-' && selectionStart === prefix.length + 1) { + if ( + key === 'Backspace' && + value[0] === '-' && + selectionStart === prefix.length + 1 && + allowNegative + ) { // bring the cursor to after negation setCaretPosition(el, 1); } diff --git a/test/library/input_numeric_format.spec.js b/test/library/input_numeric_format.spec.js index dee31f87..7d565178 100644 --- a/test/library/input_numeric_format.spec.js +++ b/test/library/input_numeric_format.spec.js @@ -10,6 +10,8 @@ import { mount, shallow, getInputValue, + render, + simulateNativeKeyInput, } from '../test_util'; /** @@ -685,33 +687,59 @@ describe('Test NumberFormat as input with numeric format options', () => { expect(wrapper.find('input').prop('value')).toEqual('0.00000001'); }); + describe('should allow typing number if prefix or suffix is just an number #691', () => { + it('when prefix is number', async () => { + const { input } = await render(); + simulateNativeKeyInput(input, '1', 0, 0); + expect(input.value).toEqual('11'); + }); + + it('when prefix is multiple digit', async () => { + const { input } = await render(); + simulateNativeKeyInput(input, '11', 0, 0); + expect(input.value).toEqual('1111'); + }); + + it('when suffix is number', async () => { + const { input } = await render(); + simulateNativeKeyInput(input, '1', 0, 0); + expect(input.value).toEqual('11'); + }); + + it('when prefix and suffix both are number', async () => { + const { input } = await render(); + simulateNativeKeyInput(input, '1', 0, 0); + expect(input.value).toEqual('111'); + }); + }); + describe('should handle if only partial prefix or suffix is removed using double click select and the remove. #694', () => { - it('while changing suffix', () => { - const wrapper = mount(); + it('while changing suffix', async () => { + const { input } = await render(); - simulateKeyInput(wrapper.find('input'), '2', 9, 12); - expect(wrapper.find('input').prop('value')).toEqual('100-1000 USD'); + simulateNativeKeyInput(input, '2', 9, 12); + expect(input.value).toEqual('100-1000 USD'); }); - it('while changing prefix', () => { - const wrapper = mount(); + it('while changing prefix', async () => { + const { input } = await render(); - simulateKeyInput(wrapper.find('input'), '2', 0, 2); - expect(wrapper.find('input').prop('value')).toEqual('100-1000 USD'); + simulateNativeKeyInput(input, '2', 0, 2); + expect(input.value).toEqual('100-1000 USD'); }); - it('while deleting suffix', () => { - const wrapper = mount(); + it('while deleting suffix', async () => { + const { input } = await render(); - simulateKeyInput(wrapper.find('input'), 'Backspace', 9, 12); - expect(wrapper.find('input').prop('value')).toEqual('100-1000 USD'); + simulateNativeKeyInput(input, 'Backspace', 9, 12); + expect(input.value).toEqual('100-1000 USD'); }); - fit('while deleting prefix', () => { - const wrapper = mount(); + it('while deleting prefix', async () => { + const { input } = await render(); - simulateKeyInput(wrapper.find('input'), 'Backspace', 0, 3); - expect(wrapper.find('input').prop('value')).toEqual('100-1000 USD'); + simulateNativeKeyInput(input, 'Backspace', 0, 3); + expect(input.value).toEqual('100-1000 USD'); }); });