tremorlabs / tremor

React components to build charts and dashboards
https://npm.tremor.so
Apache License 2.0
16.22k stars 467 forks source link

feat: (#922) add Intl.NumberFormat for numeric inputs #1111

Open hikinine opened 3 months ago

hikinine commented 3 months ago

Description As discussed in #922 , this feature attempts to add formatting functionality using the Intl.NumberFormat pattern.

Related issue(s) References https://github.com/tremorlabs/tremor/issues/922

What kind of change does this PR introduce? (check at least one)

Does this PR introduce a breaking change? (check one)

Problems found

At first, I tried to solve it in the most ideal way possible, which would be to separate the renderFormattedValue from the value. Display the renderFormattedValuewhile behind the scenes the ref value would be the original number.

PROBLEM

Lets picture the following scenario:

const formatter = new Intl.NumberFormat("en-US", { style: 'currency', currency: 'USD' }
return (
  <NumericInput formatter={formatter) />
)

1 - Input is blank 2 - You focus the input 3 - You type 1000 (that means...) 4 - Type the number 1 5 - Type the number 0 6 - Type the number 0 7 - Type the number 0

Problem (step 4) is that when you type 1, we already format the number to formatter which results on 1.00. Yet, you can still typing the rest of the sentence...

Problem really starts when you BLUR it and then FOCUS again. Your current display level will be $ 1,000.00 and cursor will be on the right side by default. If you try to maybe add 50 cents to actual number, expecting having $1,000.50, then nothing will happening because if your cursor will be on the decimal parts. 1 - You try to backspace and nothing happen (since you delete one of the decimal digits, but onChanges format it back leading the two cents back to zero) 2 - You try to type 50, and nothing happen (since you including a third decimal part on the number, onChange format it back leading two cents back to zero) 3 - You move cursor, and add 5 before the two zeros (which looks obvious, but its leads in ALOT on poor UX, cursor jumps it to right side, etc). But works... with very very poor ux.

If we had an unformatter method that takes que formatted value and pull back to number. With that we should not need handle two separate states. Unformatter does not exist on Intl.Numberformat api. There is some community implementation but is not stable at all and dont coverage half of possible Intl configuration.

What I did instead.

Control the display and ref value with isFocused status.

FOCUS = true

InputType = 'number' Value = original reference value

Focus = false

InputType = 'string' Value = display formatted value

Basically, onBlur and onFocus, changes input to display reference value or formatted value. It is not the best solution, i still think that is possible to just EDIT an formatted value with an good UX (we do it normally using regex patterns for an single input) Problem is to map every single possible format and then control it.

Summary

Works as expected with a little less UX experience since you are editing an plain number, not an formatted number. (which will be formatted on blur)

vercel[bot] commented 3 months ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
tremor-storybook ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 8, 2024 3:08pm