diff --git a/src/components/react-hook-form/numbers/float-input.js b/src/components/react-hook-form/numbers/float-input.js index 83bcaf16..433d9e04 100644 --- a/src/components/react-hook-form/numbers/float-input.js +++ b/src/components/react-hook-form/numbers/float-input.js @@ -15,7 +15,7 @@ import { isFloatNumber } from './utils'; // uses the same string representation as the intermediate text that the user // typed. For example, if the user wants to input "625", they will write "6" // and then "62" and then "625". The intermediate strings are numbers that have -// nothing in common with the desired number but their normalization is the +// nothing in common with the final number but their normalization is the // same as what was typed by the user. With exponential notation, if the user // wants to input "12.5e21", at the intermediate step of "12.5e2" their input // is normalized to "1.25e3" and after adding the final "1" they get "12.5e31" @@ -34,7 +34,6 @@ const normalizeFixed = (number) => { const FloatInput = (props) => { const inputTransform = (value) => { - // do we want to handle infinities here ? if (typeof value == 'number' && !isNaN(value)) { // if we have a parsed real number, normalize like we do after each // keystroke in outputTransform for consistency. We get parsed @@ -44,10 +43,11 @@ const FloatInput = (props) => { } else { // The user is editing, leave as is because we already did what we // need to do in outputTransform after the previous keystroke. - // NOTE: To avoid "bad things", we clear the text on NaN, so we need to - // special case known inputs that would be rejected by isNaN but are accepted by - // our acceptValue because they are need as intermediate strings for the - // user to input useful numbers. + // NOTE: To avoid "bad things" we haven't predicted and be extra + // cautious, we clear the text on NaN, so we need to special case + // known inputs that would be rejected by isNaN but are accepted by + // our acceptValue because they are needed as intermediate strings + // for the user to input useful numbers. // TODO can we remove the isNaN check and the special cases check? if (['-', '.'].includes(value)) { return value; @@ -65,7 +65,27 @@ const FloatInput = (props) => { } const tmp = value?.replace(',', '.') || ''; - if (tmp.endsWith('.') || tmp.endsWith('0')) { + + // Can't show the normalization to the user when the fractional part + // ends with 0 because normalizing removes the trailing zeroes and prevents + // inputting the required intermediate strings (e.g "1." or "1.0" to input "1.02") + // So we return the user string instead. This has the downside that + // when the user finally writes a non 0 digit at the end, the normalization takes place + // and may startle the user when changing a lot of its input text. + // For example: + // - "1.00000000000000000000000000" and then press any non zero digit + // removes all the zeroes at once + // - "1." or "1.0" and then left arrow to move the cursor to the left and then inputting many digits + // disables all normalization, can write huge numbers that are not rounded like + // - 1231231231241231241231245123124234234123123124234. + // vs 1231231231241231300000000000000000000000000000000 + // - 1.4312322342321323434534234235234 + // vs 1.4312322342321324 + // Note: this is a symmetric problem inputting many zeros + // to the left of a number to allow to input a final leading nonzero + // digit, but users never want to do that, unlike inputting trailing zeroes in the + // fractional part before inputing the final trailing non zero digit + if (tmp.endsWith('.') || (tmp.includes('.') && tmp.endsWith('0'))) { return tmp; }