@transferwise/components 0.0.0-experimental-8cc553f → 0.0.0-experimental-4660613

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -50,16 +50,24 @@ const isNumberOrNull = v => neptuneValidation.isNumber(v) || neptuneValidation.i
50
50
  const formatAmountIfSet = ({
51
51
  amount,
52
52
  currency,
53
- locale
53
+ locale,
54
+ decimals
54
55
  }) => {
55
- return typeof amount === 'number' ? formatting.formatAmount(amount, currency, locale) : '';
56
+ if (typeof amount !== 'number') {
57
+ return '';
58
+ }
59
+ if (decimals != null && currencyFormatting.getCurrencyDecimals(currency) !== 0) {
60
+ return formatting.formatNumber(amount, locale, decimals);
61
+ }
62
+ return formatting.formatAmount(amount, currency, locale);
56
63
  };
57
64
  const parseNumber = ({
58
65
  amount,
59
66
  currency,
60
- locale
67
+ locale,
68
+ decimals
61
69
  }) => {
62
- return currencyFormatting.parseAmount(amount, currency, locale);
70
+ return currencyFormatting.parseAmount(amount, currency, locale, decimals);
63
71
  };
64
72
  const allowedInputKeys = new Set(['Backspace', 'Delete', ',', '.', 'ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Enter', 'Escape', 'Tab']);
65
73
  class MoneyInput extends React.Component {
@@ -76,7 +84,8 @@ class MoneyInput extends React.Component {
76
84
  formattedAmount: formatAmountIfSet({
77
85
  amount: props.amount,
78
86
  currency: props.selectedCurrency.currency,
79
- locale: props.intl.locale
87
+ locale: props.intl.locale,
88
+ decimals: props.decimals
80
89
  }),
81
90
  locale: props.intl.locale
82
91
  };
@@ -90,7 +99,8 @@ class MoneyInput extends React.Component {
90
99
  formattedAmount: formatAmountIfSet({
91
100
  amount: nextProps.amount,
92
101
  currency: nextProps.selectedCurrency.currency,
93
- locale: nextProps.intl.locale
102
+ locale: nextProps.intl.locale,
103
+ decimals: nextProps.decimals
94
104
  })
95
105
  });
96
106
  }
