UNPKG

@kadconsulting/dry

Version:
91 lines 5.21 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useRef, useMemo, useState, forwardRef, useCallback, useLayoutEffect, } from 'react'; import './CurrencyInput.scss'; import TextInput, { BASE_INPUT_PADDING_HORIZONTAL, } from '../../../../components/TextInput/TextInput'; import { CURRENCIES } from './currencies'; import { Icon } from '../../../../components/Icons/Icon'; import { TextMd } from '../../../../components/Typography'; import { AlertCircle, ChevronDown, HelpCircle, } from '../../../../components/Icons/paths'; const CurrencyInput = forwardRef(({ id, onCurrencyChange, HintText, ErrorText, ...props }, ref) => { const [currentCurrency, setCurrentCurrency] = useState(CURRENCIES.USD); const [rightAdornmentWidth, setRightAdornmentWidth] = useState(60); const rightAdornmentRef = useRef(null); const CurrencyOptions = useMemo(() => Object.keys(CURRENCIES) .sort() .map((key) => (_jsx("option", { "data-key": key, children: key }, key))), []); const HelpOrErrorIcon = useMemo(() => { if (!HintText) return null; if (ErrorText) return (_jsx(Icon, { width: 16, height: 16, Path: AlertCircle, PathProps: { stroke: 'error', } })); return (_jsx(Icon, { width: 16, height: 16, Path: HelpCircle, PathProps: { stroke: 'gray-400', } })); }, [HintText, ErrorText]); const InputAdornmentLeft = useMemo(() => _jsx(TextMd, { weight: 'regular', children: currentCurrency.symbol }), [currentCurrency.symbol]); const InputAdornmentRight = useMemo(() => (_jsxs("div", { ref: rightAdornmentRef, style: { display: 'flex', alignItems: 'center', gap: '12px' }, children: [_jsx("select", { value: currentCurrency.iso, className: 'adornment-select', onChange: (e) => { setCurrentCurrency(CURRENCIES[e.target.value]); if (onCurrencyChange) onCurrencyChange(CURRENCIES[e.target.value]); }, style: { width: `${rightAdornmentWidth}px`, }, children: CurrencyOptions }), HelpOrErrorIcon, _jsx(TextMd, { weight: 'regular', children: currentCurrency.iso }), _jsx(Icon, { width: 20, height: 20, Path: ChevronDown, PathProps: { stroke: 'gray-400', } })] })), [ currentCurrency, CurrencyOptions, HelpOrErrorIcon, onCurrencyChange, rightAdornmentWidth, ]); useLayoutEffect(() => { if (InputAdornmentRight && rightAdornmentRef.current) setRightAdornmentWidth(rightAdornmentRef.current.getBoundingClientRect().width + 3 * BASE_INPUT_PADDING_HORIZONTAL // The padding around the adornment, plus the flex gap ); }, [InputAdornmentRight]); /** * In the example of the USD currency, the numeric separator is a comma, and the decimal separator is a period. This function will take 99999999 and convert it to 999,999.99. * In the example of the EUR currency, the numeric separator is a period, and the decimal separator is a comma. This function will take 99999999 and convert it to 999.999,99. */ const maskToCurrency = useCallback(({ nextState }) => { const { value } = nextState || {}; let amountFormatted = value?.replace?.(/\D/g, ''); amountFormatted = amountFormatted?.replace?.(/^0+/g, ''); if (amountFormatted?.length === 2) { return { ...nextState, value: `${amountFormatted}`, selection: { start: amountFormatted.length + 3, end: amountFormatted.length + 3, }, }; } const amountFormattedWithDecimal = amountFormatted?.replace?.(/(?=\d{2})(\d{2})$/, `${currentCurrency.decimalSeparator}$1`); // The numeric separator is the opposite of the decimal separator const numericSeparator = currentCurrency.decimalSeparator === '.' ? ',' : '.'; const amountFormattedWithNumericSeparator = amountFormattedWithDecimal?.replace?.(/(\d)(?=(\d{3})+(?!\d))/g, `$1${numericSeparator}`); if (amountFormattedWithNumericSeparator) { return { ...nextState, value: `${amountFormattedWithNumericSeparator}`, selection: { start: amountFormattedWithNumericSeparator.length + 3, end: amountFormattedWithNumericSeparator.length + 3, }, }; } return nextState; }, [currentCurrency]); return (_jsx(TextInput, { id: id, ref: ref, HintText: HintText, InputAdornmentLeft: InputAdornmentLeft, InputAdornmentRight: InputAdornmentRight, maskProps: { maskPlaceholder: '', alwaysShowMask: false, mask: '9999999999999999999999999999999', beforeMaskedStateChange: maskToCurrency, }, ContainerProps: { className: 'dry-currencyInput' }, placeholder: `1${currentCurrency.decimalSeparator === '.' ? ',' : '.'}000`, ...props })); }); export default CurrencyInput; //# sourceMappingURL=CurrencyInput.js.map