'use client'; import * as React from 'react'; import { Input } from '@/components/ui/input'; import { cn } from '@/lib/utils'; import { currencySymbol } from '@/lib/utils/currency'; interface CurrencyInputProps extends Omit< React.ComponentProps<'input'>, 'value' | 'onChange' | 'type' > { /** Controlled raw numeric value. `null` / `undefined` render empty. */ value: number | string | null | undefined; /** Fires with a raw number (or `null` if cleared). */ onChange: (value: number | null) => void; /** ISO currency code; renders as a leading symbol prefix. */ currency?: string; className?: string; } /** * Numeric input pre-decorated with a currency symbol. The display * value is the raw number the user typed (we don't fight the keystroke * cadence by re-formatting on every key) — formatted display lives in * read-only contexts via `formatCurrency()`. This keeps form behaviour * predictable while still scoping the input to a money field via the * symbol prefix and the `decimal` inputMode. */ export const CurrencyInput = React.forwardRef( ({ value, onChange, currency = 'USD', className, ...props }, ref) => { const symbol = currencySymbol(currency); const display = value === null || value === undefined || value === '' ? '' : String(value); return (
{symbol} { const raw = e.target.value; if (raw === '') { onChange(null); return; } const n = Number(raw); onChange(Number.isFinite(n) ? n : null); }} className={cn('pl-9 tabular-nums', className)} {...props} />
); }, ); CurrencyInput.displayName = 'CurrencyInput';