diff --git a/src/components/input-elements/BaseInput.tsx b/src/components/input-elements/BaseInput.tsx index e0a754b41..0fc65a7f4 100644 --- a/src/components/input-elements/BaseInput.tsx +++ b/src/components/input-elements/BaseInput.tsx @@ -1,5 +1,5 @@ "use client"; -import React, { ReactNode, useCallback, useRef, useState } from "react"; +import React, { ReactNode, useCallback, useMemo, useRef, useState } from "react"; import { ExclamationFilledIcon, EyeIcon, EyeOffIcon } from "assets"; import { getSelectButtonColors, hasValue } from "components/input-elements/selectUtils"; import { mergeRefs, tremorTwMerge } from "lib"; @@ -15,6 +15,7 @@ export interface BaseInputProps extends React.InputHTMLAttributes void; makeInputClassName: (className: string) => string; + formatter?: Intl.NumberFormat; } const BaseInput = React.forwardRef((props, ref) => { @@ -33,16 +34,44 @@ const BaseInput = React.forwardRef((props, ref onChange, onValueChange, autoFocus, + formatter, ...other } = props; + const [isFocused, setIsFocused] = useState(autoFocus || false); const [isPasswordVisible, setIsPasswordVisible] = useState(false); + const [numberValue, setNumberValue] = useState(() => { + if (type === "number" && (typeof defaultValue === "number" || typeof value === "number")) { + return Number(value) ?? Number(defaultValue); + } + }); + const [formatedValue, setFormatedValue] = useState(() => { + if (formatter && formatter instanceof Intl.NumberFormat && type === "number") { + return formatter.format(Number(value) ?? defaultValue); + } + }); + const toggleIsPasswordVisible = useCallback( () => setIsPasswordVisible(!isPasswordVisible), [isPasswordVisible, setIsPasswordVisible], ); + const { resolvedType, resolvedValue } = useMemo(() => { + let resolvedType = isPasswordVisible ? "text" : type; + if (type === "number") { + resolvedType = isFocused ? "number" : "text"; + } + + let resolvedValue = value; + if (type === "number") { + const valueOrNumberValue = value ?? numberValue; + resolvedValue = isFocused ? valueOrNumberValue : formatedValue; + } + + return { resolvedType, resolvedValue }; + }, [isPasswordVisible, type, value, numberValue, formatedValue, isFocused]); + const Icon = icon; const inputRef = useRef(null); @@ -112,8 +141,8 @@ const BaseInput = React.forwardRef((props, ref ((props, ref disabled={disabled} data-testid="base-input" onChange={(e) => { - onChange?.(e); - onValueChange?.(e.target.value); + if (type === "number") { + const value = Number(e.target.value); + onChange?.(e); + onValueChange?.(value); + setNumberValue(value); + + if (formatter && formatter instanceof Intl.NumberFormat) { + const formattedValue = formatter.format(value); + setFormatedValue(formattedValue); + } + } else { + onChange?.(e); + onValueChange?.(e.target.value); + } }} {...other} /> diff --git a/src/stories/input-elements/NumberInput.stories.tsx b/src/stories/input-elements/NumberInput.stories.tsx index 845aa44cb..b52ea95a8 100644 --- a/src/stories/input-elements/NumberInput.stories.tsx +++ b/src/stories/input-elements/NumberInput.stories.tsx @@ -106,3 +106,8 @@ export const ControlledWithOnChange: Story = { render: SimpleNumberInputControlled, args: {}, }; + +export const WithIntlNumberFormatter: Story = { + render: SimpleNumberInputControlled, + args: {}, +}; diff --git a/src/stories/input-elements/helpers/SimpleNumberInput.tsx b/src/stories/input-elements/helpers/SimpleNumberInput.tsx index 982c9cd6a..3afc58dd5 100644 --- a/src/stories/input-elements/helpers/SimpleNumberInput.tsx +++ b/src/stories/input-elements/helpers/SimpleNumberInput.tsx @@ -44,29 +44,40 @@ export const SimpleNumberInput = (args: any) => { }; export const SimpleNumberInputControlled = (args: any) => { - const [value, setValue] = React.useState(0); + const [value, setValue] = React.useState(333); return ( <>
{ e.preventDefault(); }} - onReset={() => setValue(0)} > + setValue(Number(e.target.value))} + formatter={new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" })} + /> + setValue(Number(e.target.value))} + formatter={new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })} /> + +

value: {value}

-

value: {value}

); };