@transferwise/components 0.0.0-experimental-08d336e → 0.0.0-experimental-b069e0c

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.
Files changed (36) hide show
  1. package/build/index.esm.js +1308 -1237
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +1306 -1236
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +1 -1
  6. package/build/styles/main.css +1 -1
  7. package/build/styles/moneyInput/MoneyInput.css +1 -1
  8. package/build/types/common/hooks/useLayout/useLayout.d.ts +6 -9
  9. package/build/types/common/hooks/useLayout/useLayout.d.ts.map +1 -1
  10. package/build/types/index.d.ts +0 -1
  11. package/build/types/index.d.ts.map +1 -1
  12. package/build/types/inputs/SelectInput.d.ts +2 -1
  13. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  14. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  15. package/package.json +1 -1
  16. package/src/common/hooks/useLayout/useLayout.ts +49 -21
  17. package/src/common/responsivePanel/ResponsivePanel.spec.js +1 -3
  18. package/src/dateLookup/DateLookup.testingLibrary.spec.js +19 -1
  19. package/src/dateLookup/dateHeader/DateHeader.spec.js +0 -2
  20. package/src/drawer/Drawer.rtl.spec.js +1 -3
  21. package/src/drawer/Drawer.spec.js +0 -2
  22. package/src/index.ts +0 -1
  23. package/src/info/Info.spec.js +11 -7
  24. package/src/inputs/SelectInput.tsx +8 -0
  25. package/src/main.css +1 -1
  26. package/src/modal/Modal.rtl.spec.js +1 -3
  27. package/src/modal/Modal.spec.js +0 -2
  28. package/src/modal/Modal.tsx +2 -2
  29. package/src/moneyInput/MoneyInput.css +1 -1
  30. package/src/moneyInput/MoneyInput.js +85 -44
  31. package/src/moneyInput/MoneyInput.less +35 -161
  32. package/src/moneyInput/MoneyInput.rtl.spec.js +71 -0
  33. package/src/moneyInput/MoneyInput.spec.js +245 -117
  34. package/src/moneyInput/MoneyInput.story.tsx +78 -1
  35. package/src/ssr.spec.js +0 -1
  36. package/src/uploadInput/UploadInput.spec.tsx +1 -3
@@ -1,10 +1,8 @@
1
1
  import { Position } from '../common';
2
- import { render, fireEvent, screen, mockMatchMedia } from '../test-utils';
2
+ import { render, fireEvent, screen } from '../test-utils';
3
3
 
4
4
  import Modal from './Modal';
5
5
 
