From 68030624f9291a7fc358d24a8040f839d8a24351 Mon Sep 17 00:00:00 2001 From: Thomas Allmer Date: Tue, 26 Nov 2019 18:00:58 +0100 Subject: [PATCH 1/2] fix(input-amount): prefer language while parsing --- packages/input-amount/src/parsers.js | 15 +++++-- packages/input-amount/test/parsers.test.js | 50 ++++++++++++---------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/packages/input-amount/src/parsers.js b/packages/input-amount/src/parsers.js index aeb76cb66..d63b499d5 100644 --- a/packages/input-amount/src/parsers.js +++ b/packages/input-amount/src/parsers.js @@ -11,9 +11,10 @@ function isDecimalSeparator(value) { /** * Determines the best possible parsing mode. * - * Parsemode depends mostely on the last 4 chars. - * - 1234 => xxx1234 (heuristic) + * - If there is only one separator (withLocale) * - 1,23 => xxx1.23 (heuristic) + * - else parse mode depends mostly on the last 4 chars + * - 1234 => xxx1234 (heuristic) * - [space]123 => xxx123 (heuristic) * - ,123 => unclear * - if 1.000,123 (we find a different separator) => 1000.123 (heuristic) @@ -30,7 +31,13 @@ function isDecimalSeparator(value) { * @param {string} value Clean number (only [0-9 ,.]) to be parsed * @return {string} unparseable|withLocale|heuristic */ -function getParseMode(value) { +function getParseMode(value, { mode = 'auto' } = {}) { + const separators = value.match(/[., ]/g); + + if (mode === 'auto' && separators && separators.length === 1) { + return 'withLocale'; + } + if (value.length > 4) { const charAtLastSeparatorPosition = value[value.length - 4]; if (isDecimalSeparator(charAtLastSeparatorPosition)) { @@ -120,7 +127,7 @@ export function parseAmount(value, options) { return undefined; } const cleanedInput = matchedInput.join(''); - const parseMode = getParseMode(cleanedInput); + const parseMode = getParseMode(cleanedInput, options); switch (parseMode) { case 'unparseable': return parseFloat(cleanedInput.match(/[0-9]/g).join('')); diff --git a/packages/input-amount/test/parsers.test.js b/packages/input-amount/test/parsers.test.js index 680293256..f8a9dec59 100644 --- a/packages/input-amount/test/parsers.test.js +++ b/packages/input-amount/test/parsers.test.js @@ -43,35 +43,35 @@ describe('parseAmount()', () => { expect(parseAmount('1 234,56789')).to.equal(1234.56789); }); - it('detects separators heuristically when there is only one e.g. 123456,78', () => { - expect(parseAmount('1.')).to.equal(1); - expect(parseAmount('1,')).to.equal(1); - expect(parseAmount('1 ')).to.equal(1); + it('detects separators heuristically when there is only one and "pasted" mode used e.g. 123456,78', () => { + expect(parseAmount('1.', { mode: 'pasted' })).to.equal(1); + expect(parseAmount('1,', { mode: 'pasted' })).to.equal(1); + expect(parseAmount('1 ', { mode: 'pasted' })).to.equal(1); - expect(parseAmount('1.2')).to.equal(1.2); - expect(parseAmount('1,2')).to.equal(1.2); - expect(parseAmount('1 2')).to.equal(12); + expect(parseAmount('1.2', { mode: 'pasted' })).to.equal(1.2); + expect(parseAmount('1,2', { mode: 'pasted' })).to.equal(1.2); + expect(parseAmount('1 2', { mode: 'pasted' })).to.equal(12); - expect(parseAmount('1.23')).to.equal(1.23); - expect(parseAmount('1,23')).to.equal(1.23); - expect(parseAmount('1 23')).to.equal(123); + expect(parseAmount('1.23', { mode: 'pasted' })).to.equal(1.23); + expect(parseAmount('1,23', { mode: 'pasted' })).to.equal(1.23); + expect(parseAmount('1 23', { mode: 'pasted' })).to.equal(123); - expect(parseAmount('1 234')).to.equal(1234); + expect(parseAmount('1 234', { mode: 'pasted' })).to.equal(1234); - expect(parseAmount('1.2345')).to.equal(1.2345); - expect(parseAmount('1,2345')).to.equal(1.2345); - expect(parseAmount('1 2345')).to.equal(12345); + expect(parseAmount('1.2345', { mode: 'pasted' })).to.equal(1.2345); + expect(parseAmount('1,2345', { mode: 'pasted' })).to.equal(1.2345); + expect(parseAmount('1 2345', { mode: 'pasted' })).to.equal(12345); - expect(parseAmount('1.23456')).to.equal(1.23456); - expect(parseAmount('1,23456')).to.equal(1.23456); - expect(parseAmount('1 23456')).to.equal(123456); + expect(parseAmount('1.23456', { mode: 'pasted' })).to.equal(1.23456); + expect(parseAmount('1,23456', { mode: 'pasted' })).to.equal(1.23456); + expect(parseAmount('1 23456', { mode: 'pasted' })).to.equal(123456); - expect(parseAmount('1.234567')).to.equal(1.234567); - expect(parseAmount('1,234567')).to.equal(1.234567); - expect(parseAmount('1 234567')).to.equal(1234567); + expect(parseAmount('1.234567', { mode: 'pasted' })).to.equal(1.234567); + expect(parseAmount('1,234567', { mode: 'pasted' })).to.equal(1.234567); + expect(parseAmount('1 234567', { mode: 'pasted' })).to.equal(1234567); - expect(parseAmount('123456,78')).to.equal(123456.78); - expect(parseAmount('123456.78')).to.equal(123456.78); + expect(parseAmount('123456,78', { mode: 'pasted' })).to.equal(123456.78); + expect(parseAmount('123456.78', { mode: 'pasted' })).to.equal(123456.78); }); it('detects separators heuristically when there are 2 same ones e.g. 1.234.56', () => { @@ -89,12 +89,16 @@ describe('parseAmount()', () => { expect(parseAmount('1,234,56789')).to.equal(1234.56789); }); - it('uses locale if amount can not be interpreted heuristically e.g. 1.234', () => { + it('uses locale to parse amount if there is only one separator e.g. 1.234', () => { localize.locale = 'en-GB'; + expect(parseAmount('12.34')).to.equal(12.34); + expect(parseAmount('12,34')).to.equal(1234); expect(parseAmount('1.234')).to.equal(1.234); expect(parseAmount('1,234')).to.equal(1234); localize.locale = 'nl-NL'; + expect(parseAmount('12.34')).to.equal(1234); + expect(parseAmount('12,34')).to.equal(12.34); expect(parseAmount('1.234')).to.equal(1234); expect(parseAmount('1,234')).to.equal(1.234); }); From 3d438fc1e0f214979bb6a4e6f7af0627b525e3e4 Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Tue, 26 Nov 2019 18:07:43 +0100 Subject: [PATCH 2/2] fix(input-amount): handle user pasting of amounts heuristically --- packages/field/src/FormatMixin.js | 6 +++++- packages/input-amount/src/LionInputAmount.js | 18 ++++++++++++++++++ packages/input-amount/stories/index.stories.js | 14 ++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/field/src/FormatMixin.js b/packages/field/src/FormatMixin.js index c59bb2fa9..b532d0102 100644 --- a/packages/field/src/FormatMixin.js +++ b/packages/field/src/FormatMixin.js @@ -310,12 +310,16 @@ export const FormatMixin = dedupeMixin( * `@user-input-changed` (this will happen later, when `formatOn` condition is met) */ _reflectBackFormattedValueToUser() { - if (!this.__isHandlingUserInput) { + if (this._reflectBackOn()) { // Text 'undefined' should not end up in this.value = typeof this.formattedValue !== 'undefined' ? this.formattedValue : ''; } } + _reflectBackOn() { + return !this.__isHandlingUserInput; + } + // This can be called whenever the view value should be updated. Dependent on component type // ("input" for or "change" for and it will become 4000 independent of your + locale.
+ If you write 4000,0 manually then it will become 4000 or 40000 dependent on your locale. +

`, );