diff --git a/src/numeric_format.tsx b/src/numeric_format.tsx index 6daba3ca..4effc42f 100644 --- a/src/numeric_format.tsx +++ b/src/numeric_format.tsx @@ -96,7 +96,7 @@ function getSeparators(props: NumericFormatProps { + /** + * 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 = 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; + } + + let charsToRemove = hasNegation ? 1 : 0; + if (hasDoubleNegation) charsToRemove = 2; + + // remove negation/double negation from start to simplify prefix logic as negation comes before prefix + if (charsToRemove) { + value = value.substring(charsToRemove); + + // account for the removal of the negation for start and end index + start -= charsToRemove; + end -= charsToRemove; + } + + return { value, start, end, hasNegation }; +}; + export function removeFormatting( value: string, changeMeta: ChangeMeta = getDefaultChangeMeta(value), @@ -163,42 +204,7 @@ export function removeFormatting( value = value.substring(0, start) + separator + value.substring(start + 1, value.length); } - const stripNegation = (value: string, start: number, end: number) => { - /** - * 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 = 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; - } - - let charsToRemove = hasNegation ? 1 : 0; - if (hasDoubleNegation) charsToRemove = 2; - - // remove negation/double negation from start to simplify prefix logic as negation comes before prefix - if (charsToRemove) { - value = value.substring(charsToRemove); - - // account for the removal of the negation for start and end index - start -= charsToRemove; - end -= charsToRemove; - } - - return { value, start, end, hasNegation }; - }; - - const toMetadata = stripNegation(value, start, end); + const toMetadata = stripNegation(value, start, end, prefix, suffix); const { hasNegation } = toMetadata; ({ value, start, end } = toMetadata); @@ -206,7 +212,7 @@ export function removeFormatting( start: fromStart, end: fromEnd, value: lastValue, - } = stripNegation(changeMeta.lastValue, from.start, from.end); + } = stripNegation(changeMeta.lastValue, from.start, from.end, prefix, suffix); // if only prefix and suffix part is updated reset the value to last value // if the changed range is from suffix in the updated value, and the the suffix starts with the same characters, allow the change diff --git a/test/library/utils/numeric-format/handle-negation.spec.ts b/test/library/utils/numeric-format/handle-negation.spec.ts new file mode 100644 index 00000000..20aab3df --- /dev/null +++ b/test/library/utils/numeric-format/handle-negation.spec.ts @@ -0,0 +1,39 @@ +import { handleNegation } from '../../../../src/numeric_format'; +import { TestCases } from '../common'; + +type Expected = string; + +type Arguments = { + value: string; + allowNegative: boolean; +}; + +describe('handleNegation', () => { + const testCases: TestCases[] = [ + { + label: 'negative integers', + cases: [ + { arguments: { value: '-10-1000', allowNegative: true }, expected: '-10' }, + { arguments: { value: '-110', allowNegative: false }, expected: '110' }, + ], + }, + { + label: 'negative floats', + cases: [ + { arguments: { value: '-10.1', allowNegative: true }, expected: '-10.1' }, + { arguments: { value: '-110.100', allowNegative: false }, expected: '110.100' }, + ], + }, + ]; + + for (const testCase of testCases) { + describe.only(testCase.label, () => { + test.each(testCase.cases)( + '%arguments.value', + ({ arguments: { value, allowNegative }, expected }) => { + expect(handleNegation(value, allowNegative)).toEqual(expected); + }, + ); + }); + } +}); diff --git a/test/library/utils/numeric-format/remove-formatting.spec.ts b/test/library/utils/numeric-format/remove-formatting.spec.ts new file mode 100644 index 00000000..dfd6c75b --- /dev/null +++ b/test/library/utils/numeric-format/remove-formatting.spec.ts @@ -0,0 +1,54 @@ +import { removeFormatting } from '../../../../src/numeric_format'; +import { ChangeMeta, InputAttributes, NumericFormatProps } from '../../../../src/types'; +import { TestCases } from '../common'; + +type Expected = string; + +type Arguments = { + value: string; + changeMeta: ChangeMeta; + props: NumericFormatProps; +}; + +describe('removeFormatting', () => { + const defaultProps = { allowNegative: true, decimalScale: 2, thousandSeparator: ',' }; + + const testCases: TestCases[] = [ + { + label: 'with prefix and suffix', + cases: [ + { + arguments: { + value: '100-1000 USD', + changeMeta: { from: { start: 0, end: 0 }, to: { start: 0, end: 12 }, lastValue: '' }, + props: { ...defaultProps, prefix: '100-', suffix: '000 USD' }, + }, + expected: '1', + }, + { + arguments: { + value: '100-10000 USD', + changeMeta: { + from: { start: 8, end: 8 }, + to: { start: 8, end: 9 }, + lastValue: '100-10000 USD', + }, + props: { ...defaultProps, prefix: '100-', suffix: '000 USD' }, + }, + expected: '10', + }, + ], + }, + ]; + + for (const testCase of testCases) { + describe(testCase.label, () => { + test.each(testCase.cases)( + '%arguments.value', + ({ arguments: { value, changeMeta, props }, expected }) => { + expect(removeFormatting(value, changeMeta, props)).toBe(expected); + }, + ); + }); + } +}); diff --git a/test/library/utils/numeric-format/strip-negation.spec.ts b/test/library/utils/numeric-format/strip-negation.spec.ts new file mode 100644 index 00000000..a1fac78f --- /dev/null +++ b/test/library/utils/numeric-format/strip-negation.spec.ts @@ -0,0 +1,56 @@ +import { stripNegation } from '../../../../src/numeric_format'; +import { TestCases } from '../common'; + +type Expected = { + value: string; + start: number; + end: number; + hasNegation: boolean; +}; + +type Arguments = { + value: string; + start: number; + end: number; + prefix: string; + suffix: string; +}; + +describe('stripNegation', () => { + const testCases: TestCases[] = [ + { + label: 'negative floats', + cases: [ + { + arguments: { value: '0.0345', start: 0, end: 6, prefix: '100-', suffix: '1000 USD' }, + expected: { value: '0.0345', start: 0, end: 6, hasNegation: false }, + }, + { + arguments: { value: '-0.0345', start: 0, end: 6, prefix: '100-', suffix: '1000 USD' }, + expected: { value: '0.0345', start: 0, end: 1, hasNegation: true }, + }, + { + arguments: { + value: '100-10000 USD', + start: 8, + end: 8, + prefix: '100-', + suffix: '1000 USD', + }, + expected: { value: '100-10000 USD', start: 8, end: 8, hasNegation: false }, + }, + ], + }, + ]; + + for (const testCase of testCases) { + describe(testCase.label, () => { + test.each(testCase.cases)( + '%arguments.value', + ({ arguments: { value, start, end, prefix, suffix }, expected }) => { + expect(stripNegation(value, start, end, prefix, suffix)).toEqual(expected); + }, + ); + }); + } +});