6
- mockMatchMedia();
7
-
8
6
  describe('Modal', () => {
9
7
  const props = {
10
8
  onClose: jest.fn(),
@@ -1,12 +1,10 @@
1
1
  import { mount } from 'enzyme';
2
2
 
3
3
  import { Title } from '..';
4
- import { mockMatchMedia } from '../test-utils';
5
4
 
6
5
  import Modal from './Modal';
7
6
 
8
7
  jest.useFakeTimers();
9
- mockMatchMedia();
10
8
  jest.mock('../common');
11
9
 
12
10
  const defaultLocale = 'en-GB';
@@ -52,7 +52,7 @@ const Modal = ({
52
52
  }: ModalProps) => {
53
53
  const checkSpecialClasses = (classToCheck: string) =>
54
54
  className?.split(' ').includes(classToCheck);
55
- const { isMedium } = useLayout();
55
+ const { isMobile, isMedium: isTablet } = useLayout();
56
56
 
57
57
  // These should be replaced with props in breaking change.
58
58
  const isCompact = checkSpecialClasses('compact');
@@ -60,7 +60,7 @@ const Modal = ({
60
60
 
61
61
  const contentReference = useRef<HTMLDivElement>(null);
62
62
 
63
- return !isMedium ? (
63
+ return isMobile || isTablet ? (
64
64
  <Drawer
65
65
  open={open}
66
66
  headerTitle={title}
@@ -1 +1 @@
1
- .tw-money-input .tw-money-input__fixed-currency{padding-left:0!important}[dir=rtl] .tw-money-input .tw-money-input__fixed-currency{padding-left:0!important;padding-right:0!important}.tw-money-input .tw-money-input__fixed-currency.input-md .currency-flag{margin-bottom:2px}.np-theme-personal .tw-money-input .tw-money-input__fixed-currency.input-md .currency-flag{margin-bottom:1px}.tw-money-input .tw-money-input__fixed-currency.input-lg .currency-flag{margin-bottom:4px}.np-theme-personal .tw-money-input .tw-money-input__fixed-currency.input-lg .currency-flag{margin-bottom:3px}.tw-money-input .tw-money-input__fixed-currency .currency-flag{vertical-align:middle}.tw-money-input .tw-money-input__fixed-currency .np-text-title-subsection{font-weight:var(--font-weight-normal)}.tw-money-input__keyline{background-color:#86a7bd1a;background-color:var(--color-background-neutral);border:1px solid #0000001a;border:1px solid var(--color-border-neutral);height:24px;height:var(--size-24);margin-right:24px;margin-right:var(--size-24);transform:translateY(4px);width:2px}[dir=rtl] .tw-money-input__keyline{margin-left:24px;margin-left:var(--size-24);margin-right:0}.tw-money-input__fixed-currency{position:relative}.tw-money-input__fixed-currency span{color:#5d7079;color:var(--color-content-secondary)}__text{font-size:1rem;font-size:var(--font-size-16)}.input-group-sm .np-text-title-subsection,.input-group-sm .tw-money-input__text{font-size:.875rem;font-size:var(--font-size-14)}.input-group-md .np-text-title-subsection{font-size:1rem;font-size:var(--font-size-16)}.input-group-lg .tw-money-input__text{font-size:1.375rem;font-size:var(--font-size-22)}.tw-money-input .amount-currency-select-btn>.np-select>.btn{align-items:center;display:flex;max-height:50px}.tw-money-input .amount-currency-select-btn>.np-select>.btn span:not(.tw-icon){font-weight:400;font-weight:var(--font-weight-regular);min-width:2.6em}.tw-money-input .amount-currency-select-btn>.np-select>.btn .currency-flag{display:inline-block!important;margin-left:2px;margin-right:2px}.tw-money-input .amount-currency-select-btn>.np-select>.np-dropdown-toggle{padding:0 16px;padding:0 var(--padding-small);text-align:center}.np-theme-personal .tw-money-input .amount-currency-select-btn>.np-select>.np-dropdown-toggle,.np-theme-personal .tw-money-input .amount-currency-select-btn>.np-select>.np-dropdown-toggle:active,.np-theme-personal .tw-money-input .amount-currency-select-btn>.np-select>.np-dropdown-toggle:hover:not(:focus){box-shadow:none}.np-theme-personal .tw-money-input .amount-currency-select-btn>.np-select>.np-dropdown-toggle .np-text-body-large{overflow:visible;text-overflow:clip}.np-theme-personal .tw-money-input .amount-currency-select-btn>.np-select>.np-dropdown-toggle .np-text-body-large .tw-money-input__text.np-text-title-subsection{font-weight:600;font-weight:var(--font-weight-semi-bold)}.tw-money-input .amount-currency-select-btn>.np-select>.np-btn>span.tw-icon{position:static}.np-theme-personal .tw-money-input__keyline{display:none}.np-theme-personal .tw-money-input.input-group-sm .form-control{min-height:34px}.np-theme-personal .tw-money-input.input-group-md .amount-currency-select-btn .btn-md,.np-theme-personal .tw-money-input.input-group-md .form-control{min-height:53px}.np-theme-personal .tw-money-input .tw-money-input__fixed-currency .np-text-title-subsection{color:#768e9c;color:var(--color-content-tertiary);font-weight:600;font-weight:var(--font-weight-semi-bold)}.np-theme-personal .tw-money-input button{border:none}.np-theme-personal .tw-money-input .np-text-title-subsection{color:var(--color-interactive-primary)}.np-theme-personal .tw-money-input .np-select-filter:focus{outline:none}.np-theme-personal .tw-money-input .amount-currency-select-btn .currency-flag{margin-right:0;margin-top:0}.np-theme-personal .tw-money-input .amount-currency-select-btn .np-btn-md .np-text-body-large{margin-left:4px;margin-right:4px}.np-theme-personal .tw-money-input .amount-currency-select-btn .np-btn-lg .np-text-body-large{margin-left:9px;margin-right:9px}
1
+ .tw-money-input{display:flex}.tw-money-input .tw-money-input__fixed-currency{padding-left:0!important}[dir=rtl] .tw-money-input .tw-money-input__fixed-currency{padding-left:0!important;padding-right:0!important}.tw-money-input .tw-money-input__fixed-currency .np-text-title-subsection{color:#768e9c;color:var(--color-content-tertiary);font-weight:600;font-weight:var(--font-weight-semi-bold)}.tw-money-input.input-group-sm .form-control{min-height:34px}.tw-money-input.input-group-sm .np-text-title-subsection{font-size:.875rem;font-size:var(--font-size-14)}.tw-money-input.input-group-md .form-control{min-height:53px}.tw-money-input.input-group-md .np-text-title-subsection{font-size:1rem;font-size:var(--font-size-16)}.tw-money-input .input-group-addon{flex-shrink:0}.tw-money-input .input-group-addon:not(.amount-currency-select-btn){align-items:center;display:flex;flex-shrink:0;width:auto}.tw-money-input .amount-currency-select-btn{flex-shrink:0;line-height:normal;width:auto}.tw-money-input .amount-currency-select-btn .np-button-input{border-bottom-right-radius:10px!important;border-bottom-right-radius:var(--radius-small)!important;border-top-right-radius:10px!important;border-top-right-radius:var(--radius-small)!important}.tw-money-input .amount-currency-select-btn .np-button-input,.tw-money-input .amount-currency-select-btn .np-button-input:active,.tw-money-input .amount-currency-select-btn .np-button-input:hover:not(:focus){box-shadow:none}
@@ -1,4 +1,5 @@
1
1
  import { isEmpty, isNumber, isNull } from '@transferwise/neptune-validation';
2
+ import { Flag } from '@wise/art';
2
3
  import classNames from 'classnames';
3
4
  import PropTypes from 'prop-types';
4
5
  import { Component } from 'react';
@@ -9,7 +10,7 @@ import { Key as keyValues } from '../common/key';
9
10
  import keyCodes from '../common/keyCodes';
10
11
  import { Size } from '../common/propsValues/size';
11
12
  import { Input } from '../inputs/Input';
12
- import Select from '../select';
13
+ import { SelectInput, SelectInputOptionContent } from '../inputs/SelectInput';
13
14
  import Title from '../title';
14
15
 
15
16
  import messages from './MoneyInput.messages';
@@ -23,7 +24,7 @@ const Currency = PropTypes.shape({
23
24
  note: PropTypes.string,
24
25
  searchable: PropTypes.string,
25
26
  });
26
- const CUSTOM_ACTION = 'CUSTOM_ACTION';
27
+
27
28
  const isNumberOrNull = (v) => isNumber(v) || isNull(v);
28
29
 
29
30
  const formatAmountIfSet = (amount, currency, locale, maxLengthOverride) => {
@@ -67,6 +68,7 @@ class MoneyInput extends Component {
67
68
  this.formatMessage = this.props.intl.formatMessage;
68
69
  this.state = {
69
70
  searchQuery: '',
71
+ selectedOption: this.props.selectedCurrency,
70
72
  formattedAmount: formatAmountIfSet(
71
73
  props.amount,
72
74
  props.selectedCurrency.currency,
@@ -165,14 +167,37 @@ class MoneyInput extends Component {
165
167
  this.amountFocused = true;
166
168
  };
167
169
 
170
+ mapOption = (item) => {
171
+ return {
172
+ type: 'option',
173
+ value: item,
174
+ filterMatchers: [item.value, item.label, item.note, item.searchable],
175
+ };
176
+ };
177
+
168
178
  getSelectOptions() {
169
179
  const selectOptions = [...filterOptionsForQuery(this.props.currencies, this.state.searchQuery)];
170
180
 
171
- if (this.props.onCustomAction) {
172
- selectOptions.push({ value: CUSTOM_ACTION, label: this.props.customActionLabel });
173
- }
174
-
175
- return selectOptions;
181
+ let formattedOptions = [];
182
+ let groupIndex = null;
183
+
184
+ selectOptions.forEach((item) => {
185
+ if (item.header) {
186
+ formattedOptions.push({
187
+ type: 'group',
188
+ label: item.header,
189
+ options: [],
190
+ });
191
+ groupIndex = formattedOptions.length - 1;
192
+ } else {
193
+ if (groupIndex === null) {
194
+ formattedOptions.push(this.mapOption(item));
195
+ } else {
196
+ formattedOptions[groupIndex]?.options.push(this.mapOption(item));
197
+ }
198
+ }
199
+ });
200
+ return formattedOptions;
176
201
  }
177
202
 
178
203
  setAmount() {
@@ -201,11 +226,14 @@ class MoneyInput extends Component {
201
226
 
202
227
  handleSelectChange = (value) => {
203
228
  this.handleSearchChange('');
229
+ this.setState({ selectedOption: value });
230
+ this.props.onCurrencyChange(value);
231
+ };
204
232
 
205
- if (this.props.onCustomAction && value.value === CUSTOM_ACTION) {
233
+ handleCustomAction = () => {
234
+ this.handleSearchChange('');
235
+ if (this.props.onCustomAction) {
206
236
  this.props.onCustomAction();
207
- } else {
208
- this.props.onCurrencyChange(value);
209
237
  }
210
238
  };
211
239
 
@@ -225,10 +253,25 @@ class MoneyInput extends Component {
225
253
  const { selectedCurrency, onCurrencyChange, size, addon, id, selectProps, maxLengthOverride } =
226
254
  this.props;
227
255
  const selectOptions = this.getSelectOptions();
256
+
257
+ const firstOptionValue = () => {
258
+ if (selectOptions.length !== 0) {
259
+ const firstOption = selectOptions[0];
260
+ if (firstOption.type === 'option') {
261
+ return firstOption.value.value;
262
+ }
263
+ if (firstOption.type === 'group' && firstOption.options.length !== 0) {
264
+ return firstOption.options[0].value.value;
265
+ }
266
+ }
267
+ return null;
268
+ };
269
+
270
+ const firstOption = firstOptionValue();
271
+
228
272
  const isFixedCurrency =
229
- !this.state.searchQuery &&
230
- ((selectOptions.length === 1 && selectOptions[0].currency === selectedCurrency.currency) ||
231
- !onCurrencyChange);
273
+ (selectOptions.length === 1 && firstOption === selectedCurrency.currency) ||
274
+ !onCurrencyChange;
232
275
 
233
276
  const disabled = !this.props.onAmountChange;
234
277
  return (
@@ -279,16 +322,11 @@ class MoneyInput extends Component {
279
322
  )}
280
323
  >
281
324
  {(size === 'lg' || size === 'md') && (
282
- <>
283
- <i className={classNames(this.style('tw-money-input__keyline'))} />
284
- <i
285
- className={classNames(
286
- this.style('currency-flag'),
287
- this.style(`currency-flag-${selectedCurrency.currency.toLowerCase()}`),
288
- this.style('m-r-2'),
289
- )}
290
- />
291
- </>
325
+ <span
326
+ className={classNames(this.style('money-input-currency-flag'), this.style('m-r-2'))}
327
+ >
328
+ <Flag code={selectedCurrency.currency.toLowerCase()} intrinsicSize={24} />
329
+ </span>
292
330
  )}
293
331
  <Title
294
332
  as="span"
@@ -305,30 +343,33 @@ class MoneyInput extends Component {
305
343
  this.style('amount-currency-select-btn'),
306
344
  )}
307
345
  >
308
- <Select
309
- id={id ? `${id}-select` : undefined}
310
- classNames={this.props.classNames}
311
- options={selectOptions}
312
- selected={{
313
- ...selectedCurrency,
314
- label: (
315
- <Title
316
- as="span"
317
- type={Typography.TITLE_SUBSECTION}
318
- className="tw-money-input__text"
319
- >
320
- {selectedCurrency.label}
321
- </Title>
322
- ),
323
- note: null,
346
+ <SelectInput
347
+ items={selectOptions}
348
+ value={this.state.selectedOption}
349
+ renderValue={(currency, withinTrigger) => {
350
+ return (
351
+ <SelectInputOptionContent
352
+ title={currency.label}
353
+ note={withinTrigger ? undefined : currency.note}
354
+ icon={<Flag code={currency.currency} intrinsicSize={24} />}
355
+ />
356
+ );
324
357
  }}
358
+ renderFooter={
359
+ this.props.onCustomAction
360
+ ? () => (
361
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events
362
+ <div role="button" tabIndex="0" onClick={this.handleCustomAction}>
363
+ {this.props.customActionLabel}
364
+ </div>
365
+ )
366
+ : null
367
+ }
325
368
  placeholder={this.formatMessage(messages.selectPlaceholder)}
326
- searchPlaceholder={this.props.searchPlaceholder}
327
- searchValue={this.state.searchQuery}
369
+ filterable
370
+ filterPlaceholder={this.props.searchPlaceholder}
371
+ disabled={disabled}
328
372
  size={size}
329
- required
330
- dropdownWidth={Size.LARGE}
331
- inverse
332
373
  onChange={this.handleSelectChange}
333
374
  onSearchChange={this.handleSearchChange}
334
375
  {...selectProps}
@@ -2,187 +2,61 @@
2
2
  @import (reference) "../../node_modules/@transferwise/neptune-css/src/less/mixins/_logical-properties.less";
3
3
 
4
4
  .tw-money-input {
5
+ display: flex;
5
6
  .tw-money-input__fixed-currency {
6
7
  .padding(left, 0) !important;
7
8
 
8
- // let's plan on getting rid of these custom margins
9
- // they center the flags for fixed money input currency flags
10
- // there's got to be a better way to do it
11
-
12
- &.input-md {
13
- .currency-flag {
14
- margin-bottom: 2px;
15
-
16
- .np-theme-personal & {
17
- margin-bottom: 1px;
18
- }
19
- }
20
- }
21
-
22
- &.input-lg {
23
- .currency-flag {
24
- margin-bottom: 4px;
25
-
26
- .np-theme-personal & {
27
- margin-bottom: 3px;
28
- }
29
- }
30
- }
31
-
32
- .currency-flag {
33
- vertical-align: middle;
34
- }
35
-
36
9
  .np-text-title-subsection {
37
- font-weight: var(--font-weight-normal);
10
+ color: var(--color-content-tertiary);
11
+ font-weight: var(--font-weight-semi-bold);
38
12
  }
39
13
  }
40
14
 
41
- &__keyline {
42
- width: 2px;
43
- border: solid 1px var(--color-border-neutral);
44
- height: var(--size-24);
45
- background-color: var(--color-background-neutral);
46
- .margin(right, var(--size-24));
47
-
48
- transform: translateY(4px);
49
- }
50
-
51
- &__fixed-currency {
52
- span {
53
- color: var(--color-content-secondary);
54
- }
55
-
56
- position: relative;
57
- }
58
- }
59
-
60
- &__text {
61
- font-size: var(--font-size-16);
62
- }
63
-
64
- &.input-group-sm {
65
- .tw-money-input__text {
66
- font-size: var(--font-size-14);
67
- }
68
-
69
- .np-text-title-subsection {
70
- font-size: var(--font-size-14);
71
- }
72
- }
73
-
74
- &.input-group-md {
75
- .np-text-title-subsection {
76
- font-size: var(--font-size-16);
77
- }
78
- }
79
-
80
- &.input-group-lg {
81
- .tw-money-input__text {
82
- font-size: var(--font-size-22);
83
- }
84
- }
85
-
86
- .tw-money-input .amount-currency-select-btn > .np-select > .btn {
87
- display: flex;
88
- align-items: center;
89
- max-height: 50px;
90
-
91
- span:not(.tw-icon) {
92
- min-width: 2.6em; // fits a 3 letter string, ZMW being the longest one
93
- font-weight: var(--font-weight-regular);
94
- }
95
-
96
- .currency-flag {
97
- margin-right: 2px;
98
- margin-left: 2px;
99
- display: inline-block !important; // override a hidden-xs in select option which has too much logic around it
100
- }
101
- }
102
-
103
- .tw-money-input .amount-currency-select-btn > .np-select > .np-dropdown-toggle {
104
- padding: 0 var(--padding-small);
105
- text-align: center;
106
-
107
- .np-theme-personal & {
108
- box-shadow: none;
109
-
110
- &:hover:not(:focus),
111
- &:active {
112
- box-shadow: none;
113
- }
114
-
115
- .np-text-body-large {
116
- .tw-money-input__text.np-text-title-subsection {
117
- font-weight: var(--font-weight-semi-bold);
118
- }
119
- overflow: visible;
120
- text-overflow: clip;
121
- }
122
- }
123
- }
124
-
125
- .tw-money-input .amount-currency-select-btn > .np-select > .np-btn > span.tw-icon {
126
- position: static;
127
- }
128
-
129
- .np-theme-personal {
130
- .tw-money-input__keyline {
131
- display: none;
132
- }
133
-
134
- .tw-money-input.input-group-sm {
15
+ &.input-group-sm {
135
16
  .form-control {
136
17
  min-height: 34px;
137
18
  }
138
- }
139
-
140
- .tw-money-input.input-group-md {
141
- .form-control,
142
- .amount-currency-select-btn .btn-md {
143
- min-height: 53px;
19
+ .np-text-title-subsection {
20
+ font-size: var(--font-size-14);
144
21
  }
145
22
  }
146
23
 
147
- .tw-money-input {
148
- .tw-money-input__fixed-currency {
149
- .np-text-title-subsection {
150
- color: var(--color-content-tertiary);
151
- font-weight: var(--font-weight-semi-bold);
152
- }
153
- }
154
-
155
- button {
156
- border: none;
24
+ &.input-group-md {
25
+ .form-control {
26
+ min-height: 53px;
157
27
  }
158
-
159
28
  .np-text-title-subsection {
160
- color: var(--color-interactive-primary);
29
+ font-size: var(--font-size-16);
161
30
  }
31
+ }
162
32
 
163
- .np-select-filter:focus {
164
- outline: none;
165
- }
33
+ // .np-select -> .np-input-group
34
+ // .np-dropdown-toggle -> .np-button-input
166
35
 
167
- .amount-currency-select-btn {
168
- .currency-flag {
169
- margin-right: 0;
170
- margin-top: 0;
171
- }
36
+ .input-group-addon {
37
+ flex-shrink: 0;
38
+ &:not(.amount-currency-select-btn) {
39
+ display: flex;
40
+ align-items: center;
41
+ flex-shrink: 0;
42
+ width: auto;
43
+ }
44
+ }
45
+
46
+ .amount-currency-select-btn {
47
+ flex-shrink: 0;
48
+ width: auto;
49
+ line-height: normal;
172
50
 
173
- .np-btn-md {
174
- .np-text-body-large {
175
- margin-left: 4px;
176
- margin-right: 4px;
177
- }
178
- }
51
+ .np-button-input {
52
+ border-top-right-radius: var(--radius-small) !important;
53
+ border-bottom-right-radius: var(--radius-small) !important;
179
54
 
180
- .np-btn-lg {
181
- .np-text-body-large {
182
- margin-left: 9px;
183
- margin-right: 9px;
184
- }
55
+ &,
56
+ &:hover:not(:focus),
57
+ &:active {
58
+ box-shadow: none;
185
59
  }
186
60
  }
187
61
  }
188
- }
62
+ }
@@ -0,0 +1,71 @@
1
+ import { mockMatchMedia, mockResizeObserver, render, userEvent } from '../test-utils';
2
+
3
+ import MoneyInput from './MoneyInput';
4
+
5
+ mockMatchMedia();
6
+ mockResizeObserver();
7
+
8
+ describe('MoneyInput', () => {
9
+ const currencies = [
10
+ {
11
+ header: 'Popular currencies',
12
+ },
13
+ {
14
+ value: 'EUR',
15
+ label: 'EUR',
16
+ note: 'Euro',
17
+ currency: 'eur',
18
+ searchable: 'Spain, Germany, France, Austria, Estonia',
19
+ },
20
+ {
21
+ value: 'USD',
22
+ label: 'USD',
23
+ note: 'United States dollar',
24
+ currency: 'usd',
25
+ searchable: 'Hong Kong, Saudi Arabia',
26
+ },
27
+ {
28
+ value: 'GBP',
29
+ label: 'GBP',
30
+ note: 'British pound',
31
+ currency: 'gbp',
32
+ searchable: 'England, Scotland, Wales',
33
+ },
34
+ {
35
+ header: 'Some other currencies',
36
+ },
37
+ {
38
+ value: 'CAD',
39
+ label: 'CAD',
40
+ note: 'Canadian dollar',
41
+ currency: 'cad',
42
+ },
43
+ {
44
+ value: 'AUD',
45
+ label: 'AUD',
46
+ note: 'Australian dollar',
47
+ currency: 'aud',
48
+ },
49
+ ];
50
+ const props = {
51
+ currencies,
52
+ selectedCurrency: currencies[1],
53
+ amount: 1000,
54
+ onAmountChange: jest.fn(),
55
+ onCurrencyChange: jest.fn(),
56
+ };
57
+ it.each([
58
+ ['asd', ''],
59
+ ['1a2s3d', '123'],
60
+ ['±!@#$^*_+?><', ''],
61
+ ['1±!@#$^*,_+?><2', '1,2'],
62
+ ['12,3', '12,3'],
63
+ ['12.3', '12.3'],
64
+ ])("ignores the letters when typed '%s' and shows '%s'", (testValue, expectedValue) => {
65
+ const { container } = render(<MoneyInput {...props} amount={null} />);
66
+
67
+ const input = container.querySelector('input');
68
+ userEvent.type(input, testValue);
69
+ expect(input).toHaveValue(expectedValue);
70
+ });
71
+ });