@kadconsulting/dry
Version:
KAD Reusable Component Library
91 lines • 5.21 kB
JavaScript
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