@@ -117,14 +127,16 @@ class MoneyInput extends React.Component {
117
127
  const parsed = neptuneValidation.isEmpty(paste) ? null : parseNumber({
118
128
  amount: paste,
119
129
  currency: this.props.selectedCurrency.currency,
120
- locale
130
+ locale,
131
+ decimals: this.props.decimals
121
132
  });
122
133
  if (isNumberOrNull(parsed)) {
123
134
  this.setState({
124
135
  formattedAmount: formatAmountIfSet({
125
136
  amount: parsed,
126
137
  currency: this.props.selectedCurrency.currency,
127
- locale
138
+ locale,
139
+ decimals: this.props.decimals
128
140
  })
129
141
  });
130
142
  this.props.onAmountChange?.(parsed);
@@ -141,7 +153,8 @@ class MoneyInput extends React.Component {
141
153
  const parsed = neptuneValidation.isEmpty(value) ? null : parseNumber({
142
154
  amount: value,
143
155
  currency: this.props.selectedCurrency.currency,
144
- locale: this.state.locale
156
+ locale: this.state.locale,
157
+ decimals: this.props.decimals
145
158
  });
146
159
  if (isNumberOrNull(parsed)) {
147
160
  this.props.onAmountChange?.(parsed);
@@ -181,7 +194,8 @@ class MoneyInput extends React.Component {
181
194
  const parsed = parseNumber({
182
195
  amount: previousState.formattedAmount,
183
196
  currency: this.props.selectedCurrency.currency,
184
- locale: previousState.locale
197
+ locale: previousState.locale,
198
+ decimals: this.props.decimals
185
199
  });
186
200
  if (!isNumberOrNull(parsed)) {
187
201
  return {
@@ -192,7 +206,8 @@ class MoneyInput extends React.Component {
192
206
  formattedAmount: formatAmountIfSet({
193
207
  amount: parsed,
194
208
  currency: this.props.selectedCurrency.currency,
195
- locale: previousState.locale
209
+ locale: previousState.locale,
210
+ decimals: this.props.decimals
196
211
  })
197
212
  };
198
213
  });
@@ -257,7 +272,8 @@ class MoneyInput extends React.Component {
257
272
  placeholder: formatAmountIfSet({
258
273
  amount: this.props.placeholder,
259
274
  currency: this.props.selectedCurrency.currency,
260
- locale: this.state.locale
275
+ locale: this.state.locale,
276
+ decimals: this.props.decimals
261
277
  }),
262
278
  autoComplete: "off",
263
279
  "aria-describedby": selectedCurrencyElementId,
@@ -1 +1 @@
1
- {"version":3,"file":"MoneyInput.js","sources":["../../src/moneyInput/MoneyInput.tsx"],"sourcesContent":["import { isEmpty, isNumber, isNull } from '@transferwise/neptune-validation';\nimport { Flag } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { Component } from 'react';\nimport { injectIntl, WrappedComponentProps } from 'react-intl';\n\nimport {\n Typography,\n Size,\n SizeLarge,\n SizeMedium,\n SizeSmall,\n getLocaleCurrencyName,\n} from '../common';\nimport { withInputAttributes, WithInputAttributesProps } from '../inputs/contexts';\nimport { Input } from '../inputs/Input';\nimport {\n SelectInput,\n SelectInputItem,\n SelectInputOptionContent,\n SelectInputOptionItem,\n SelectInputProps,\n} from '../inputs/SelectInput';\nimport Title from '../title';\n\nimport messages from './MoneyInput.messages';\nimport { formatAmount, parseAmount } from './currencyFormatting';\nimport withId from '../withId';\n\nexport interface CurrencyOptionItem {\n header?: never;\n value: string;\n label: string;\n currency: string;\n note?: string;\n searchable?: string;\n}\n\nexport interface CurrencyHeaderItem {\n header: string;\n}\n\nexport type CurrencyItem = CurrencyOptionItem | CurrencyHeaderItem;\n\nconst isNumberOrNull = (v: unknown): v is number | null => isNumber(v) || isNull(v);\n\nconst formatAmountIfSet = ({\n amount,\n currency,\n locale,\n}: {\n amount: number | null | undefined;\n currency: string;\n locale: string;\n}) => {\n return typeof amount === 'number' ? formatAmount(amount, currency, locale) : '';\n};\n\nconst parseNumber = ({\n amount,\n currency,\n locale,\n}: {\n amount: string;\n currency: string;\n locale: string;\n}) => {\n return parseAmount(amount, currency, locale);\n};\n\nconst allowedInputKeys = new Set([\n 'Backspace',\n 'Delete',\n ',',\n '.',\n 'ArrowDown',\n 'ArrowUp',\n 'ArrowLeft',\n 'ArrowRight',\n 'Enter',\n 'Escape',\n 'Tab',\n]);\n\nexport interface MoneyInputProps extends WrappedComponentProps {\n id?: string;\n 'aria-labelledby'?: string;\n currencies: readonly CurrencyItem[];\n selectedCurrency: CurrencyOptionItem;\n onCurrencyChange?: (value: CurrencyOptionItem) => void;\n placeholder?: number;\n amount: number | null;\n size?: SizeSmall | SizeMedium | SizeLarge;\n onAmountChange?: (value: number | null) => void;\n addon?: React.ReactNode;\n searchPlaceholder?: string;\n /**\n * Allows the consumer to react to searching, while the search itself is handled internally.\n */\n onSearchChange?: (value: { searchQuery: string; filteredOptions: CurrencyItem[] }) => void;\n customActionLabel?: React.ReactNode;\n onCustomAction?: () => void;\n classNames?: Record<string, string>;\n selectProps?: Partial<SelectInputProps<CurrencyOptionItem>>;\n}\n\nexport type MoneyInputPropsWithInputAttributes = MoneyInputProps &\n Partial<WithInputAttributesProps>;\n\ninterface MoneyInputState {\n searchQuery: string;\n formattedAmount: string;\n locale: string;\n}\n\nclass MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInputState> {\n declare props: MoneyInputPropsWithInputAttributes &\n Required<Pick<MoneyInputPropsWithInputAttributes, keyof typeof MoneyInput.defaultProps>>;\n\n static defaultProps = {\n size: Size.LARGE,\n classNames: {},\n selectProps: {},\n } satisfies Partial<MoneyInputPropsWithInputAttributes>;\n\n amountFocused = false;\n\n constructor(props: MoneyInputProps) {\n super(props);\n this.state = {\n searchQuery: '',\n formattedAmount: formatAmountIfSet({\n amount: props.amount,\n currency: props.selectedCurrency.currency,\n locale: props.intl.locale,\n }),\n locale: props.intl.locale,\n };\n }\n\n UNSAFE_componentWillReceiveProps(nextProps: MoneyInputProps) {\n this.setState({ locale: nextProps.intl.locale });\n\n if (!this.amountFocused) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: nextProps.amount,\n currency: nextProps.selectedCurrency.currency,\n locale: nextProps.intl.locale,\n }),\n });\n }\n }\n\n isInputAllowedForKeyEvent = (event: React.KeyboardEvent<HTMLInputElement>) => {\n const { metaKey, key, ctrlKey } = event;\n const isNumberKey = isNumber(Number.parseInt(key, 10));\n\n return isNumberKey || metaKey || ctrlKey || allowedInputKeys.has(key);\n };\n\n handleKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (!this.isInputAllowedForKeyEvent(event)) {\n event.preventDefault();\n }\n };\n\n handlePaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {\n const paste = event.clipboardData.getData('text');\n const { locale } = this.state;\n const parsed = isEmpty(paste)\n ? null\n : parseNumber({\n amount: paste,\n currency: this.props.selectedCurrency.currency,\n locale,\n });\n\n if (isNumberOrNull(parsed)) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale,\n }),\n });\n this.props.onAmountChange?.(parsed);\n }\n\n event.preventDefault();\n };\n\n onAmountChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {\n const { value } = event.target;\n this.setState({\n formattedAmount: value,\n });\n const parsed = isEmpty(value)\n ? null\n : parseNumber({\n amount: value,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n });\n if (isNumberOrNull(parsed)) {\n this.props.onAmountChange?.(parsed);\n }\n };\n\n onAmountBlur = () => {\n this.amountFocused = false;\n this.setAmount();\n };\n\n onAmountFocus = () => {\n this.amountFocused = true;\n };\n\n getSelectOptions() {\n const selectOptions = filterCurrenciesForQuery(this.props.currencies, this.state.searchQuery);\n\n const formattedOptions: SelectInputItem<CurrencyOptionItem>[] = [];\n let currentGroupOptions: SelectInputOptionItem<CurrencyOptionItem>[] | undefined;\n\n selectOptions.forEach((item) => {\n if (item.header != null) {\n currentGroupOptions = [];\n formattedOptions.push({\n type: 'group',\n label: item.header,\n options: currentGroupOptions,\n });\n } else {\n (currentGroupOptions ?? formattedOptions).push({\n type: 'option',\n value: item,\n filterMatchers: [item.value, item.label, item.note ?? '', item.searchable ?? ''],\n });\n }\n });\n\n return formattedOptions;\n }\n\n setAmount() {\n this.setState((previousState) => {\n const parsed = parseNumber({\n amount: previousState.formattedAmount,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n });\n if (!isNumberOrNull(parsed)) {\n return {\n formattedAmount: previousState.formattedAmount,\n };\n }\n return {\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n }),\n };\n });\n }\n\n handleSelectChange = (value: CurrencyOptionItem) => {\n this.handleSearchChange('');\n this.props.onCurrencyChange?.(value);\n };\n\n handleSearchChange = (searchQuery: string) => {\n this.setState({ searchQuery });\n this.props.onSearchChange?.({\n searchQuery,\n filteredOptions: filterCurrenciesForQuery(this.props.currencies, searchQuery),\n });\n };\n\n style = (className: string) => this.props.classNames[className] || className;\n\n render() {\n const {\n inputAttributes,\n id: amountInputId,\n 'aria-labelledby': ariaLabelledByProp,\n selectedCurrency,\n onCurrencyChange,\n size,\n addon,\n selectProps,\n } = this.props;\n const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes?.['aria-labelledby'];\n const selectOptions = this.getSelectOptions();\n\n const hasSingleCurrency = () => {\n if (selectOptions.length !== 0) {\n const firstItem = selectOptions[0];\n\n if (selectOptions.length === 1) {\n if (firstItem.type === 'option') {\n return firstItem.value.currency === selectedCurrency.currency;\n }\n if (firstItem.type === 'group') {\n return (\n firstItem.options.length === 1 &&\n !(this.props.onCustomAction && this.props.customActionLabel)\n );\n }\n }\n } else if (selectedCurrency?.currency) {\n return true;\n }\n\n return false;\n };\n\n const isFixedCurrency = (!this.state.searchQuery && hasSingleCurrency()) || !onCurrencyChange;\n const disabled = !this.props.onAmountChange;\n const selectedCurrencyElementId = `${inputAttributes?.id ?? amountInputId}SelectedCurrency`;\n\n return (\n <fieldset\n aria-invalid={inputAttributes?.['aria-invalid']}\n aria-describedby={inputAttributes?.['aria-describedby']}\n aria-labelledby={inputAttributes?.id ?? amountInputId}\n className={clsx(\n this.style('tw-money-input'),\n this.style('input-group'),\n this.style(`input-group-${size}`),\n )}\n >\n <Input\n id={inputAttributes?.id ?? amountInputId}\n aria-labelledby={ariaLabelledBy}\n value={this.state.formattedAmount}\n inputMode=\"decimal\"\n disabled={disabled}\n placeholder={formatAmountIfSet({\n amount: this.props.placeholder,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n })}\n autoComplete=\"off\"\n aria-describedby={selectedCurrencyElementId}\n onKeyDown={this.handleKeyDown}\n onChange={this.onAmountChange}\n onFocus={this.onAmountFocus}\n onBlur={this.onAmountBlur}\n onPaste={this.handlePaste}\n />\n {addon && (\n <span\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n disabled ? this.style('disabled') : '',\n )}\n >\n {addon}\n </span>\n )}\n {isFixedCurrency ? (\n <div\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n this.style('tw-money-input__fixed-currency'),\n disabled ? this.style('disabled') : '',\n )}\n id={selectedCurrencyElementId}\n >\n {(size === 'lg' || size === 'md') && (\n <span className={clsx(this.style('money-input-currency-flag'), this.style('m-r-2'))}>\n <Flag code={selectedCurrency.currency.toLowerCase()} intrinsicSize={24} />\n </span>\n )}\n <Title\n as=\"span\"\n type={Typography.TITLE_SUBSECTION}\n className={size === 'lg' ? this.style('m-r-1') : ''}\n aria-label={getLocaleCurrencyName(this.props.intl, selectedCurrency.currency)}\n >\n {selectedCurrency.currency.toUpperCase()}\n </Title>\n </div>\n ) : (\n <div\n translate=\"no\"\n className={clsx(\n this.style('input-group-btn'),\n this.style('amount-currency-select-btn'),\n )}\n >\n <SelectInput\n UNSAFE_triggerButtonProps={{\n id: undefined,\n 'aria-labelledby': undefined,\n 'aria-describedby': ariaLabelledBy,\n 'aria-invalid': undefined,\n 'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel),\n }}\n id={selectedCurrencyElementId}\n items={selectOptions}\n value={selectedCurrency}\n compareValues=\"currency\"\n renderValue={(currency, withinTrigger) => {\n return (\n <SelectInputOptionContent\n title={\n withinTrigger ? (\n <span\n aria-label={getLocaleCurrencyName(this.props.intl, currency.currency)}\n >\n {currency.currency.toUpperCase()}\n </span>\n ) : (\n currency.label\n )\n }\n note={withinTrigger ? undefined : currency.note}\n icon={<Flag code={currency.currency} intrinsicSize={24} />}\n />\n );\n }}\n renderFooter={\n this.props.onCustomAction\n ? () => (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events\n <div role=\"button\" tabIndex={0} onClick={this.props.onCustomAction}>\n {this.props.customActionLabel}\n </div>\n )\n : undefined\n }\n placeholder={this.props.intl.formatMessage(messages.selectPlaceholder)}\n filterable\n filterPlaceholder={\n this.props.searchPlaceholder ||\n this.props.intl.formatMessage(messages.searchPlaceholder)\n }\n disabled={disabled}\n size={size}\n onChange={this.handleSelectChange}\n onFilterChange={({ queryNormalized }) => {\n this.handleSearchChange(queryNormalized ?? '');\n }}\n {...selectProps}\n />\n </div>\n )}\n </fieldset>\n );\n }\n}\n\nfunction filterCurrenciesForQuery(\n currencies: readonly CurrencyItem[],\n query: string,\n): CurrencyItem[] {\n if (!query) {\n return [...currencies];\n }\n\n const options = currencies.filter(\n (option): option is CurrencyOptionItem => option.header == null,\n );\n const filteredOptions = removeDuplicateValueOptions(options).filter((option) =>\n currencyOptionFitsQuery(option, query),\n );\n\n return sortOptionsLabelsToFirst(filteredOptions, query);\n}\n\nfunction removeDuplicateValueOptions(options: readonly CurrencyOptionItem[]) {\n const uniqueValues = new Set<string>();\n return options.filter((option) => {\n if (!uniqueValues.has(option.value)) {\n uniqueValues.add(option.value);\n return true;\n }\n return false;\n });\n}\n\nfunction currencyOptionFitsQuery(option: CurrencyOptionItem, query: string) {\n if (!option.value) {\n return false;\n }\n\n return (\n contains(option.label, query) ||\n contains(option.searchable, query) ||\n contains(option.note, query)\n );\n}\n\nfunction contains(property: string | undefined, query: string) {\n return property?.toLowerCase().includes(query.toLowerCase());\n}\n\nfunction sortOptionsLabelsToFirst(options: readonly CurrencyOptionItem[], query: string) {\n return [...options].sort((first, second) => {\n const firstContains = contains(first.label, query);\n const secondContains = contains(second.label, query);\n\n if (firstContains && secondContains) {\n return 0;\n }\n if (firstContains) {\n return -1;\n }\n if (secondContains) {\n return 1;\n }\n return 0;\n });\n}\n\nexport default injectIntl(withId(withInputAttributes(MoneyInput, { nonLabelable: true })));\n"],"names":["isNumberOrNull","v","isNumber","isNull","formatAmountIfSet","amount","currency","locale","formatAmount","parseNumber","parseAmount","allowedInputKeys","Set","MoneyInput","Component","defaultProps","size","Size","LARGE","classNames","selectProps","amountFocused","constructor","props","state","searchQuery","formattedAmount","selectedCurrency","intl","UNSAFE_componentWillReceiveProps","nextProps","setState","isInputAllowedForKeyEvent","event","metaKey","key","ctrlKey","isNumberKey","Number","parseInt","has","handleKeyDown","preventDefault","handlePaste","paste","clipboardData","getData","parsed","isEmpty","onAmountChange","value","target","onAmountBlur","setAmount","onAmountFocus","getSelectOptions","selectOptions","filterCurrenciesForQuery","currencies","formattedOptions","currentGroupOptions","forEach","item","header","push","type","label","options","filterMatchers","note","searchable","previousState","handleSelectChange","handleSearchChange","onCurrencyChange","onSearchChange","filteredOptions","style","className","render","inputAttributes","id","amountInputId","ariaLabelledByProp","addon","ariaLabelledBy","hasSingleCurrency","length","firstItem","onCustomAction","customActionLabel","isFixedCurrency","disabled","selectedCurrencyElementId","_jsxs","clsx","children","_jsx","Input","inputMode","placeholder","autoComplete","onKeyDown","onChange","onFocus","onBlur","onPaste","Flag","code","toLowerCase","intrinsicSize","Title","as","Typography","TITLE_SUBSECTION","getLocaleCurrencyName","toUpperCase","translate","SelectInput","UNSAFE_triggerButtonProps","undefined","formatMessage","messages","selectCurrencyLabel","items","compareValues","renderValue","withinTrigger","SelectInputOptionContent","title","icon","renderFooter","role","tabIndex","onClick","selectPlaceholder","filterable","filterPlaceholder","searchPlaceholder","onFilterChange","queryNormalized","query","filter","option","removeDuplicateValueOptions","currencyOptionFitsQuery","sortOptionsLabelsToFirst","uniqueValues","add","contains","property","includes","sort","first","second","firstContains","secondContains","injectIntl","withId","withInputAttributes","nonLabelable"],"mappings":"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"}
1
+ {"version":3,"file":"MoneyInput.js","sources":["../../src/moneyInput/MoneyInput.tsx"],"sourcesContent":["import { isEmpty, isNumber, isNull } from '@transferwise/neptune-validation';\nimport { Flag } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { Component } from 'react';\nimport { injectIntl, WrappedComponentProps } from 'react-intl';\n\nimport {\n Typography,\n Size,\n SizeLarge,\n SizeMedium,\n SizeSmall,\n getLocaleCurrencyName,\n} from '../common';\nimport { withInputAttributes, WithInputAttributesProps } from '../inputs/contexts';\nimport { Input } from '../inputs/Input';\nimport {\n SelectInput,\n SelectInputItem,\n SelectInputOptionContent,\n SelectInputOptionItem,\n SelectInputProps,\n} from '../inputs/SelectInput';\nimport Title from '../title';\n\nimport messages from './MoneyInput.messages';\nimport { formatAmount, formatNumber, getCurrencyDecimals, parseAmount } from './currencyFormatting';\nimport withId from '../withId';\n\nexport interface CurrencyOptionItem {\n header?: never;\n value: string;\n label: string;\n currency: string;\n note?: string;\n searchable?: string;\n}\n\nexport interface CurrencyHeaderItem {\n header: string;\n}\n\nexport type CurrencyItem = CurrencyOptionItem | CurrencyHeaderItem;\n\nconst isNumberOrNull = (v: unknown): v is number | null => isNumber(v) || isNull(v);\n\nconst formatAmountIfSet = ({\n amount,\n currency,\n locale,\n decimals,\n}: {\n amount: number | null | undefined;\n currency: string;\n locale: string;\n decimals?: number;\n}) => {\n if (typeof amount !== 'number') {\n return '';\n }\n if (decimals != null && getCurrencyDecimals(currency) !== 0) {\n return formatNumber(amount, locale, decimals);\n }\n return formatAmount(amount, currency, locale);\n};\n\nconst parseNumber = ({\n amount,\n currency,\n locale,\n decimals,\n}: {\n amount: string;\n currency: string;\n locale: string;\n decimals?: number;\n}) => {\n return parseAmount(amount, currency, locale, decimals);\n};\n\nconst allowedInputKeys = new Set([\n 'Backspace',\n 'Delete',\n ',',\n '.',\n 'ArrowDown',\n 'ArrowUp',\n 'ArrowLeft',\n 'ArrowRight',\n 'Enter',\n 'Escape',\n 'Tab',\n]);\n\nexport interface MoneyInputProps extends WrappedComponentProps {\n id?: string;\n 'aria-labelledby'?: string;\n currencies: readonly CurrencyItem[];\n selectedCurrency: CurrencyOptionItem;\n onCurrencyChange?: (value: CurrencyOptionItem) => void;\n placeholder?: number;\n amount: number | null;\n size?: SizeSmall | SizeMedium | SizeLarge;\n onAmountChange?: (value: number | null) => void;\n addon?: React.ReactNode;\n searchPlaceholder?: string;\n /**\n * Allows the consumer to react to searching, while the search itself is handled internally.\n */\n onSearchChange?: (value: { searchQuery: string; filteredOptions: CurrencyItem[] }) => void;\n customActionLabel?: React.ReactNode;\n onCustomAction?: () => void;\n classNames?: Record<string, string>;\n selectProps?: Partial<SelectInputProps<CurrencyOptionItem>>;\n /**\n * Specify the number of decimal places to format the amount. When not specified, the number of\n * decimals is determined by the selected currency (e.g. 2 for EUR, 0 for JPY, 3 for BHD).\n * This override is ignored for zero-decimal currencies (e.g. JPY, KRW, HUF), which always use 0.\n */\n decimals?: number;\n}\n\nexport type MoneyInputPropsWithInputAttributes = MoneyInputProps &\n Partial<WithInputAttributesProps>;\n\ninterface MoneyInputState {\n searchQuery: string;\n formattedAmount: string;\n locale: string;\n}\n\nclass MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInputState> {\n declare props: MoneyInputPropsWithInputAttributes &\n Required<Pick<MoneyInputPropsWithInputAttributes, keyof typeof MoneyInput.defaultProps>>;\n\n static defaultProps = {\n size: Size.LARGE,\n classNames: {},\n selectProps: {},\n } satisfies Partial<MoneyInputPropsWithInputAttributes>;\n\n amountFocused = false;\n\n constructor(props: MoneyInputProps) {\n super(props);\n this.state = {\n searchQuery: '',\n formattedAmount: formatAmountIfSet({\n amount: props.amount,\n currency: props.selectedCurrency.currency,\n locale: props.intl.locale,\n decimals: props.decimals,\n }),\n locale: props.intl.locale,\n };\n }\n\n UNSAFE_componentWillReceiveProps(nextProps: MoneyInputProps) {\n this.setState({ locale: nextProps.intl.locale });\n\n if (!this.amountFocused) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: nextProps.amount,\n currency: nextProps.selectedCurrency.currency,\n locale: nextProps.intl.locale,\n decimals: nextProps.decimals,\n }),\n });\n }\n }\n\n isInputAllowedForKeyEvent = (event: React.KeyboardEvent<HTMLInputElement>) => {\n const { metaKey, key, ctrlKey } = event;\n const isNumberKey = isNumber(Number.parseInt(key, 10));\n\n return isNumberKey || metaKey || ctrlKey || allowedInputKeys.has(key);\n };\n\n handleKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (!this.isInputAllowedForKeyEvent(event)) {\n event.preventDefault();\n }\n };\n\n handlePaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {\n const paste = event.clipboardData.getData('text');\n const { locale } = this.state;\n const parsed = isEmpty(paste)\n ? null\n : parseNumber({\n amount: paste,\n currency: this.props.selectedCurrency.currency,\n locale,\n decimals: this.props.decimals,\n });\n\n if (isNumberOrNull(parsed)) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale,\n decimals: this.props.decimals,\n }),\n });\n this.props.onAmountChange?.(parsed);\n }\n\n event.preventDefault();\n };\n\n onAmountChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {\n const { value } = event.target;\n this.setState({\n formattedAmount: value,\n });\n const parsed = isEmpty(value)\n ? null\n : parseNumber({\n amount: value,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n decimals: this.props.decimals,\n });\n if (isNumberOrNull(parsed)) {\n this.props.onAmountChange?.(parsed);\n }\n };\n\n onAmountBlur = () => {\n this.amountFocused = false;\n this.setAmount();\n };\n\n onAmountFocus = () => {\n this.amountFocused = true;\n };\n\n getSelectOptions() {\n const selectOptions = filterCurrenciesForQuery(this.props.currencies, this.state.searchQuery);\n\n const formattedOptions: SelectInputItem<CurrencyOptionItem>[] = [];\n let currentGroupOptions: SelectInputOptionItem<CurrencyOptionItem>[] | undefined;\n\n selectOptions.forEach((item) => {\n if (item.header != null) {\n currentGroupOptions = [];\n formattedOptions.push({\n type: 'group',\n label: item.header,\n options: currentGroupOptions,\n });\n } else {\n (currentGroupOptions ?? formattedOptions).push({\n type: 'option',\n value: item,\n filterMatchers: [item.value, item.label, item.note ?? '', item.searchable ?? ''],\n });\n }\n });\n\n return formattedOptions;\n }\n\n setAmount() {\n this.setState((previousState) => {\n const parsed = parseNumber({\n amount: previousState.formattedAmount,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n decimals: this.props.decimals,\n });\n if (!isNumberOrNull(parsed)) {\n return {\n formattedAmount: previousState.formattedAmount,\n };\n }\n return {\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n decimals: this.props.decimals,\n }),\n };\n });\n }\n\n handleSelectChange = (value: CurrencyOptionItem) => {\n this.handleSearchChange('');\n this.props.onCurrencyChange?.(value);\n };\n\n handleSearchChange = (searchQuery: string) => {\n this.setState({ searchQuery });\n this.props.onSearchChange?.({\n searchQuery,\n filteredOptions: filterCurrenciesForQuery(this.props.currencies, searchQuery),\n });\n };\n\n style = (className: string) => this.props.classNames[className] || className;\n\n render() {\n const {\n inputAttributes,\n id: amountInputId,\n 'aria-labelledby': ariaLabelledByProp,\n selectedCurrency,\n onCurrencyChange,\n size,\n addon,\n selectProps,\n } = this.props;\n const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes?.['aria-labelledby'];\n const selectOptions = this.getSelectOptions();\n\n const hasSingleCurrency = () => {\n if (selectOptions.length !== 0) {\n const firstItem = selectOptions[0];\n\n if (selectOptions.length === 1) {\n if (firstItem.type === 'option') {\n return firstItem.value.currency === selectedCurrency.currency;\n }\n if (firstItem.type === 'group') {\n return (\n firstItem.options.length === 1 &&\n !(this.props.onCustomAction && this.props.customActionLabel)\n );\n }\n }\n } else if (selectedCurrency?.currency) {\n return true;\n }\n\n return false;\n };\n\n const isFixedCurrency = (!this.state.searchQuery && hasSingleCurrency()) || !onCurrencyChange;\n const disabled = !this.props.onAmountChange;\n const selectedCurrencyElementId = `${inputAttributes?.id ?? amountInputId}SelectedCurrency`;\n\n return (\n <fieldset\n aria-invalid={inputAttributes?.['aria-invalid']}\n aria-describedby={inputAttributes?.['aria-describedby']}\n aria-labelledby={inputAttributes?.id ?? amountInputId}\n className={clsx(\n this.style('tw-money-input'),\n this.style('input-group'),\n this.style(`input-group-${size}`),\n )}\n >\n <Input\n id={inputAttributes?.id ?? amountInputId}\n aria-labelledby={ariaLabelledBy}\n value={this.state.formattedAmount}\n inputMode=\"decimal\"\n disabled={disabled}\n placeholder={formatAmountIfSet({\n amount: this.props.placeholder,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n decimals: this.props.decimals,\n })}\n autoComplete=\"off\"\n aria-describedby={selectedCurrencyElementId}\n onKeyDown={this.handleKeyDown}\n onChange={this.onAmountChange}\n onFocus={this.onAmountFocus}\n onBlur={this.onAmountBlur}\n onPaste={this.handlePaste}\n />\n {addon && (\n <span\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n disabled ? this.style('disabled') : '',\n )}\n >\n {addon}\n </span>\n )}\n {isFixedCurrency ? (\n <div\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n this.style('tw-money-input__fixed-currency'),\n disabled ? this.style('disabled') : '',\n )}\n id={selectedCurrencyElementId}\n >\n {(size === 'lg' || size === 'md') && (\n <span className={clsx(this.style('money-input-currency-flag'), this.style('m-r-2'))}>\n <Flag code={selectedCurrency.currency.toLowerCase()} intrinsicSize={24} />\n </span>\n )}\n <Title\n as=\"span\"\n type={Typography.TITLE_SUBSECTION}\n className={size === 'lg' ? this.style('m-r-1') : ''}\n aria-label={getLocaleCurrencyName(this.props.intl, selectedCurrency.currency)}\n >\n {selectedCurrency.currency.toUpperCase()}\n </Title>\n </div>\n ) : (\n <div\n translate=\"no\"\n className={clsx(\n this.style('input-group-btn'),\n this.style('amount-currency-select-btn'),\n )}\n >\n <SelectInput\n UNSAFE_triggerButtonProps={{\n id: undefined,\n 'aria-labelledby': undefined,\n 'aria-describedby': ariaLabelledBy,\n 'aria-invalid': undefined,\n 'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel),\n }}\n id={selectedCurrencyElementId}\n items={selectOptions}\n value={selectedCurrency}\n compareValues=\"currency\"\n renderValue={(currency, withinTrigger) => {\n return (\n <SelectInputOptionContent\n title={\n withinTrigger ? (\n <span\n aria-label={getLocaleCurrencyName(this.props.intl, currency.currency)}\n >\n {currency.currency.toUpperCase()}\n </span>\n ) : (\n currency.label\n )\n }\n note={withinTrigger ? undefined : currency.note}\n icon={<Flag code={currency.currency} intrinsicSize={24} />}\n />\n );\n }}\n renderFooter={\n this.props.onCustomAction\n ? () => (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events\n <div role=\"button\" tabIndex={0} onClick={this.props.onCustomAction}>\n {this.props.customActionLabel}\n </div>\n )\n : undefined\n }\n placeholder={this.props.intl.formatMessage(messages.selectPlaceholder)}\n filterable\n filterPlaceholder={\n this.props.searchPlaceholder ||\n this.props.intl.formatMessage(messages.searchPlaceholder)\n }\n disabled={disabled}\n size={size}\n onChange={this.handleSelectChange}\n onFilterChange={({ queryNormalized }) => {\n this.handleSearchChange(queryNormalized ?? '');\n }}\n {...selectProps}\n />\n </div>\n )}\n </fieldset>\n );\n }\n}\n\nfunction filterCurrenciesForQuery(\n currencies: readonly CurrencyItem[],\n query: string,\n): CurrencyItem[] {\n if (!query) {\n return [...currencies];\n }\n\n const options = currencies.filter(\n (option): option is CurrencyOptionItem => option.header == null,\n );\n const filteredOptions = removeDuplicateValueOptions(options).filter((option) =>\n currencyOptionFitsQuery(option, query),\n );\n\n return sortOptionsLabelsToFirst(filteredOptions, query);\n}\n\nfunction removeDuplicateValueOptions(options: readonly CurrencyOptionItem[]) {\n const uniqueValues = new Set<string>();\n return options.filter((option) => {\n if (!uniqueValues.has(option.value)) {\n uniqueValues.add(option.value);\n return true;\n }\n return false;\n });\n}\n\nfunction currencyOptionFitsQuery(option: CurrencyOptionItem, query: string) {\n if (!option.value) {\n return false;\n }\n\n return (\n contains(option.label, query) ||\n contains(option.searchable, query) ||\n contains(option.note, query)\n );\n}\n\nfunction contains(property: string | undefined, query: string) {\n return property?.toLowerCase().includes(query.toLowerCase());\n}\n\nfunction sortOptionsLabelsToFirst(options: readonly CurrencyOptionItem[], query: string) {\n return [...options].sort((first, second) => {\n const firstContains = contains(first.label, query);\n const secondContains = contains(second.label, query);\n\n if (firstContains && secondContains) {\n return 0;\n }\n if (firstContains) {\n return -1;\n }\n if (secondContains) {\n return 1;\n }\n return 0;\n });\n}\n\nexport default injectIntl(withId(withInputAttributes(MoneyInput, { nonLabelable: true })));\n"],"names":["isNumberOrNull","v","isNumber","isNull","formatAmountIfSet","amount","currency","locale","decimals","getCurrencyDecimals","formatNumber","formatAmount","parseNumber","parseAmount","allowedInputKeys","Set","MoneyInput","Component","defaultProps","size","Size","LARGE","classNames","selectProps","amountFocused","constructor","props","state","searchQuery","formattedAmount","selectedCurrency","intl","UNSAFE_componentWillReceiveProps","nextProps","setState","isInputAllowedForKeyEvent","event","metaKey","key","ctrlKey","isNumberKey","Number","parseInt","has","handleKeyDown","preventDefault","handlePaste","paste","clipboardData","getData","parsed","isEmpty","onAmountChange","value","target","onAmountBlur","setAmount","onAmountFocus","getSelectOptions","selectOptions","filterCurrenciesForQuery","currencies","formattedOptions","currentGroupOptions","forEach","item","header","push","type","label","options","filterMatchers","note","searchable","previousState","handleSelectChange","handleSearchChange","onCurrencyChange","onSearchChange","filteredOptions","style","className","render","inputAttributes","id","amountInputId","ariaLabelledByProp","addon","ariaLabelledBy","hasSingleCurrency","length","firstItem","onCustomAction","customActionLabel","isFixedCurrency","disabled","selectedCurrencyElementId","_jsxs","clsx","children","_jsx","Input","inputMode","placeholder","autoComplete","onKeyDown","onChange","onFocus","onBlur","onPaste","Flag","code","toLowerCase","intrinsicSize","Title","as","Typography","TITLE_SUBSECTION","getLocaleCurrencyName","toUpperCase","translate","SelectInput","UNSAFE_triggerButtonProps","undefined","formatMessage","messages","selectCurrencyLabel","items","compareValues","renderValue","withinTrigger","SelectInputOptionContent","title","icon","renderFooter","role","tabIndex","onClick","selectPlaceholder","filterable","filterPlaceholder","searchPlaceholder","onFilterChange","queryNormalized","query","filter","option","removeDuplicateValueOptions","currencyOptionFitsQuery","sortOptionsLabelsToFirst","uniqueValues","add","contains","property","includes","sort","first","second","firstContains","secondContains","injectIntl","withId","withInputAttributes","nonLabelable"],"mappings":"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"}
@@ -38,24 +38,32 @@ import 'virtua';
38
38
  import '../inputs/SelectInput/SelectInput.messages.mjs';
39
39
  import Title from '../title/Title.mjs';
40
40
  import messages from './MoneyInput.messages.mjs';
41
- import { parseAmount } from './currencyFormatting.mjs';
41
+ import { getCurrencyDecimals, parseAmount } from './currencyFormatting.mjs';
42
42
  import withId from '../withId/withId.mjs';
43
- import { formatAmount } from '@transferwise/formatting';
43
+ import { formatNumber, formatAmount } from '@transferwise/formatting';
44
44
 
45
45
  const isNumberOrNull = v => isNumber(v) || isNull(v);
46
46
  const formatAmountIfSet = ({
47
47
  amount,
48
48
  currency,
49
- locale
49
+ locale,
50
+ decimals
50
51
  }) => {
51
- return typeof amount === 'number' ? formatAmount(amount, currency, locale) : '';
52
+ if (typeof amount !== 'number') {
53
+ return '';
54
+ }
55
+ if (decimals != null && getCurrencyDecimals(currency) !== 0) {
56
+ return formatNumber(amount, locale, decimals);
57
+ }
58
+ return formatAmount(amount, currency, locale);
52
59
  };
53
60
  const parseNumber = ({
54
61
  amount,
55
62
  currency,
56
- locale
63
+ locale,
64
+ decimals
57
65
  }) => {
58
- return parseAmount(amount, currency, locale);
66
+ return parseAmount(amount, currency, locale, decimals);
59
67
  };
60
68
  const allowedInputKeys = new Set(['Backspace', 'Delete', ',', '.', 'ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Enter', 'Escape', 'Tab']);
61
69
  class MoneyInput extends Component {
@@ -72,7 +80,8 @@ class MoneyInput extends Component {
72
80
  formattedAmount: formatAmountIfSet({
73
81
  amount: props.amount,
74
82
  currency: props.selectedCurrency.currency,
75
- locale: props.intl.locale
83
+ locale: props.intl.locale,
84
+ decimals: props.decimals
76
85
  }),
77
86
  locale: props.intl.locale
78
87
  };
@@ -86,7 +95,8 @@ class MoneyInput extends Component {
86
95
  formattedAmount: formatAmountIfSet({
87
96
  amount: nextProps.amount,
88
97
  currency: nextProps.selectedCurrency.currency,
89
- locale: nextProps.intl.locale
98
+ locale: nextProps.intl.locale,
99
+ decimals: nextProps.decimals
90
100
  })
91
101
  });
92
102
  }
@@ -113,14 +123,16 @@ class MoneyInput extends Component {
113
123
  const parsed = isEmpty(paste) ? null : parseNumber({
114
124
  amount: paste,
115
125
  currency: this.props.selectedCurrency.currency,
116
- locale
126
+ locale,
127
+ decimals: this.props.decimals
117
128
  });
118
129
  if (isNumberOrNull(parsed)) {
119
130
  this.setState({
120
131
  formattedAmount: formatAmountIfSet({
121
132
  amount: parsed,
122
133
  currency: this.props.selectedCurrency.currency,
123
- locale
134
+ locale,
135
+ decimals: this.props.decimals
124
136
  })
125
137
  });
126
138
  this.props.onAmountChange?.(parsed);
@@ -137,7 +149,8 @@ class MoneyInput extends Component {
137
149
  const parsed = isEmpty(value) ? null : parseNumber({
138
150
  amount: value,
139
151
  currency: this.props.selectedCurrency.currency,
140
- locale: this.state.locale
152
+ locale: this.state.locale,
153
+ decimals: this.props.decimals
141
154
  });
142
155
  if (isNumberOrNull(parsed)) {
143
156
  this.props.onAmountChange?.(parsed);
@@ -177,7 +190,8 @@ class MoneyInput extends Component {
177
190
  const parsed = parseNumber({
178
191
  amount: previousState.formattedAmount,
179
192
  currency: this.props.selectedCurrency.currency,
180
- locale: previousState.locale
193
+ locale: previousState.locale,
194
+ decimals: this.props.decimals
181
195
  });
182
196
  if (!isNumberOrNull(parsed)) {
183
197
  return {
@@ -188,7 +202,8 @@ class MoneyInput extends Component {
188
202
  formattedAmount: formatAmountIfSet({
189
203
  amount: parsed,
190
204
  currency: this.props.selectedCurrency.currency,
191
- locale: previousState.locale
205
+ locale: previousState.locale,
206
+ decimals: this.props.decimals
192
207
  })
193
208
  };
194
209
  });
@@ -253,7 +268,8 @@ class MoneyInput extends Component {
253
268
  placeholder: formatAmountIfSet({
254
269
  amount: this.props.placeholder,
255
270
  currency: this.props.selectedCurrency.currency,
256
- locale: this.state.locale
271
+ locale: this.state.locale,
272
+ decimals: this.props.decimals
257
273
  }),
258
274
  autoComplete: "off",
259
275
  "aria-describedby": selectedCurrencyElementId,
@@ -1 +1 @@
1
- {"version":3,"file":"MoneyInput.mjs","sources":["../../src/moneyInput/MoneyInput.tsx"],"sourcesContent":["import { isEmpty, isNumber, isNull } from '@transferwise/neptune-validation';\nimport { Flag } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { Component } from 'react';\nimport { injectIntl, WrappedComponentProps } from 'react-intl';\n\nimport {\n Typography,\n Size,\n SizeLarge,\n SizeMedium,\n SizeSmall,\n getLocaleCurrencyName,\n} from '../common';\nimport { withInputAttributes, WithInputAttributesProps } from '../inputs/contexts';\nimport { Input } from '../inputs/Input';\nimport {\n SelectInput,\n SelectInputItem,\n SelectInputOptionContent,\n SelectInputOptionItem,\n SelectInputProps,\n} from '../inputs/SelectInput';\nimport Title from '../title';\n\nimport messages from './MoneyInput.messages';\nimport { formatAmount, parseAmount } from './currencyFormatting';\nimport withId from '../withId';\n\nexport interface CurrencyOptionItem {\n header?: never;\n value: string;\n label: string;\n currency: string;\n note?: string;\n searchable?: string;\n}\n\nexport interface CurrencyHeaderItem {\n header: string;\n}\n\nexport type CurrencyItem = CurrencyOptionItem | CurrencyHeaderItem;\n\nconst isNumberOrNull = (v: unknown): v is number | null => isNumber(v) || isNull(v);\n\nconst formatAmountIfSet = ({\n amount,\n currency,\n locale,\n}: {\n amount: number | null | undefined;\n currency: string;\n locale: string;\n}) => {\n return typeof amount === 'number' ? formatAmount(amount, currency, locale) : '';\n};\n\nconst parseNumber = ({\n amount,\n currency,\n locale,\n}: {\n amount: string;\n currency: string;\n locale: string;\n}) => {\n return parseAmount(amount, currency, locale);\n};\n\nconst allowedInputKeys = new Set([\n 'Backspace',\n 'Delete',\n ',',\n '.',\n 'ArrowDown',\n 'ArrowUp',\n 'ArrowLeft',\n 'ArrowRight',\n 'Enter',\n 'Escape',\n 'Tab',\n]);\n\nexport interface MoneyInputProps extends WrappedComponentProps {\n id?: string;\n 'aria-labelledby'?: string;\n currencies: readonly CurrencyItem[];\n selectedCurrency: CurrencyOptionItem;\n onCurrencyChange?: (value: CurrencyOptionItem) => void;\n placeholder?: number;\n amount: number | null;\n size?: SizeSmall | SizeMedium | SizeLarge;\n onAmountChange?: (value: number | null) => void;\n addon?: React.ReactNode;\n searchPlaceholder?: string;\n /**\n * Allows the consumer to react to searching, while the search itself is handled internally.\n */\n onSearchChange?: (value: { searchQuery: string; filteredOptions: CurrencyItem[] }) => void;\n customActionLabel?: React.ReactNode;\n onCustomAction?: () => void;\n classNames?: Record<string, string>;\n selectProps?: Partial<SelectInputProps<CurrencyOptionItem>>;\n}\n\nexport type MoneyInputPropsWithInputAttributes = MoneyInputProps &\n Partial<WithInputAttributesProps>;\n\ninterface MoneyInputState {\n searchQuery: string;\n formattedAmount: string;\n locale: string;\n}\n\nclass MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInputState> {\n declare props: MoneyInputPropsWithInputAttributes &\n Required<Pick<MoneyInputPropsWithInputAttributes, keyof typeof MoneyInput.defaultProps>>;\n\n static defaultProps = {\n size: Size.LARGE,\n classNames: {},\n selectProps: {},\n } satisfies Partial<MoneyInputPropsWithInputAttributes>;\n\n amountFocused = false;\n\n constructor(props: MoneyInputProps) {\n super(props);\n this.state = {\n searchQuery: '',\n formattedAmount: formatAmountIfSet({\n amount: props.amount,\n currency: props.selectedCurrency.currency,\n locale: props.intl.locale,\n }),\n locale: props.intl.locale,\n };\n }\n\n UNSAFE_componentWillReceiveProps(nextProps: MoneyInputProps) {\n this.setState({ locale: nextProps.intl.locale });\n\n if (!this.amountFocused) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: nextProps.amount,\n currency: nextProps.selectedCurrency.currency,\n locale: nextProps.intl.locale,\n }),\n });\n }\n }\n\n isInputAllowedForKeyEvent = (event: React.KeyboardEvent<HTMLInputElement>) => {\n const { metaKey, key, ctrlKey } = event;\n const isNumberKey = isNumber(Number.parseInt(key, 10));\n\n return isNumberKey || metaKey || ctrlKey || allowedInputKeys.has(key);\n };\n\n handleKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (!this.isInputAllowedForKeyEvent(event)) {\n event.preventDefault();\n }\n };\n\n handlePaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {\n const paste = event.clipboardData.getData('text');\n const { locale } = this.state;\n const parsed = isEmpty(paste)\n ? null\n : parseNumber({\n amount: paste,\n currency: this.props.selectedCurrency.currency,\n locale,\n });\n\n if (isNumberOrNull(parsed)) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale,\n }),\n });\n this.props.onAmountChange?.(parsed);\n }\n\n event.preventDefault();\n };\n\n onAmountChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {\n const { value } = event.target;\n this.setState({\n formattedAmount: value,\n });\n const parsed = isEmpty(value)\n ? null\n : parseNumber({\n amount: value,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n });\n if (isNumberOrNull(parsed)) {\n this.props.onAmountChange?.(parsed);\n }\n };\n\n onAmountBlur = () => {\n this.amountFocused = false;\n this.setAmount();\n };\n\n onAmountFocus = () => {\n this.amountFocused = true;\n };\n\n getSelectOptions() {\n const selectOptions = filterCurrenciesForQuery(this.props.currencies, this.state.searchQuery);\n\n const formattedOptions: SelectInputItem<CurrencyOptionItem>[] = [];\n let currentGroupOptions: SelectInputOptionItem<CurrencyOptionItem>[] | undefined;\n\n selectOptions.forEach((item) => {\n if (item.header != null) {\n currentGroupOptions = [];\n formattedOptions.push({\n type: 'group',\n label: item.header,\n options: currentGroupOptions,\n });\n } else {\n (currentGroupOptions ?? formattedOptions).push({\n type: 'option',\n value: item,\n filterMatchers: [item.value, item.label, item.note ?? '', item.searchable ?? ''],\n });\n }\n });\n\n return formattedOptions;\n }\n\n setAmount() {\n this.setState((previousState) => {\n const parsed = parseNumber({\n amount: previousState.formattedAmount,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n });\n if (!isNumberOrNull(parsed)) {\n return {\n formattedAmount: previousState.formattedAmount,\n };\n }\n return {\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n }),\n };\n });\n }\n\n handleSelectChange = (value: CurrencyOptionItem) => {\n this.handleSearchChange('');\n this.props.onCurrencyChange?.(value);\n };\n\n handleSearchChange = (searchQuery: string) => {\n this.setState({ searchQuery });\n this.props.onSearchChange?.({\n searchQuery,\n filteredOptions: filterCurrenciesForQuery(this.props.currencies, searchQuery),\n });\n };\n\n style = (className: string) => this.props.classNames[className] || className;\n\n render() {\n const {\n inputAttributes,\n id: amountInputId,\n 'aria-labelledby': ariaLabelledByProp,\n selectedCurrency,\n onCurrencyChange,\n size,\n addon,\n selectProps,\n } = this.props;\n const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes?.['aria-labelledby'];\n const selectOptions = this.getSelectOptions();\n\n const hasSingleCurrency = () => {\n if (selectOptions.length !== 0) {\n const firstItem = selectOptions[0];\n\n if (selectOptions.length === 1) {\n if (firstItem.type === 'option') {\n return firstItem.value.currency === selectedCurrency.currency;\n }\n if (firstItem.type === 'group') {\n return (\n firstItem.options.length === 1 &&\n !(this.props.onCustomAction && this.props.customActionLabel)\n );\n }\n }\n } else if (selectedCurrency?.currency) {\n return true;\n }\n\n return false;\n };\n\n const isFixedCurrency = (!this.state.searchQuery && hasSingleCurrency()) || !onCurrencyChange;\n const disabled = !this.props.onAmountChange;\n const selectedCurrencyElementId = `${inputAttributes?.id ?? amountInputId}SelectedCurrency`;\n\n return (\n <fieldset\n aria-invalid={inputAttributes?.['aria-invalid']}\n aria-describedby={inputAttributes?.['aria-describedby']}\n aria-labelledby={inputAttributes?.id ?? amountInputId}\n className={clsx(\n this.style('tw-money-input'),\n this.style('input-group'),\n this.style(`input-group-${size}`),\n )}\n >\n <Input\n id={inputAttributes?.id ?? amountInputId}\n aria-labelledby={ariaLabelledBy}\n value={this.state.formattedAmount}\n inputMode=\"decimal\"\n disabled={disabled}\n placeholder={formatAmountIfSet({\n amount: this.props.placeholder,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n })}\n autoComplete=\"off\"\n aria-describedby={selectedCurrencyElementId}\n onKeyDown={this.handleKeyDown}\n onChange={this.onAmountChange}\n onFocus={this.onAmountFocus}\n onBlur={this.onAmountBlur}\n onPaste={this.handlePaste}\n />\n {addon && (\n <span\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n disabled ? this.style('disabled') : '',\n )}\n >\n {addon}\n </span>\n )}\n {isFixedCurrency ? (\n <div\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n this.style('tw-money-input__fixed-currency'),\n disabled ? this.style('disabled') : '',\n )}\n id={selectedCurrencyElementId}\n >\n {(size === 'lg' || size === 'md') && (\n <span className={clsx(this.style('money-input-currency-flag'), this.style('m-r-2'))}>\n <Flag code={selectedCurrency.currency.toLowerCase()} intrinsicSize={24} />\n </span>\n )}\n <Title\n as=\"span\"\n type={Typography.TITLE_SUBSECTION}\n className={size === 'lg' ? this.style('m-r-1') : ''}\n aria-label={getLocaleCurrencyName(this.props.intl, selectedCurrency.currency)}\n >\n {selectedCurrency.currency.toUpperCase()}\n </Title>\n </div>\n ) : (\n <div\n translate=\"no\"\n className={clsx(\n this.style('input-group-btn'),\n this.style('amount-currency-select-btn'),\n )}\n >\n <SelectInput\n UNSAFE_triggerButtonProps={{\n id: undefined,\n 'aria-labelledby': undefined,\n 'aria-describedby': ariaLabelledBy,\n 'aria-invalid': undefined,\n 'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel),\n }}\n id={selectedCurrencyElementId}\n items={selectOptions}\n value={selectedCurrency}\n compareValues=\"currency\"\n renderValue={(currency, withinTrigger) => {\n return (\n <SelectInputOptionContent\n title={\n withinTrigger ? (\n <span\n aria-label={getLocaleCurrencyName(this.props.intl, currency.currency)}\n >\n {currency.currency.toUpperCase()}\n </span>\n ) : (\n currency.label\n )\n }\n note={withinTrigger ? undefined : currency.note}\n icon={<Flag code={currency.currency} intrinsicSize={24} />}\n />\n );\n }}\n renderFooter={\n this.props.onCustomAction\n ? () => (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events\n <div role=\"button\" tabIndex={0} onClick={this.props.onCustomAction}>\n {this.props.customActionLabel}\n </div>\n )\n : undefined\n }\n placeholder={this.props.intl.formatMessage(messages.selectPlaceholder)}\n filterable\n filterPlaceholder={\n this.props.searchPlaceholder ||\n this.props.intl.formatMessage(messages.searchPlaceholder)\n }\n disabled={disabled}\n size={size}\n onChange={this.handleSelectChange}\n onFilterChange={({ queryNormalized }) => {\n this.handleSearchChange(queryNormalized ?? '');\n }}\n {...selectProps}\n />\n </div>\n )}\n </fieldset>\n );\n }\n}\n\nfunction filterCurrenciesForQuery(\n currencies: readonly CurrencyItem[],\n query: string,\n): CurrencyItem[] {\n if (!query) {\n return [...currencies];\n }\n\n const options = currencies.filter(\n (option): option is CurrencyOptionItem => option.header == null,\n );\n const filteredOptions = removeDuplicateValueOptions(options).filter((option) =>\n currencyOptionFitsQuery(option, query),\n );\n\n return sortOptionsLabelsToFirst(filteredOptions, query);\n}\n\nfunction removeDuplicateValueOptions(options: readonly CurrencyOptionItem[]) {\n const uniqueValues = new Set<string>();\n return options.filter((option) => {\n if (!uniqueValues.has(option.value)) {\n uniqueValues.add(option.value);\n return true;\n }\n return false;\n });\n}\n\nfunction currencyOptionFitsQuery(option: CurrencyOptionItem, query: string) {\n if (!option.value) {\n return false;\n }\n\n return (\n contains(option.label, query) ||\n contains(option.searchable, query) ||\n contains(option.note, query)\n );\n}\n\nfunction contains(property: string | undefined, query: string) {\n return property?.toLowerCase().includes(query.toLowerCase());\n}\n\nfunction sortOptionsLabelsToFirst(options: readonly CurrencyOptionItem[], query: string) {\n return [...options].sort((first, second) => {\n const firstContains = contains(first.label, query);\n const secondContains = contains(second.label, query);\n\n if (firstContains && secondContains) {\n return 0;\n }\n if (firstContains) {\n return -1;\n }\n if (secondContains) {\n return 1;\n }\n return 0;\n });\n}\n\nexport default injectIntl(withId(withInputAttributes(MoneyInput, { nonLabelable: true })));\n"],"names":["isNumberOrNull","v","isNumber","isNull","formatAmountIfSet","amount","currency","locale","formatAmount","parseNumber","parseAmount","allowedInputKeys","Set","MoneyInput","Component","defaultProps","size","Size","LARGE","classNames","selectProps","amountFocused","constructor","props","state","searchQuery","formattedAmount","selectedCurrency","intl","UNSAFE_componentWillReceiveProps","nextProps","setState","isInputAllowedForKeyEvent","event","metaKey","key","ctrlKey","isNumberKey","Number","parseInt","has","handleKeyDown","preventDefault","handlePaste","paste","clipboardData","getData","parsed","isEmpty","onAmountChange","value","target","onAmountBlur","setAmount","onAmountFocus","getSelectOptions","selectOptions","filterCurrenciesForQuery","currencies","formattedOptions","currentGroupOptions","forEach","item","header","push","type","label","options","filterMatchers","note","searchable","previousState","handleSelectChange","handleSearchChange","onCurrencyChange","onSearchChange","filteredOptions","style","className","render","inputAttributes","id","amountInputId","ariaLabelledByProp","addon","ariaLabelledBy","hasSingleCurrency","length","firstItem","onCustomAction","customActionLabel","isFixedCurrency","disabled","selectedCurrencyElementId","_jsxs","clsx","children","_jsx","Input","inputMode","placeholder","autoComplete","onKeyDown","onChange","onFocus","onBlur","onPaste","Flag","code","toLowerCase","intrinsicSize","Title","as","Typography","TITLE_SUBSECTION","getLocaleCurrencyName","toUpperCase","translate","SelectInput","UNSAFE_triggerButtonProps","undefined","formatMessage","messages","selectCurrencyLabel","items","compareValues","renderValue","withinTrigger","SelectInputOptionContent","title","icon","renderFooter","role","tabIndex","onClick","selectPlaceholder","filterable","filterPlaceholder","searchPlaceholder","onFilterChange","queryNormalized","query","filter","option","removeDuplicateValueOptions","currencyOptionFitsQuery","sortOptionsLabelsToFirst","uniqueValues","add","contains","property","includes","sort","first","second","firstContains","secondContains","injectIntl","withId","withInputAttributes","nonLabelable"],"mappings":"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"}
1
+ {"version":3,"file":"MoneyInput.mjs","sources":["../../src/moneyInput/MoneyInput.tsx"],"sourcesContent":["import { isEmpty, isNumber, isNull } from '@transferwise/neptune-validation';\nimport { Flag } from '@wise/art';\nimport { clsx } from 'clsx';\nimport { Component } from 'react';\nimport { injectIntl, WrappedComponentProps } from 'react-intl';\n\nimport {\n Typography,\n Size,\n SizeLarge,\n SizeMedium,\n SizeSmall,\n getLocaleCurrencyName,\n} from '../common';\nimport { withInputAttributes, WithInputAttributesProps } from '../inputs/contexts';\nimport { Input } from '../inputs/Input';\nimport {\n SelectInput,\n SelectInputItem,\n SelectInputOptionContent,\n SelectInputOptionItem,\n SelectInputProps,\n} from '../inputs/SelectInput';\nimport Title from '../title';\n\nimport messages from './MoneyInput.messages';\nimport { formatAmount, formatNumber, getCurrencyDecimals, parseAmount } from './currencyFormatting';\nimport withId from '../withId';\n\nexport interface CurrencyOptionItem {\n header?: never;\n value: string;\n label: string;\n currency: string;\n note?: string;\n searchable?: string;\n}\n\nexport interface CurrencyHeaderItem {\n header: string;\n}\n\nexport type CurrencyItem = CurrencyOptionItem | CurrencyHeaderItem;\n\nconst isNumberOrNull = (v: unknown): v is number | null => isNumber(v) || isNull(v);\n\nconst formatAmountIfSet = ({\n amount,\n currency,\n locale,\n decimals,\n}: {\n amount: number | null | undefined;\n currency: string;\n locale: string;\n decimals?: number;\n}) => {\n if (typeof amount !== 'number') {\n return '';\n }\n if (decimals != null && getCurrencyDecimals(currency) !== 0) {\n return formatNumber(amount, locale, decimals);\n }\n return formatAmount(amount, currency, locale);\n};\n\nconst parseNumber = ({\n amount,\n currency,\n locale,\n decimals,\n}: {\n amount: string;\n currency: string;\n locale: string;\n decimals?: number;\n}) => {\n return parseAmount(amount, currency, locale, decimals);\n};\n\nconst allowedInputKeys = new Set([\n 'Backspace',\n 'Delete',\n ',',\n '.',\n 'ArrowDown',\n 'ArrowUp',\n 'ArrowLeft',\n 'ArrowRight',\n 'Enter',\n 'Escape',\n 'Tab',\n]);\n\nexport interface MoneyInputProps extends WrappedComponentProps {\n id?: string;\n 'aria-labelledby'?: string;\n currencies: readonly CurrencyItem[];\n selectedCurrency: CurrencyOptionItem;\n onCurrencyChange?: (value: CurrencyOptionItem) => void;\n placeholder?: number;\n amount: number | null;\n size?: SizeSmall | SizeMedium | SizeLarge;\n onAmountChange?: (value: number | null) => void;\n addon?: React.ReactNode;\n searchPlaceholder?: string;\n /**\n * Allows the consumer to react to searching, while the search itself is handled internally.\n */\n onSearchChange?: (value: { searchQuery: string; filteredOptions: CurrencyItem[] }) => void;\n customActionLabel?: React.ReactNode;\n onCustomAction?: () => void;\n classNames?: Record<string, string>;\n selectProps?: Partial<SelectInputProps<CurrencyOptionItem>>;\n /**\n * Specify the number of decimal places to format the amount. When not specified, the number of\n * decimals is determined by the selected currency (e.g. 2 for EUR, 0 for JPY, 3 for BHD).\n * This override is ignored for zero-decimal currencies (e.g. JPY, KRW, HUF), which always use 0.\n */\n decimals?: number;\n}\n\nexport type MoneyInputPropsWithInputAttributes = MoneyInputProps &\n Partial<WithInputAttributesProps>;\n\ninterface MoneyInputState {\n searchQuery: string;\n formattedAmount: string;\n locale: string;\n}\n\nclass MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInputState> {\n declare props: MoneyInputPropsWithInputAttributes &\n Required<Pick<MoneyInputPropsWithInputAttributes, keyof typeof MoneyInput.defaultProps>>;\n\n static defaultProps = {\n size: Size.LARGE,\n classNames: {},\n selectProps: {},\n } satisfies Partial<MoneyInputPropsWithInputAttributes>;\n\n amountFocused = false;\n\n constructor(props: MoneyInputProps) {\n super(props);\n this.state = {\n searchQuery: '',\n formattedAmount: formatAmountIfSet({\n amount: props.amount,\n currency: props.selectedCurrency.currency,\n locale: props.intl.locale,\n decimals: props.decimals,\n }),\n locale: props.intl.locale,\n };\n }\n\n UNSAFE_componentWillReceiveProps(nextProps: MoneyInputProps) {\n this.setState({ locale: nextProps.intl.locale });\n\n if (!this.amountFocused) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: nextProps.amount,\n currency: nextProps.selectedCurrency.currency,\n locale: nextProps.intl.locale,\n decimals: nextProps.decimals,\n }),\n });\n }\n }\n\n isInputAllowedForKeyEvent = (event: React.KeyboardEvent<HTMLInputElement>) => {\n const { metaKey, key, ctrlKey } = event;\n const isNumberKey = isNumber(Number.parseInt(key, 10));\n\n return isNumberKey || metaKey || ctrlKey || allowedInputKeys.has(key);\n };\n\n handleKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {\n if (!this.isInputAllowedForKeyEvent(event)) {\n event.preventDefault();\n }\n };\n\n handlePaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {\n const paste = event.clipboardData.getData('text');\n const { locale } = this.state;\n const parsed = isEmpty(paste)\n ? null\n : parseNumber({\n amount: paste,\n currency: this.props.selectedCurrency.currency,\n locale,\n decimals: this.props.decimals,\n });\n\n if (isNumberOrNull(parsed)) {\n this.setState({\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale,\n decimals: this.props.decimals,\n }),\n });\n this.props.onAmountChange?.(parsed);\n }\n\n event.preventDefault();\n };\n\n onAmountChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {\n const { value } = event.target;\n this.setState({\n formattedAmount: value,\n });\n const parsed = isEmpty(value)\n ? null\n : parseNumber({\n amount: value,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n decimals: this.props.decimals,\n });\n if (isNumberOrNull(parsed)) {\n this.props.onAmountChange?.(parsed);\n }\n };\n\n onAmountBlur = () => {\n this.amountFocused = false;\n this.setAmount();\n };\n\n onAmountFocus = () => {\n this.amountFocused = true;\n };\n\n getSelectOptions() {\n const selectOptions = filterCurrenciesForQuery(this.props.currencies, this.state.searchQuery);\n\n const formattedOptions: SelectInputItem<CurrencyOptionItem>[] = [];\n let currentGroupOptions: SelectInputOptionItem<CurrencyOptionItem>[] | undefined;\n\n selectOptions.forEach((item) => {\n if (item.header != null) {\n currentGroupOptions = [];\n formattedOptions.push({\n type: 'group',\n label: item.header,\n options: currentGroupOptions,\n });\n } else {\n (currentGroupOptions ?? formattedOptions).push({\n type: 'option',\n value: item,\n filterMatchers: [item.value, item.label, item.note ?? '', item.searchable ?? ''],\n });\n }\n });\n\n return formattedOptions;\n }\n\n setAmount() {\n this.setState((previousState) => {\n const parsed = parseNumber({\n amount: previousState.formattedAmount,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n decimals: this.props.decimals,\n });\n if (!isNumberOrNull(parsed)) {\n return {\n formattedAmount: previousState.formattedAmount,\n };\n }\n return {\n formattedAmount: formatAmountIfSet({\n amount: parsed,\n currency: this.props.selectedCurrency.currency,\n locale: previousState.locale,\n decimals: this.props.decimals,\n }),\n };\n });\n }\n\n handleSelectChange = (value: CurrencyOptionItem) => {\n this.handleSearchChange('');\n this.props.onCurrencyChange?.(value);\n };\n\n handleSearchChange = (searchQuery: string) => {\n this.setState({ searchQuery });\n this.props.onSearchChange?.({\n searchQuery,\n filteredOptions: filterCurrenciesForQuery(this.props.currencies, searchQuery),\n });\n };\n\n style = (className: string) => this.props.classNames[className] || className;\n\n render() {\n const {\n inputAttributes,\n id: amountInputId,\n 'aria-labelledby': ariaLabelledByProp,\n selectedCurrency,\n onCurrencyChange,\n size,\n addon,\n selectProps,\n } = this.props;\n const ariaLabelledBy = ariaLabelledByProp ?? inputAttributes?.['aria-labelledby'];\n const selectOptions = this.getSelectOptions();\n\n const hasSingleCurrency = () => {\n if (selectOptions.length !== 0) {\n const firstItem = selectOptions[0];\n\n if (selectOptions.length === 1) {\n if (firstItem.type === 'option') {\n return firstItem.value.currency === selectedCurrency.currency;\n }\n if (firstItem.type === 'group') {\n return (\n firstItem.options.length === 1 &&\n !(this.props.onCustomAction && this.props.customActionLabel)\n );\n }\n }\n } else if (selectedCurrency?.currency) {\n return true;\n }\n\n return false;\n };\n\n const isFixedCurrency = (!this.state.searchQuery && hasSingleCurrency()) || !onCurrencyChange;\n const disabled = !this.props.onAmountChange;\n const selectedCurrencyElementId = `${inputAttributes?.id ?? amountInputId}SelectedCurrency`;\n\n return (\n <fieldset\n aria-invalid={inputAttributes?.['aria-invalid']}\n aria-describedby={inputAttributes?.['aria-describedby']}\n aria-labelledby={inputAttributes?.id ?? amountInputId}\n className={clsx(\n this.style('tw-money-input'),\n this.style('input-group'),\n this.style(`input-group-${size}`),\n )}\n >\n <Input\n id={inputAttributes?.id ?? amountInputId}\n aria-labelledby={ariaLabelledBy}\n value={this.state.formattedAmount}\n inputMode=\"decimal\"\n disabled={disabled}\n placeholder={formatAmountIfSet({\n amount: this.props.placeholder,\n currency: this.props.selectedCurrency.currency,\n locale: this.state.locale,\n decimals: this.props.decimals,\n })}\n autoComplete=\"off\"\n aria-describedby={selectedCurrencyElementId}\n onKeyDown={this.handleKeyDown}\n onChange={this.onAmountChange}\n onFocus={this.onAmountFocus}\n onBlur={this.onAmountBlur}\n onPaste={this.handlePaste}\n />\n {addon && (\n <span\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n disabled ? this.style('disabled') : '',\n )}\n >\n {addon}\n </span>\n )}\n {isFixedCurrency ? (\n <div\n className={clsx(\n this.style('input-group-addon'),\n this.style(`input-${size}`),\n this.style('tw-money-input__fixed-currency'),\n disabled ? this.style('disabled') : '',\n )}\n id={selectedCurrencyElementId}\n >\n {(size === 'lg' || size === 'md') && (\n <span className={clsx(this.style('money-input-currency-flag'), this.style('m-r-2'))}>\n <Flag code={selectedCurrency.currency.toLowerCase()} intrinsicSize={24} />\n </span>\n )}\n <Title\n as=\"span\"\n type={Typography.TITLE_SUBSECTION}\n className={size === 'lg' ? this.style('m-r-1') : ''}\n aria-label={getLocaleCurrencyName(this.props.intl, selectedCurrency.currency)}\n >\n {selectedCurrency.currency.toUpperCase()}\n </Title>\n </div>\n ) : (\n <div\n translate=\"no\"\n className={clsx(\n this.style('input-group-btn'),\n this.style('amount-currency-select-btn'),\n )}\n >\n <SelectInput\n UNSAFE_triggerButtonProps={{\n id: undefined,\n 'aria-labelledby': undefined,\n 'aria-describedby': ariaLabelledBy,\n 'aria-invalid': undefined,\n 'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel),\n }}\n id={selectedCurrencyElementId}\n items={selectOptions}\n value={selectedCurrency}\n compareValues=\"currency\"\n renderValue={(currency, withinTrigger) => {\n return (\n <SelectInputOptionContent\n title={\n withinTrigger ? (\n <span\n aria-label={getLocaleCurrencyName(this.props.intl, currency.currency)}\n >\n {currency.currency.toUpperCase()}\n </span>\n ) : (\n currency.label\n )\n }\n note={withinTrigger ? undefined : currency.note}\n icon={<Flag code={currency.currency} intrinsicSize={24} />}\n />\n );\n }}\n renderFooter={\n this.props.onCustomAction\n ? () => (\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events\n <div role=\"button\" tabIndex={0} onClick={this.props.onCustomAction}>\n {this.props.customActionLabel}\n </div>\n )\n : undefined\n }\n placeholder={this.props.intl.formatMessage(messages.selectPlaceholder)}\n filterable\n filterPlaceholder={\n this.props.searchPlaceholder ||\n this.props.intl.formatMessage(messages.searchPlaceholder)\n }\n disabled={disabled}\n size={size}\n onChange={this.handleSelectChange}\n onFilterChange={({ queryNormalized }) => {\n this.handleSearchChange(queryNormalized ?? '');\n }}\n {...selectProps}\n />\n </div>\n )}\n </fieldset>\n );\n }\n}\n\nfunction filterCurrenciesForQuery(\n currencies: readonly CurrencyItem[],\n query: string,\n): CurrencyItem[] {\n if (!query) {\n return [...currencies];\n }\n\n const options = currencies.filter(\n (option): option is CurrencyOptionItem => option.header == null,\n );\n const filteredOptions = removeDuplicateValueOptions(options).filter((option) =>\n currencyOptionFitsQuery(option, query),\n );\n\n return sortOptionsLabelsToFirst(filteredOptions, query);\n}\n\nfunction removeDuplicateValueOptions(options: readonly CurrencyOptionItem[]) {\n const uniqueValues = new Set<string>();\n return options.filter((option) => {\n if (!uniqueValues.has(option.value)) {\n uniqueValues.add(option.value);\n return true;\n }\n return false;\n });\n}\n\nfunction currencyOptionFitsQuery(option: CurrencyOptionItem, query: string) {\n if (!option.value) {\n return false;\n }\n\n return (\n contains(option.label, query) ||\n contains(option.searchable, query) ||\n contains(option.note, query)\n );\n}\n\nfunction contains(property: string | undefined, query: string) {\n return property?.toLowerCase().includes(query.toLowerCase());\n}\n\nfunction sortOptionsLabelsToFirst(options: readonly CurrencyOptionItem[], query: string) {\n return [...options].sort((first, second) => {\n const firstContains = contains(first.label, query);\n const secondContains = contains(second.label, query);\n\n if (firstContains && secondContains) {\n return 0;\n }\n if (firstContains) {\n return -1;\n }\n if (secondContains) {\n return 1;\n }\n return 0;\n });\n}\n\nexport default injectIntl(withId(withInputAttributes(MoneyInput, { nonLabelable: true })));\n"],"names":["isNumberOrNull","v","isNumber","isNull","formatAmountIfSet","amount","currency","locale","decimals","getCurrencyDecimals","formatNumber","formatAmount","parseNumber","parseAmount","allowedInputKeys","Set","MoneyInput","Component","defaultProps","size","Size","LARGE","classNames","selectProps","amountFocused","constructor","props","state","searchQuery","formattedAmount","selectedCurrency","intl","UNSAFE_componentWillReceiveProps","nextProps","setState","isInputAllowedForKeyEvent","event","metaKey","key","ctrlKey","isNumberKey","Number","parseInt","has","handleKeyDown","preventDefault","handlePaste","paste","clipboardData","getData","parsed","isEmpty","onAmountChange","value","target","onAmountBlur","setAmount","onAmountFocus","getSelectOptions","selectOptions","filterCurrenciesForQuery","currencies","formattedOptions","currentGroupOptions","forEach","item","header","push","type","label","options","filterMatchers","note","searchable","previousState","handleSelectChange","handleSearchChange","onCurrencyChange","onSearchChange","filteredOptions","style","className","render","inputAttributes","id","amountInputId","ariaLabelledByProp","addon","ariaLabelledBy","hasSingleCurrency","length","firstItem","onCustomAction","customActionLabel","isFixedCurrency","disabled","selectedCurrencyElementId","_jsxs","clsx","children","_jsx","Input","inputMode","placeholder","autoComplete","onKeyDown","onChange","onFocus","onBlur","onPaste","Flag","code","toLowerCase","intrinsicSize","Title","as","Typography","TITLE_SUBSECTION","getLocaleCurrencyName","toUpperCase","translate","SelectInput","UNSAFE_triggerButtonProps","undefined","formatMessage","messages","selectCurrencyLabel","items","compareValues","renderValue","withinTrigger","SelectInputOptionContent","title","icon","renderFooter","role","tabIndex","onClick","selectPlaceholder","filterable","filterPlaceholder","searchPlaceholder","onFilterChange","queryNormalized","query","filter","option","removeDuplicateValueOptions","currencyOptionFitsQuery","sortOptionsLabelsToFirst","uniqueValues","add","contains","property","includes","sort","first","second","firstContains","secondContains","injectIntl","withId","withInputAttributes","nonLabelable"],"mappings":"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"}
@@ -52,9 +52,10 @@ function getCurrencyDecimals(currency) {
52
52
  function getDecimalSeparator(locale) {
53
53
  return isNumberLocaleSupported() ? 1.1.toLocaleString(locale)[1] : '.';
54
54
  }
55
- function parseAmount(number, currency, locale = index.DEFAULT_LOCALE) {
55
+ function parseAmount(number, currency, locale = index.DEFAULT_LOCALE, decimals) {
56
56
  const validLocale = getValidLocale(locale);
57
- const precision = getCurrencyDecimals(currency);
57
+ const currencyDefault = getCurrencyDecimals(currency);
58
+ const precision = currencyDefault === 0 ? 0 : decimals ?? currencyDefault;
58
59
  const groupSeparator = isNumberLocaleSupported() ? 10000 .toLocaleString(validLocale)[2] : ',';
59
60
  const decimalSeparator = getDecimalSeparator(validLocale);
60
61
  const numberWithStandardDecimalSeparator = (number || '').replace(new RegExp(`\\${groupSeparator}`, 'g'), '').replace(new RegExp(`\\${decimalSeparator}`, 'g'), '.').replace(/[^0-9.]/g, '');
@@ -66,5 +67,10 @@ Object.defineProperty(exports, "formatAmount", {
66
67
  enumerable: true,
67
68
  get: function () { return formatting.formatAmount; }
68
69
  });
70
+ Object.defineProperty(exports, "formatNumber", {
71
+ enumerable: true,
72
+ get: function () { return formatting.formatNumber; }
73
+ });
74
+ exports.getCurrencyDecimals = getCurrencyDecimals;
69
75
  exports.parseAmount = parseAmount;
70
76
  //# sourceMappingURL=currencyFormatting.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"currencyFormatting.js","sources":["../../src/moneyInput/currencyFormatting.ts"],"sourcesContent":["import { formatAmount } from '@transferwise/formatting';\n\nimport { DEFAULT_LOCALE } from '../common/locale';\n\nexport { formatAmount };\n\n// TODO: do not duplicate this between formatting and components\nconst currencyDecimals: Record<string, number> = {\n BIF: 0,\n BYR: 0,\n CLP: 0,\n DJF: 0,\n GNF: 0,\n JPY: 0,\n KMF: 0,\n KRW: 0,\n MGA: 0,\n PYG: 0,\n RWF: 0,\n VND: 0,\n VUV: 0,\n XAF: 0,\n XOF: 0,\n XPF: 0,\n // technically HUF does have decimals, but due to the exchange rate banks\n // do not accept decimal amounts\n HUF: 0,\n\n BHD: 3,\n JOD: 3,\n KWD: 3,\n OMR: 3,\n TND: 3,\n};\n\nconst DEFAULT_CURRENCY_DECIMALS = 2;\n\nfunction isNumberLocaleSupported() {\n const number = 1234;\n const numberString = number.toLocaleString && number.toLocaleString(DEFAULT_LOCALE);\n return numberString === '1,234';\n}\n\nfunction getValidLocale(locale: string) {\n try {\n const noUnderscoreLocale = locale.replace(/_/, '-');\n\n Intl.NumberFormat(noUnderscoreLocale);\n return noUnderscoreLocale;\n } catch {\n return DEFAULT_LOCALE;\n }\n}\n\nfunction getCurrencyDecimals(currency: string) {\n const upperCaseCurrency = currency.toUpperCase();\n return currencyDecimals[upperCaseCurrency] ?? DEFAULT_CURRENCY_DECIMALS;\n}\n\nfunction getDecimalSeparator(locale: string) {\n return isNumberLocaleSupported() ? (1.1).toLocaleString(locale)[1] : '.';\n}\n\nexport function parseAmount(number: string, currency: string, locale = DEFAULT_LOCALE) {\n const validLocale = getValidLocale(locale);\n\n const precision = getCurrencyDecimals(currency);\n const groupSeparator = isNumberLocaleSupported() ? (10000).toLocaleString(validLocale)[2] : ',';\n const decimalSeparator = getDecimalSeparator(validLocale);\n const numberWithStandardDecimalSeparator = (number || '')\n .replace(new RegExp(`\\\\${groupSeparator}`, 'g'), '')\n .replace(new RegExp(`\\\\${decimalSeparator}`, 'g'), '.')\n .replace(/[^0-9.]/g, '');\n const parsedAmount = Number.parseFloat(\n Number.parseFloat(numberWithStandardDecimalSeparator).toFixed(precision),\n );\n return Math.abs(parsedAmount);\n}\n"],"names":["currencyDecimals","BIF","BYR","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","VND","VUV","XAF","XOF","XPF","HUF","BHD","JOD","KWD","OMR","TND","DEFAULT_CURRENCY_DECIMALS","isNumberLocaleSupported","number","numberString","toLocaleString","DEFAULT_LOCALE","getValidLocale","locale","noUnderscoreLocale","replace","Intl","NumberFormat","getCurrencyDecimals","currency","upperCaseCurrency","toUpperCase","getDecimalSeparator","parseAmount","validLocale","precision","groupSeparator","decimalSeparator","numberWithStandardDecimalSeparator","RegExp","parsedAmount","Number","parseFloat","toFixed","Math","abs"],"mappings":"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"}
1
+ {"version":3,"file":"currencyFormatting.js","sources":["../../src/moneyInput/currencyFormatting.ts"],"sourcesContent":["import { formatAmount, formatNumber } from '@transferwise/formatting';\n\nimport { DEFAULT_LOCALE } from '../common/locale';\n\nexport { formatAmount, formatNumber };\n\n// TODO: do not duplicate this between formatting and components\nconst currencyDecimals: Record<string, number> = {\n BIF: 0,\n BYR: 0,\n CLP: 0,\n DJF: 0,\n GNF: 0,\n JPY: 0,\n KMF: 0,\n KRW: 0,\n MGA: 0,\n PYG: 0,\n RWF: 0,\n VND: 0,\n VUV: 0,\n XAF: 0,\n XOF: 0,\n XPF: 0,\n // technically HUF does have decimals, but due to the exchange rate banks\n // do not accept decimal amounts\n HUF: 0,\n\n BHD: 3,\n JOD: 3,\n KWD: 3,\n OMR: 3,\n TND: 3,\n};\n\nconst DEFAULT_CURRENCY_DECIMALS = 2;\n\nfunction isNumberLocaleSupported() {\n const number = 1234;\n const numberString = number.toLocaleString && number.toLocaleString(DEFAULT_LOCALE);\n return numberString === '1,234';\n}\n\nfunction getValidLocale(locale: string) {\n try {\n const noUnderscoreLocale = locale.replace(/_/, '-');\n\n Intl.NumberFormat(noUnderscoreLocale);\n return noUnderscoreLocale;\n } catch {\n return DEFAULT_LOCALE;\n }\n}\n\nexport function getCurrencyDecimals(currency: string) {\n const upperCaseCurrency = currency.toUpperCase();\n return currencyDecimals[upperCaseCurrency] ?? DEFAULT_CURRENCY_DECIMALS;\n}\n\nfunction getDecimalSeparator(locale: string) {\n return isNumberLocaleSupported() ? (1.1).toLocaleString(locale)[1] : '.';\n}\n\nexport function parseAmount(\n number: string,\n currency: string,\n locale = DEFAULT_LOCALE,\n decimals?: number,\n) {\n const validLocale = getValidLocale(locale);\n\n const currencyDefault = getCurrencyDecimals(currency);\n const precision = currencyDefault === 0 ? 0 : (decimals ?? currencyDefault);\n const groupSeparator = isNumberLocaleSupported() ? (10000).toLocaleString(validLocale)[2] : ',';\n const decimalSeparator = getDecimalSeparator(validLocale);\n const numberWithStandardDecimalSeparator = (number || '')\n .replace(new RegExp(`\\\\${groupSeparator}`, 'g'), '')\n .replace(new RegExp(`\\\\${decimalSeparator}`, 'g'), '.')\n .replace(/[^0-9.]/g, '');\n const parsedAmount = Number.parseFloat(\n Number.parseFloat(numberWithStandardDecimalSeparator).toFixed(precision),\n );\n return Math.abs(parsedAmount);\n}\n"],"names":["currencyDecimals","BIF","BYR","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","VND","VUV","XAF","XOF","XPF","HUF","BHD","JOD","KWD","OMR","TND","DEFAULT_CURRENCY_DECIMALS","isNumberLocaleSupported","number","numberString","toLocaleString","DEFAULT_LOCALE","getValidLocale","locale","noUnderscoreLocale","replace","Intl","NumberFormat","getCurrencyDecimals","currency","upperCaseCurrency","toUpperCase","getDecimalSeparator","parseAmount","decimals","validLocale","currencyDefault","precision","groupSeparator","decimalSeparator","numberWithStandardDecimalSeparator","RegExp","parsedAmount","Number","parseFloat","toFixed","Math","abs"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export { formatAmount } from '@transferwise/formatting';
1
+ export { formatAmount, formatNumber } from '@transferwise/formatting';
2
2
  import { DEFAULT_LOCALE } from '../common/locale/index.mjs';
3
3
 
4
4
  // TODO: do not duplicate this between formatting and components
@@ -50,9 +50,10 @@ function getCurrencyDecimals(currency) {
50
50
  function getDecimalSeparator(locale) {
51
51
  return isNumberLocaleSupported() ? 1.1.toLocaleString(locale)[1] : '.';
52
52
  }
53
- function parseAmount(number, currency, locale = DEFAULT_LOCALE) {
53
+ function parseAmount(number, currency, locale = DEFAULT_LOCALE, decimals) {
54
54
  const validLocale = getValidLocale(locale);
55
- const precision = getCurrencyDecimals(currency);
55
+ const currencyDefault = getCurrencyDecimals(currency);
56
+ const precision = currencyDefault === 0 ? 0 : decimals ?? currencyDefault;
56
57
  const groupSeparator = isNumberLocaleSupported() ? 10000 .toLocaleString(validLocale)[2] : ',';
57
58
  const decimalSeparator = getDecimalSeparator(validLocale);
58
59
  const numberWithStandardDecimalSeparator = (number || '').replace(new RegExp(`\\${groupSeparator}`, 'g'), '').replace(new RegExp(`\\${decimalSeparator}`, 'g'), '.').replace(/[^0-9.]/g, '');
@@ -60,5 +61,5 @@ function parseAmount(number, currency, locale = DEFAULT_LOCALE) {
60
61
  return Math.abs(parsedAmount);
61
62
  }
62
63
 
63
- export { parseAmount };
64
+ export { getCurrencyDecimals, parseAmount };
64
65
  //# sourceMappingURL=currencyFormatting.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"currencyFormatting.mjs","sources":["../../src/moneyInput/currencyFormatting.ts"],"sourcesContent":["import { formatAmount } from '@transferwise/formatting';\n\nimport { DEFAULT_LOCALE } from '../common/locale';\n\nexport { formatAmount };\n\n// TODO: do not duplicate this between formatting and components\nconst currencyDecimals: Record<string, number> = {\n BIF: 0,\n BYR: 0,\n CLP: 0,\n DJF: 0,\n GNF: 0,\n JPY: 0,\n KMF: 0,\n KRW: 0,\n MGA: 0,\n PYG: 0,\n RWF: 0,\n VND: 0,\n VUV: 0,\n XAF: 0,\n XOF: 0,\n XPF: 0,\n // technically HUF does have decimals, but due to the exchange rate banks\n // do not accept decimal amounts\n HUF: 0,\n\n BHD: 3,\n JOD: 3,\n KWD: 3,\n OMR: 3,\n TND: 3,\n};\n\nconst DEFAULT_CURRENCY_DECIMALS = 2;\n\nfunction isNumberLocaleSupported() {\n const number = 1234;\n const numberString = number.toLocaleString && number.toLocaleString(DEFAULT_LOCALE);\n return numberString === '1,234';\n}\n\nfunction getValidLocale(locale: string) {\n try {\n const noUnderscoreLocale = locale.replace(/_/, '-');\n\n Intl.NumberFormat(noUnderscoreLocale);\n return noUnderscoreLocale;\n } catch {\n return DEFAULT_LOCALE;\n }\n}\n\nfunction getCurrencyDecimals(currency: string) {\n const upperCaseCurrency = currency.toUpperCase();\n return currencyDecimals[upperCaseCurrency] ?? DEFAULT_CURRENCY_DECIMALS;\n}\n\nfunction getDecimalSeparator(locale: string) {\n return isNumberLocaleSupported() ? (1.1).toLocaleString(locale)[1] : '.';\n}\n\nexport function parseAmount(number: string, currency: string, locale = DEFAULT_LOCALE) {\n const validLocale = getValidLocale(locale);\n\n const precision = getCurrencyDecimals(currency);\n const groupSeparator = isNumberLocaleSupported() ? (10000).toLocaleString(validLocale)[2] : ',';\n const decimalSeparator = getDecimalSeparator(validLocale);\n const numberWithStandardDecimalSeparator = (number || '')\n .replace(new RegExp(`\\\\${groupSeparator}`, 'g'), '')\n .replace(new RegExp(`\\\\${decimalSeparator}`, 'g'), '.')\n .replace(/[^0-9.]/g, '');\n const parsedAmount = Number.parseFloat(\n Number.parseFloat(numberWithStandardDecimalSeparator).toFixed(precision),\n );\n return Math.abs(parsedAmount);\n}\n"],"names":["currencyDecimals","BIF","BYR","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","VND","VUV","XAF","XOF","XPF","HUF","BHD","JOD","KWD","OMR","TND","DEFAULT_CURRENCY_DECIMALS","isNumberLocaleSupported","number","numberString","toLocaleString","DEFAULT_LOCALE","getValidLocale","locale","noUnderscoreLocale","replace","Intl","NumberFormat","getCurrencyDecimals","currency","upperCaseCurrency","toUpperCase","getDecimalSeparator","parseAmount","validLocale","precision","groupSeparator","decimalSeparator","numberWithStandardDecimalSeparator","RegExp","parsedAmount","Number","parseFloat","toFixed","Math","abs"],"mappings":"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"}
1
+ {"version":3,"file":"currencyFormatting.mjs","sources":["../../src/moneyInput/currencyFormatting.ts"],"sourcesContent":["import { formatAmount, formatNumber } from '@transferwise/formatting';\n\nimport { DEFAULT_LOCALE } from '../common/locale';\n\nexport { formatAmount, formatNumber };\n\n// TODO: do not duplicate this between formatting and components\nconst currencyDecimals: Record<string, number> = {\n BIF: 0,\n BYR: 0,\n CLP: 0,\n DJF: 0,\n GNF: 0,\n JPY: 0,\n KMF: 0,\n KRW: 0,\n MGA: 0,\n PYG: 0,\n RWF: 0,\n VND: 0,\n VUV: 0,\n XAF: 0,\n XOF: 0,\n XPF: 0,\n // technically HUF does have decimals, but due to the exchange rate banks\n // do not accept decimal amounts\n HUF: 0,\n\n BHD: 3,\n JOD: 3,\n KWD: 3,\n OMR: 3,\n TND: 3,\n};\n\nconst DEFAULT_CURRENCY_DECIMALS = 2;\n\nfunction isNumberLocaleSupported() {\n const number = 1234;\n const numberString = number.toLocaleString && number.toLocaleString(DEFAULT_LOCALE);\n return numberString === '1,234';\n}\n\nfunction getValidLocale(locale: string) {\n try {\n const noUnderscoreLocale = locale.replace(/_/, '-');\n\n Intl.NumberFormat(noUnderscoreLocale);\n return noUnderscoreLocale;\n } catch {\n return DEFAULT_LOCALE;\n }\n}\n\nexport function getCurrencyDecimals(currency: string) {\n const upperCaseCurrency = currency.toUpperCase();\n return currencyDecimals[upperCaseCurrency] ?? DEFAULT_CURRENCY_DECIMALS;\n}\n\nfunction getDecimalSeparator(locale: string) {\n return isNumberLocaleSupported() ? (1.1).toLocaleString(locale)[1] : '.';\n}\n\nexport function parseAmount(\n number: string,\n currency: string,\n locale = DEFAULT_LOCALE,\n decimals?: number,\n) {\n const validLocale = getValidLocale(locale);\n\n const currencyDefault = getCurrencyDecimals(currency);\n const precision = currencyDefault === 0 ? 0 : (decimals ?? currencyDefault);\n const groupSeparator = isNumberLocaleSupported() ? (10000).toLocaleString(validLocale)[2] : ',';\n const decimalSeparator = getDecimalSeparator(validLocale);\n const numberWithStandardDecimalSeparator = (number || '')\n .replace(new RegExp(`\\\\${groupSeparator}`, 'g'), '')\n .replace(new RegExp(`\\\\${decimalSeparator}`, 'g'), '.')\n .replace(/[^0-9.]/g, '');\n const parsedAmount = Number.parseFloat(\n Number.parseFloat(numberWithStandardDecimalSeparator).toFixed(precision),\n );\n return Math.abs(parsedAmount);\n}\n"],"names":["currencyDecimals","BIF","BYR","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","VND","VUV","XAF","XOF","XPF","HUF","BHD","JOD","KWD","OMR","TND","DEFAULT_CURRENCY_DECIMALS","isNumberLocaleSupported","number","numberString","toLocaleString","DEFAULT_LOCALE","getValidLocale","locale","noUnderscoreLocale","replace","Intl","NumberFormat","getCurrencyDecimals","currency","upperCaseCurrency","toUpperCase","getDecimalSeparator","parseAmount","decimals","validLocale","currencyDefault","precision","groupSeparator","decimalSeparator","numberWithStandardDecimalSeparator","RegExp","parsedAmount","Number","parseFloat","toFixed","Math","abs"],"mappings":"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"}
@@ -37,6 +37,12 @@ export interface MoneyInputProps extends WrappedComponentProps {
37
37
  onCustomAction?: () => void;
38
38
  classNames?: Record<string, string>;
39
39
  selectProps?: Partial<SelectInputProps<CurrencyOptionItem>>;
40
+ /**
41
+ * Specify the number of decimal places to format the amount. When not specified, the number of
42
+ * decimals is determined by the selected currency (e.g. 2 for EUR, 0 for JPY, 3 for BHD).
43
+ * This override is ignored for zero-decimal currencies (e.g. JPY, KRW, HUF), which always use 0.
44
+ */
45
+ decimals?: number;
40
46
  }
41
47
  export type MoneyInputPropsWithInputAttributes = MoneyInputProps & Partial<WithInputAttributesProps>;
42
48
  declare const _default: import("react").FC<import("react-intl").WithIntlProps<Omit<MoneyInputPropsWithInputAttributes, "inputAttributes"> & {
@@ -1 +1 @@
1
- {"version":3,"file":"MoneyInput.d.ts","sourceRoot":"","sources":["../../../src/moneyInput/MoneyInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE/D,OAAO,EAGL,SAAS,EACT,UAAU,EACV,SAAS,EAEV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAuB,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAEnF,OAAO,EAKL,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AA0CnE,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IACpC,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1C,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,YAAY,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3F,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAAC;CAC7D;AAED,MAAM,MAAM,kCAAkC,GAAG,eAAe,GAC9D,OAAO,CAAC,wBAAwB,CAAC,CAAC;;;;;;;;AA4ZpC,wBAA2F"}
1
+ {"version":3,"file":"MoneyInput.d.ts","sourceRoot":"","sources":["../../../src/moneyInput/MoneyInput.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE/D,OAAO,EAGL,SAAS,EACT,UAAU,EACV,SAAS,EAEV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAuB,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAEnF,OAAO,EAKL,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAO/B,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAoDnE,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IACpC,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IAC1C,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,YAAY,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3F,iBAAiB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAC5D;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,kCAAkC,GAAG,eAAe,GAC9D,OAAO,CAAC,wBAAwB,CAAC,CAAC;;;;;;;;AAoapC,wBAA2F"}
@@ -1,4 +1,5 @@
1
- import { formatAmount } from '@transferwise/formatting';
2
- export { formatAmount };
3
- export declare function parseAmount(number: string, currency: string, locale?: string): number;
1
+ import { formatAmount, formatNumber } from '@transferwise/formatting';
2
+ export { formatAmount, formatNumber };
3
+ export declare function getCurrencyDecimals(currency: string): number;
4
+ export declare function parseAmount(number: string, currency: string, locale?: string, decimals?: number): number;
4
5
  //# sourceMappingURL=currencyFormatting.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"currencyFormatting.d.ts","sourceRoot":"","sources":["../../../src/moneyInput/currencyFormatting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIxD,OAAO,EAAE,YAAY,EAAE,CAAC;AA2DxB,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAiB,UAcpF"}
1
+ {"version":3,"file":"currencyFormatting.d.ts","sourceRoot":"","sources":["../../../src/moneyInput/currencyFormatting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAItE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AAkDtC,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,UAGnD;AAMD,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,SAAiB,EACvB,QAAQ,CAAC,EAAE,MAAM,UAgBlB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-8cc553f",
3
+ "version": "0.0.0-experimental-4660613",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1,5 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
- import { within, userEvent } from 'storybook/test';
2
+ import { within, userEvent, expect } from 'storybook/test';
3
3
  import { Lock } from '@transferwise/icons';
4
4
  import { useState } from 'react';
5
5
 
@@ -155,6 +155,15 @@ export const BalanceCurrencies: Story = {
155
155
  },
156
156
  };
157
157
 
158
+ export const WithDecimals: Story = {
159
+ args: {
160
+ currencies: [],
161
+ selectedCurrency: exampleCurrency.eur,
162
+ decimals: 4,
163
+ amount: 1234.1412,
164
+ },
165
+ };
166
+
158
167
  export const OpenedInput: Story = {
159
168
  ...MultipleCurrencies,
160
169
  play: async ({ canvasElement }) => {
@@ -1,5 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
- import { within, fireEvent } from 'storybook/test';
2
+ import { within, userEvent, fireEvent, expect } from 'storybook/test';
3
3
  import { allModes } from '../../.storybook/modes';
4
4
  import { lorem500 } from '../test-utils';
5
5
  import { Field } from '../field/Field';
@@ -102,3 +102,143 @@ export const SmoothScrollReset: Story = {
102
102
  },
103
103
  },
104
104
  };
105
+
106
+ export const WithDecimals: Story = {
107
+ args: {
108
+ currencies: [],
109
+ decimals: 4,
110
+ amount: 1234.5678,
111
+ },
112
+ play: async ({ canvas }) => {
113
+ const input = canvas.getByRole('textbox');
114
+ await expect(input).toHaveValue('1,234.5678');
115
+ await userEvent.clear(input);
116
+ await userEvent.type(input, '99.123456789');
117
+ await userEvent.tab();
118
+ await expect(input).toHaveValue('99.1235');
119
+ },
120
+ };
121
+
122
+ const eur = {
123
+ value: 'EUR',
124
+ label: 'EUR',
125
+ note: 'Euro',
126
+ currency: 'eur',
127
+ } as const;
128
+
129
+ const bhd = {
130
+ value: 'BHD',
131
+ label: 'BHD',
132
+ note: 'Bahraini dinar',
133
+ currency: 'bhd',
134
+ } as const;
135
+
136
+ const jpy = {
137
+ value: 'JPY',
138
+ label: 'JPY',
139
+ note: 'Japanese yen',
140
+ currency: 'jpy',
141
+ } as const;
142
+
143
+ const sharedProps = {
144
+ currencies: [],
145
+ onAmountChange: () => {},
146
+ onCurrencyChange: () => {},
147
+ } as const;
148
+
149
+ function Row({
150
+ label,
151
+ amount,
152
+ currency,
153
+ decimals,
154
+ }: {
155
+ label: string;
156
+ amount: number;
157
+ currency: { value: string; label: string; note: string; currency: string };
158
+ decimals: number;
159
+ }) {
160
+ return (
161
+ <div
162
+ style={{
163
+ display: 'grid',
164
+ gridTemplateColumns: '240px 1fr 1fr',
165
+ gap: 12,
166
+ alignItems: 'center',
167
+ }}
168
+ >
169
+ <Body as="span" style={{ fontSize: 13, color: '#6b7280' }}>
170
+ {label}
171
+ </Body>
172
+ <Field label={`No decimals prop (${currency.value})`}>
173
+ <MoneyInput {...sharedProps} selectedCurrency={currency} amount={amount} />
174
+ </Field>
175
+ <Field label={`decimals={${decimals}} (${currency.value})`}>
176
+ <MoneyInput
177
+ {...sharedProps}
178
+ selectedCurrency={currency}
179
+ amount={amount}
180
+ decimals={decimals}
181
+ />
182
+ </Field>
183
+ </div>
184
+ );
185
+ }
186
+
187
+ /**
188
+ * Side-by-side comparison of formatAmount (no decimals prop) vs formatNumber (with decimals prop)
189
+ * when decimals matches the currency default. Differences indicate a formatting parity issue.
190
+ *
191
+ * Problem 1: Trailing zero stripping — formatAmount strips ".00" for whole numbers,
192
+ * formatNumber always pads to the requested precision.
193
+ *
194
+ * Problem 2: BHD decimal count — formatAmount renders 2 fractional digits for BHD,
195
+ * but the currencyDecimals map says BHD has 3. formatNumber with decimals=3 shows 3.
196
+ */
197
+ export const DecimalsFormatParity: Story = {
198
+ render: () => (
199
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
200
+ <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
201
+ EUR — whole numbers (trailing zero stripping)
202
+ </Body>
203
+ <Row label="amount=0" amount={0} currency={eur} decimals={2} />
204
+ <Row label="amount=1" amount={1} currency={eur} decimals={2} />
205
+ <Row label="amount=42" amount={42} currency={eur} decimals={2} />
206
+ <Row label="amount=100" amount={100} currency={eur} decimals={2} />
207
+ <Row label="amount=1000" amount={1000} currency={eur} decimals={2} />
208
+ <Row label="amount=9999999" amount={9999999} currency={eur} decimals={2} />
209
+
210
+ <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
211
+ EUR — fractional amounts (should match)
212
+ </Body>
213
+ <Row label="amount=0.01" amount={0.01} currency={eur} decimals={2} />
214
+ <Row label="amount=0.1" amount={0.1} currency={eur} decimals={2} />
215
+ <Row label="amount=99.9" amount={99.9} currency={eur} decimals={2} />
216
+ <Row label="amount=1234567.89" amount={1234567.89} currency={eur} decimals={2} />
217
+
218
+ <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
219
+ BHD — all amounts (formatAmount uses 2 digits, formatNumber uses 3)
220
+ </Body>
221
+ <Row label="amount=0" amount={0} currency={bhd} decimals={3} />
222
+ <Row label="amount=0.001" amount={0.001} currency={bhd} decimals={3} />
223
+ <Row label="amount=0.01" amount={0.01} currency={bhd} decimals={3} />
224
+ <Row label="amount=0.1" amount={0.1} currency={bhd} decimals={3} />
225
+ <Row label="amount=42" amount={42} currency={bhd} decimals={3} />
226
+ <Row label="amount=99.9" amount={99.9} currency={bhd} decimals={3} />
227
+ <Row label="amount=999.99" amount={999.99} currency={bhd} decimals={3} />
228
+ <Row label="amount=1234567.89" amount={1234567.89} currency={bhd} decimals={3} />
229
+
230
+ <Body as="p" style={{ fontWeight: 600, marginTop: 8 }}>
231
+ JPY — zero-decimal currency (should always match)
232
+ </Body>
233
+ <Row label="amount=0" amount={0} currency={jpy} decimals={0} />
234
+ <Row label="amount=1" amount={1} currency={jpy} decimals={0} />
235
+ <Row label="amount=1000" amount={1000} currency={jpy} decimals={0} />
236
+ <Row label="amount=1234567" amount={1234567} currency={jpy} decimals={0} />
237
+ </div>
238
+ ),
239
+ parameters: {
240
+ chromatic: {
241
+ disableSnapshot: true,
242
+ },
243
+ },
244
+ };
@@ -253,6 +253,45 @@ describe('Money Input', () => {
253
253
  await userEvent.tab();
254
254
  expect(input).toHaveValue('1,234,567.65');
255
255
  });
256
+
257
+ it('uses custom decimals when specified', async () => {
258
+ customRender({ decimals: 4 });
259
+ const input = getInput();
260
+ await userEvent.clear(input);
261
+ await userEvent.type(input, '1234.56789');
262
+ await userEvent.tab();
263
+ expect(input).toHaveValue('1,234.5679');
264
+ });
265
+
266
+ it('uses custom decimals of 0', async () => {
267
+ customRender({ decimals: 0 });
268
+ const input = getInput();
269
+ await userEvent.clear(input);
270
+ await userEvent.type(input, '1234.56');
271
+ await userEvent.tab();
272
+ expect(input).toHaveValue('1,235');
273
+ });
274
+
275
+ it('ignores custom decimals override for zero-decimal currencies like JPY', async () => {
276
+ const jpyCurrency: CurrencyOptionItem = {
277
+ value: 'JPY',
278
+ label: 'JPY',
279
+ note: 'Japanese yen',
280
+ currency: 'jpy',
281
+ };
282
+ customRender({
283
+ decimals: 4,
284
+ selectedCurrency: jpyCurrency,
285
+ currencies: [jpyCurrency],
286
+ amount: 1234,
287
+ });
288
+ const input = getInput();
289
+ expect(input).toHaveValue('1,234');
290
+ await userEvent.clear(input);
291
+ await userEvent.type(input, '5678.9999');
292
+ await userEvent.tab();
293
+ expect(input).toHaveValue('5,679');
294
+ });
256
295
  });
257
296
 
258
297
  it('calls onAmountChange with parsed and formatted value', async () => {
@@ -263,6 +302,12 @@ describe('Money Input', () => {
263
302
  expect(initialProps.onAmountChange).toHaveBeenCalledWith(1000.65);
264
303
  });
265
304
 
305
+ it('calls onAmountChange with value rounded to custom decimals', async () => {
306
+ customRender({ decimals: 4, amount: null });
307
+ await userEvent.type(getInput(), '12.34567');
308
+ expect(initialProps.onAmountChange).toHaveBeenCalledWith(12.3457);
309
+ });
310
+
266
311
  it('calls onAmountChange when input value is empty', async () => {
267
312
  customRender();
268
313
  await userEvent.clear(getInput());
@@ -24,7 +24,7 @@ import {
24
24
  import Title from '../title';
25
25
 
26
26
  import messages from './MoneyInput.messages';
27
- import { formatAmount, parseAmount } from './currencyFormatting';
27
+ import { formatAmount, formatNumber, getCurrencyDecimals, parseAmount } from './currencyFormatting';
28
28
  import withId from '../withId';
29
29
 
30
30
  export interface CurrencyOptionItem {
@@ -48,24 +48,34 @@ const formatAmountIfSet = ({
48
48
  amount,
49
49
  currency,
50
50
  locale,
51
+ decimals,
51
52
  }: {
52
53
  amount: number | null | undefined;
53
54
  currency: string;
54
55
  locale: string;
56
+ decimals?: number;
55
57
  }) => {
56
- return typeof amount === 'number' ? formatAmount(amount, currency, locale) : '';
58
+ if (typeof amount !== 'number') {
59
+ return '';
60
+ }
61
+ if (decimals != null && getCurrencyDecimals(currency) !== 0) {
62
+ return formatNumber(amount, locale, decimals);
63
+ }
64
+ return formatAmount(amount, currency, locale);
57
65
  };
58
66
 
59
67
  const parseNumber = ({
60
68
  amount,
61
69
  currency,
62
70
  locale,
71
+ decimals,
63
72
  }: {
64
73
  amount: string;
65
74
  currency: string;
66
75
  locale: string;
76
+ decimals?: number;
67
77
  }) => {
68
- return parseAmount(amount, currency, locale);
78
+ return parseAmount(amount, currency, locale, decimals);
69
79
  };
70
80
 
71
81
  const allowedInputKeys = new Set([
@@ -102,6 +112,12 @@ export interface MoneyInputProps extends WrappedComponentProps {
102
112
  onCustomAction?: () => void;
103
113
  classNames?: Record<string, string>;
104
114
  selectProps?: Partial<SelectInputProps<CurrencyOptionItem>>;
115
+ /**
116
+ * Specify the number of decimal places to format the amount. When not specified, the number of
117
+ * decimals is determined by the selected currency (e.g. 2 for EUR, 0 for JPY, 3 for BHD).
118
+ * This override is ignored for zero-decimal currencies (e.g. JPY, KRW, HUF), which always use 0.
119
+ */
120
+ decimals?: number;
105
121
  }
106
122
 
107
123
  export type MoneyInputPropsWithInputAttributes = MoneyInputProps &
@@ -133,6 +149,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
133
149
  amount: props.amount,
134
150
  currency: props.selectedCurrency.currency,
135
151
  locale: props.intl.locale,
152
+ decimals: props.decimals,
136
153
  }),
137
154
  locale: props.intl.locale,
138
155
  };
@@ -147,6 +164,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
147
164
  amount: nextProps.amount,
148
165
  currency: nextProps.selectedCurrency.currency,
149
166
  locale: nextProps.intl.locale,
167
+ decimals: nextProps.decimals,
150
168
  }),
151
169
  });
152
170
  }
@@ -174,6 +192,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
174
192
  amount: paste,
175
193
  currency: this.props.selectedCurrency.currency,
176
194
  locale,
195
+ decimals: this.props.decimals,
177
196
  });
178
197
 
179
198
  if (isNumberOrNull(parsed)) {
@@ -182,6 +201,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
182
201
  amount: parsed,
183
202
  currency: this.props.selectedCurrency.currency,
184
203
  locale,
204
+ decimals: this.props.decimals,
185
205
  }),
186
206
  });
187
207
  this.props.onAmountChange?.(parsed);
@@ -201,6 +221,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
201
221
  amount: value,
202
222
  currency: this.props.selectedCurrency.currency,
203
223
  locale: this.state.locale,
224
+ decimals: this.props.decimals,
204
225
  });
205
226
  if (isNumberOrNull(parsed)) {
206
227
  this.props.onAmountChange?.(parsed);
@@ -248,6 +269,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
248
269
  amount: previousState.formattedAmount,
249
270
  currency: this.props.selectedCurrency.currency,
250
271
  locale: previousState.locale,
272
+ decimals: this.props.decimals,
251
273
  });
252
274
  if (!isNumberOrNull(parsed)) {
253
275
  return {
@@ -259,6 +281,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
259
281
  amount: parsed,
260
282
  currency: this.props.selectedCurrency.currency,
261
283
  locale: previousState.locale,
284
+ decimals: this.props.decimals,
262
285
  }),
263
286
  };
264
287
  });
@@ -340,6 +363,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
340
363
  amount: this.props.placeholder,
341
364
  currency: this.props.selectedCurrency.currency,
342
365
  locale: this.state.locale,
366
+ decimals: this.props.decimals,
343
367
  })}
344
368
  autoComplete="off"
345
369
  aria-describedby={selectedCurrencyElementId}
@@ -1,8 +1,8 @@
1
- import { formatAmount } from '@transferwise/formatting';
1
+ import { formatAmount, formatNumber } from '@transferwise/formatting';
2
2
 
3
3
  import { DEFAULT_LOCALE } from '../common/locale';
4
4
 
5
- export { formatAmount };
5
+ export { formatAmount, formatNumber };
6
6
 
7
7
  // TODO: do not duplicate this between formatting and components
8
8
  const currencyDecimals: Record<string, number> = {
@@ -52,7 +52,7 @@ function getValidLocale(locale: string) {
52
52
  }
53
53
  }
54
54
 
55
- function getCurrencyDecimals(currency: string) {
55
+ export function getCurrencyDecimals(currency: string) {
56
56
  const upperCaseCurrency = currency.toUpperCase();
57
57
  return currencyDecimals[upperCaseCurrency] ?? DEFAULT_CURRENCY_DECIMALS;
58
58
  }
@@ -61,10 +61,16 @@ function getDecimalSeparator(locale: string) {
61
61
  return isNumberLocaleSupported() ? (1.1).toLocaleString(locale)[1] : '.';
62
62
  }
63
63
 
64
- export function parseAmount(number: string, currency: string, locale = DEFAULT_LOCALE) {
64
+ export function parseAmount(
65
+ number: string,
66
+ currency: string,
67
+ locale = DEFAULT_LOCALE,
68
+ decimals?: number,
69
+ ) {
65
70
  const validLocale = getValidLocale(locale);
66
71
 
67
- const precision = getCurrencyDecimals(currency);
72
+ const currencyDefault = getCurrencyDecimals(currency);
73
+ const precision = currencyDefault === 0 ? 0 : (decimals ?? currencyDefault);
68
74
  const groupSeparator = isNumberLocaleSupported() ? (10000).toLocaleString(validLocale)[2] : ',';
69
75
  const decimalSeparator = getDecimalSeparator(validLocale);
70
76
  const numberWithStandardDecimalSeparator = (number || '')