@transferwise/components 0.0.0-experimental-c46d48c → 0.0.0-experimental-5865548
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.
- package/build/alert/Alert.js +8 -0
- package/build/alert/Alert.js.map +1 -1
- package/build/alert/Alert.mjs +8 -0
- package/build/alert/Alert.mjs.map +1 -1
- package/build/common/closeButton/CloseButton.js +3 -1
- package/build/common/closeButton/CloseButton.js.map +1 -1
- package/build/common/closeButton/CloseButton.mjs +3 -1
- package/build/common/closeButton/CloseButton.mjs.map +1 -1
- package/build/i18n/en.json +0 -2
- package/build/i18n/en.json.js +0 -2
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +0 -2
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.js +2 -36
- package/build/phoneNumberInput/PhoneNumberInput.js.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.messages.js +0 -6
- package/build/phoneNumberInput/PhoneNumberInput.messages.js.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.messages.mjs +0 -6
- package/build/phoneNumberInput/PhoneNumberInput.messages.mjs.map +1 -1
- package/build/phoneNumberInput/PhoneNumberInput.mjs +2 -36
- package/build/phoneNumberInput/PhoneNumberInput.mjs.map +1 -1
- package/build/types/alert/Alert.d.ts.map +1 -1
- package/build/types/common/closeButton/CloseButton.d.ts +2 -0
- package/build/types/common/closeButton/CloseButton.d.ts.map +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.messages.d.ts +0 -8
- package/build/types/phoneNumberInput/PhoneNumberInput.messages.d.ts.map +1 -1
- package/build/types/test-utils/index.d.ts +0 -4
- package/build/types/test-utils/index.d.ts.map +1 -1
- package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
- package/build/withDisplayFormat/WithDisplayFormat.js +3 -2
- package/build/withDisplayFormat/WithDisplayFormat.js.map +1 -1
- package/build/withDisplayFormat/WithDisplayFormat.mjs +3 -2
- package/build/withDisplayFormat/WithDisplayFormat.mjs.map +1 -1
- package/package.json +4 -7
- package/src/alert/Alert.spec.tsx +11 -0
- package/src/alert/Alert.story.tsx +23 -9
- package/src/alert/Alert.tsx +14 -1
- package/src/common/closeButton/CloseButton.spec.tsx +13 -1
- package/src/common/closeButton/CloseButton.tsx +3 -0
- package/src/i18n/en.json +0 -2
- package/src/phoneNumberInput/PhoneNumberInput.messages.ts +0 -8
- package/src/phoneNumberInput/PhoneNumberInput.spec.tsx +43 -77
- package/src/phoneNumberInput/PhoneNumberInput.tsx +2 -34
- package/src/test-utils/jest.setup.ts +0 -4
- package/src/typeahead/Typeahead.spec.tsx +182 -0
- package/src/typeahead/typeaheadInput/TypeaheadInput.spec.tsx +103 -0
- package/src/typeahead/util/highlight.spec.tsx +43 -0
- package/src/withDisplayFormat/WithDisplayFormat.spec.js +11 -15
- package/src/withDisplayFormat/WithDisplayFormat.tsx +3 -2
- package/src/typeahead/Typeahead.rtl.spec.tsx +0 -54
- package/src/typeahead/Typeahead.spec.js +0 -404
- package/src/typeahead/typeaheadInput/TypeaheadInput.spec.js +0 -74
- package/src/typeahead/typeaheadOption/TypeaheadOption.spec.js +0 -75
- package/src/typeahead/util/highlight.spec.js +0 -34
|
@@ -15,6 +15,7 @@ export type CloseButtonProps = Pick<
|
|
|
15
15
|
filled?: boolean;
|
|
16
16
|
isDisabled?: boolean;
|
|
17
17
|
testId?: string;
|
|
18
|
+
tabIndex?: number;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -29,6 +30,7 @@ export const CloseButton = forwardRef(function CloseButton(
|
|
|
29
30
|
onClick,
|
|
30
31
|
isDisabled,
|
|
31
32
|
testId,
|
|
33
|
+
tabIndex,
|
|
32
34
|
}: CloseButtonProps,
|
|
33
35
|
reference: React.ForwardedRef<HTMLButtonElement | null>,
|
|
34
36
|
) {
|
|
@@ -55,6 +57,7 @@ export const CloseButton = forwardRef(function CloseButton(
|
|
|
55
57
|
aria-disabled={isDisabled}
|
|
56
58
|
disabled={isDisabled}
|
|
57
59
|
data-testid={testId}
|
|
60
|
+
tabIndex={tabIndex}
|
|
58
61
|
onClick={onClick}
|
|
59
62
|
>
|
|
60
63
|
<Icon size={size === Size.SMALL || size === Size.EXTRA_SMALL ? 16 : 24} />
|
package/src/i18n/en.json
CHANGED
|
@@ -23,8 +23,6 @@
|
|
|
23
23
|
"neptune.MoneyInput.Select.placeholder": "Select an option...",
|
|
24
24
|
"neptune.MoneyInput.Select.selectCurrencyLabel": "Select currency",
|
|
25
25
|
"neptune.PhoneNumberInput.SelectInput.placeholder": "Select an option...",
|
|
26
|
-
"neptune.PhoneNumberInput.countryCodeLabel": "Country code",
|
|
27
|
-
"neptune.PhoneNumberInput.phoneNumberLabel": "Phone number",
|
|
28
26
|
"neptune.Select.searchPlaceholder": "Search...",
|
|
29
27
|
"neptune.SelectInput.noResultsFound": "No results found",
|
|
30
28
|
"neptune.SelectOption.action.label": "Choose",
|
|
@@ -5,12 +5,4 @@ export default defineMessages({
|
|
|
5
5
|
id: 'neptune.PhoneNumberInput.SelectInput.placeholder',
|
|
6
6
|
defaultMessage: 'Select an option...',
|
|
7
7
|
},
|
|
8
|
-
countryCodeLabel: {
|
|
9
|
-
id: 'neptune.PhoneNumberInput.countryCodeLabel',
|
|
10
|
-
defaultMessage: 'Country code',
|
|
11
|
-
},
|
|
12
|
-
phoneNumberLabel: {
|
|
13
|
-
id: 'neptune.PhoneNumberInput.phoneNumberLabel',
|
|
14
|
-
defaultMessage: 'Phone number',
|
|
15
|
-
},
|
|
16
8
|
});
|
|
@@ -21,30 +21,28 @@ describe('PhoneNumberInput', () => {
|
|
|
21
21
|
const customRender = (overrides: Partial<PhoneNumberInputProps> = {}, locale?: string) =>
|
|
22
22
|
render(<PhoneNumberInput {...props} {...overrides} />, { locale });
|
|
23
23
|
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const getPhoneNumberInput = () => screen.getByRole('textbox');
|
|
27
|
-
const getPhoneNumberLabel = () => screen.getByText('Phone number');
|
|
24
|
+
const getPrefixEl = () => screen.getByRole('combobox');
|
|
25
|
+
const getInputEl = () => screen.getByRole('textbox');
|
|
28
26
|
|
|
29
27
|
describe('defaults', () => {
|
|
30
28
|
it('should set prefix control to default UK value', () => {
|
|
31
29
|
customRender();
|
|
32
|
-
expect(
|
|
30
|
+
expect(getPrefixEl()).toHaveTextContent('+44');
|
|
33
31
|
});
|
|
34
32
|
|
|
35
33
|
it('should set number control to empty', () => {
|
|
36
34
|
customRender();
|
|
37
|
-
expect(
|
|
35
|
+
expect(getInputEl()).toHaveValue('');
|
|
38
36
|
});
|
|
39
37
|
|
|
40
38
|
it('should not disable the select', () => {
|
|
41
39
|
customRender();
|
|
42
|
-
expect(
|
|
40
|
+
expect(getPrefixEl()).toBeEnabled();
|
|
43
41
|
});
|
|
44
42
|
|
|
45
43
|
it('should not disable the input', () => {
|
|
46
44
|
customRender();
|
|
47
|
-
expect(
|
|
45
|
+
expect(getInputEl()).toBeEnabled();
|
|
48
46
|
});
|
|
49
47
|
});
|
|
50
48
|
|
|
@@ -52,54 +50,22 @@ describe('PhoneNumberInput', () => {
|
|
|
52
50
|
const prefix = '+39';
|
|
53
51
|
const number = '123456789';
|
|
54
52
|
customRender({ initialValue: `${prefix}${number}` });
|
|
55
|
-
expect(
|
|
56
|
-
expect(
|
|
53
|
+
expect(getPrefixEl()).toHaveTextContent(prefix);
|
|
54
|
+
expect(getInputEl()).toHaveValue(number);
|
|
57
55
|
});
|
|
58
56
|
|
|
59
57
|
describe('id prop', () => {
|
|
60
|
-
it('should render
|
|
58
|
+
it('should not render id by default', () => {
|
|
61
59
|
customRender();
|
|
62
|
-
|
|
63
|
-
expect(
|
|
64
|
-
const countryCodeLabelID = getCountryCodeLabel().getAttribute('id');
|
|
65
|
-
expect(countryCodeLabelID).toMatch(/^country-code-label-[a-z0-9]{6}$/);
|
|
66
|
-
const phoneNumberInputID = getPhoneNumberInput().getAttribute('id');
|
|
67
|
-
expect(phoneNumberInputID).toMatch(/^phone-number-input-[a-z0-9]{6}$/);
|
|
68
|
-
const phoneNumberLabelID = getPhoneNumberLabel().getAttribute('id');
|
|
69
|
-
expect(phoneNumberLabelID).toMatch(/^phone-number-label-[a-z0-9]{6}$/);
|
|
60
|
+
expect(getPrefixEl()).not.toHaveAttribute('id');
|
|
61
|
+
expect(getInputEl()).not.toHaveAttribute('id');
|
|
70
62
|
});
|
|
71
63
|
|
|
72
|
-
it('should
|
|
64
|
+
it('should respect `id` for the input and ignore the select', () => {
|
|
73
65
|
const id = 'component-id';
|
|
74
66
|
customRender({ id });
|
|
75
|
-
expect(
|
|
76
|
-
expect(
|
|
77
|
-
expect(getCountryCodeSelect()).toHaveAttribute('id', `${id}-country-code-select`);
|
|
78
|
-
expect(getCountryCodeLabel()).toHaveAttribute('id', `${id}-country-code-label`);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should set correct ARIA attributes on the country code select when id is provided', () => {
|
|
82
|
-
const id = 'my-id';
|
|
83
|
-
customRender({ id });
|
|
84
|
-
expect(getCountryCodeSelect()).toHaveAttribute('aria-labelledby', `${id}-country-code-label`);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should set correct ARIA attributes on the country code select when id is not provided', () => {
|
|
88
|
-
customRender();
|
|
89
|
-
const selectLabelledBy = getCountryCodeSelect().getAttribute('aria-labelledby');
|
|
90
|
-
expect(selectLabelledBy).toMatch(/^country-code-label-[a-z0-9]{6}$/);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should set correct ARIA attributes on the phone number input when id is provided', () => {
|
|
94
|
-
const id = 'my-id';
|
|
95
|
-
customRender({ id });
|
|
96
|
-
expect(getPhoneNumberInput()).toHaveAttribute('aria-labelledby', `${id}-phone-number-label`);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should set correct ARIA attributes on the phone number input when id is not provided', () => {
|
|
100
|
-
customRender();
|
|
101
|
-
const inputLabelledBy = getPhoneNumberInput().getAttribute('aria-labelledby');
|
|
102
|
-
expect(inputLabelledBy).toMatch(/^phone-number-label-[a-z0-9]{6}$/);
|
|
67
|
+
expect(getPrefixEl()).not.toHaveAttribute('id');
|
|
68
|
+
expect(getInputEl()).toHaveAttribute('id', id);
|
|
103
69
|
});
|
|
104
70
|
});
|
|
105
71
|
|
|
@@ -128,38 +94,38 @@ describe('PhoneNumberInput', () => {
|
|
|
128
94
|
it(`'${number}' number should update the value properly`, async () => {
|
|
129
95
|
await renderAndPaste(number);
|
|
130
96
|
|
|
131
|
-
expect(
|
|
132
|
-
expect(
|
|
97
|
+
expect(getPrefixEl()).toHaveTextContent(countryCode);
|
|
98
|
+
expect(getInputEl()).toHaveValue(localNumber);
|
|
133
99
|
expect(props.onChange).toHaveBeenCalledWith(number.replace(/[\s-]+/g, ''), countryCode);
|
|
134
100
|
});
|
|
135
101
|
});
|
|
136
102
|
|
|
137
103
|
it('should not paste invalid characters', async () => {
|
|
138
104
|
await renderAndPaste('+36asdasdasd');
|
|
139
|
-
expect(
|
|
140
|
-
expect(
|
|
105
|
+
expect(getPrefixEl()).toHaveTextContent(initialPrefix);
|
|
106
|
+
expect(getInputEl()).toHaveValue(initialNumber);
|
|
141
107
|
expect(props.onChange).not.toHaveBeenCalled();
|
|
142
108
|
});
|
|
143
109
|
|
|
144
110
|
it('should not paste countries which are not in the select', async () => {
|
|
145
111
|
await renderAndPaste('+9992342343423');
|
|
146
|
-
expect(
|
|
147
|
-
expect(
|
|
112
|
+
expect(getPrefixEl()).toHaveTextContent(initialPrefix);
|
|
113
|
+
expect(getInputEl()).toHaveValue(initialNumber);
|
|
148
114
|
expect(props.onChange).not.toHaveBeenCalled();
|
|
149
115
|
});
|
|
150
116
|
|
|
151
117
|
it("should not paste numbers which doesn't start with the country code", async () => {
|
|
152
118
|
await renderAndPaste('0+36303932551');
|
|
153
|
-
expect(
|
|
154
|
-
expect(
|
|
119
|
+
expect(getPrefixEl()).toHaveTextContent(initialPrefix);
|
|
120
|
+
expect(getInputEl()).toHaveValue(initialNumber);
|
|
155
121
|
expect(props.onChange).not.toHaveBeenCalled();
|
|
156
122
|
});
|
|
157
123
|
|
|
158
124
|
it("should allow pasting numbers which don't contain a country code", async () => {
|
|
159
125
|
const newNumber = '06303932551';
|
|
160
126
|
await renderAndPaste(newNumber);
|
|
161
|
-
expect(
|
|
162
|
-
expect(
|
|
127
|
+
expect(getPrefixEl()).toHaveTextContent(initialPrefix);
|
|
128
|
+
expect(getInputEl()).toHaveValue(newNumber);
|
|
163
129
|
expect(props.onChange).toHaveBeenCalledWith(`${initialPrefix}${newNumber}`, initialPrefix);
|
|
164
130
|
});
|
|
165
131
|
});
|
|
@@ -170,12 +136,12 @@ describe('PhoneNumberInput', () => {
|
|
|
170
136
|
|
|
171
137
|
it('should set the select to the longest matching prefix', () => {
|
|
172
138
|
customRender(initialProps);
|
|
173
|
-
expect(
|
|
139
|
+
expect(getPrefixEl()).toHaveTextContent('+1868');
|
|
174
140
|
});
|
|
175
141
|
|
|
176
142
|
it('should set the number input to the rest of the number', () => {
|
|
177
143
|
customRender(initialProps);
|
|
178
|
-
expect(
|
|
144
|
+
expect(getInputEl()).toHaveValue('123456789');
|
|
179
145
|
});
|
|
180
146
|
});
|
|
181
147
|
|
|
@@ -184,20 +150,20 @@ describe('PhoneNumberInput', () => {
|
|
|
184
150
|
|
|
185
151
|
it('should empty the select', () => {
|
|
186
152
|
customRender(initialProps);
|
|
187
|
-
expect(
|
|
153
|
+
expect(getPrefixEl()).toHaveTextContent('Select an option...');
|
|
188
154
|
});
|
|
189
155
|
|
|
190
156
|
it('should put the whole value in the input without the plus', () => {
|
|
191
157
|
customRender(initialProps);
|
|
192
|
-
expect(
|
|
158
|
+
expect(getInputEl()).toHaveValue('999123456789');
|
|
193
159
|
});
|
|
194
160
|
});
|
|
195
161
|
|
|
196
162
|
describe('when an partial model is supplied (with a matching prefix)', () => {
|
|
197
163
|
it('should set the select to the matching prefix and put the rest of the number in the suffix', () => {
|
|
198
164
|
customRender({ initialValue: '+123' });
|
|
199
|
-
expect(
|
|
200
|
-
expect(
|
|
165
|
+
expect(getPrefixEl()).toHaveTextContent('+1');
|
|
166
|
+
expect(getInputEl()).toHaveValue('23');
|
|
201
167
|
});
|
|
202
168
|
});
|
|
203
169
|
});
|
|
@@ -205,8 +171,8 @@ describe('PhoneNumberInput', () => {
|
|
|
205
171
|
describe('when disabled is true', () => {
|
|
206
172
|
it('should disable both controls', () => {
|
|
207
173
|
customRender({ disabled: true });
|
|
208
|
-
expect(
|
|
209
|
-
expect(
|
|
174
|
+
expect(getPrefixEl()).toBeDisabled();
|
|
175
|
+
expect(getInputEl()).toBeDisabled();
|
|
210
176
|
});
|
|
211
177
|
});
|
|
212
178
|
|
|
@@ -214,13 +180,13 @@ describe('PhoneNumberInput', () => {
|
|
|
214
180
|
it('should use the provided placeholder', () => {
|
|
215
181
|
const placeholder = 'custom placeholder';
|
|
216
182
|
customRender({ placeholder });
|
|
217
|
-
expect(
|
|
183
|
+
expect(getInputEl()).toHaveAttribute('placeholder', placeholder);
|
|
218
184
|
});
|
|
219
185
|
|
|
220
186
|
it('should use the provided searchPlaceholder', async () => {
|
|
221
187
|
const searchPlaceholder = 'search placeholder';
|
|
222
188
|
customRender({ searchPlaceholder });
|
|
223
|
-
await userEvent.click(
|
|
189
|
+
await userEvent.click(getPrefixEl());
|
|
224
190
|
expect(screen.getByRole('combobox', { name: searchPlaceholder })).toBeInTheDocument();
|
|
225
191
|
});
|
|
226
192
|
});
|
|
@@ -229,7 +195,7 @@ describe('PhoneNumberInput', () => {
|
|
|
229
195
|
describe('and a value', () => {
|
|
230
196
|
it('should use the prefix of the supplied value', () => {
|
|
231
197
|
customRender({ initialValue: '+12345678' }, 'es');
|
|
232
|
-
expect(
|
|
198
|
+
expect(getPrefixEl()).toHaveTextContent('+1');
|
|
233
199
|
});
|
|
234
200
|
});
|
|
235
201
|
|
|
@@ -237,14 +203,14 @@ describe('PhoneNumberInput', () => {
|
|
|
237
203
|
describe('and no country code', () => {
|
|
238
204
|
it('should default the prefix to the local country', () => {
|
|
239
205
|
customRender(undefined, 'es');
|
|
240
|
-
expect(
|
|
206
|
+
expect(getPrefixEl()).toHaveTextContent('+34');
|
|
241
207
|
});
|
|
242
208
|
});
|
|
243
209
|
|
|
244
210
|
describe('and country code', () => {
|
|
245
211
|
it('should override locale prefix with country specific prefix', () => {
|
|
246
212
|
customRender({ countryCode: 'US' }, 'es');
|
|
247
|
-
expect(
|
|
213
|
+
expect(getPrefixEl()).toHaveTextContent('+1');
|
|
248
214
|
});
|
|
249
215
|
});
|
|
250
216
|
});
|
|
@@ -254,7 +220,7 @@ describe('PhoneNumberInput', () => {
|
|
|
254
220
|
describe('valid number', () => {
|
|
255
221
|
it('should trigger onChange handler', async () => {
|
|
256
222
|
customRender();
|
|
257
|
-
await userEvent.type(
|
|
223
|
+
await userEvent.type(getInputEl(), '123');
|
|
258
224
|
expect(props.onChange).toHaveBeenCalledWith('+44123', '+44');
|
|
259
225
|
});
|
|
260
226
|
});
|
|
@@ -262,7 +228,7 @@ describe('PhoneNumberInput', () => {
|
|
|
262
228
|
describe('invalid number', () => {
|
|
263
229
|
it('should trigger onChange with null value', async () => {
|
|
264
230
|
customRender({ initialValue: '+1234' });
|
|
265
|
-
await userEvent.type(
|
|
231
|
+
await userEvent.type(getInputEl(), '{Backspace}{Backspace}{Backspace}1');
|
|
266
232
|
expect(props.onChange).toHaveBeenCalledWith(null, '+1');
|
|
267
233
|
});
|
|
268
234
|
});
|
|
@@ -270,7 +236,7 @@ describe('PhoneNumberInput', () => {
|
|
|
270
236
|
describe('when user insert invalid character', () => {
|
|
271
237
|
it('should strip them', async () => {
|
|
272
238
|
customRender({ initialValue: '+12345678' });
|
|
273
|
-
await userEvent.type(
|
|
239
|
+
await userEvent.type(getInputEl(), '123--');
|
|
274
240
|
expect(props.onChange).toHaveBeenCalledWith('+12345678123', '+1');
|
|
275
241
|
});
|
|
276
242
|
});
|
|
@@ -278,8 +244,8 @@ describe('PhoneNumberInput', () => {
|
|
|
278
244
|
describe('overlapping prefix and suffix numbers', () => {
|
|
279
245
|
it("shouldn't change the prefix number on matching suffix input", async () => {
|
|
280
246
|
customRender({ countryCode: 'eg' });
|
|
281
|
-
await userEvent.type(
|
|
282
|
-
expect(
|
|
247
|
+
await userEvent.type(getInputEl(), '1111111');
|
|
248
|
+
expect(getInputEl()).toHaveValue('1111111');
|
|
283
249
|
expect(props.onChange).toHaveBeenCalledWith('+201111111', '+20');
|
|
284
250
|
});
|
|
285
251
|
});
|
|
@@ -288,7 +254,7 @@ describe('PhoneNumberInput', () => {
|
|
|
288
254
|
describe('when selectProps is supplied', () => {
|
|
289
255
|
it('renders Select component with expected props', () => {
|
|
290
256
|
customRender({ selectProps: { className: 'custom-class' } });
|
|
291
|
-
expect(
|
|
257
|
+
expect(getPrefixEl().parentElement).toHaveClass('custom-class');
|
|
292
258
|
});
|
|
293
259
|
});
|
|
294
260
|
|
|
@@ -4,6 +4,7 @@ import { useIntl } from 'react-intl';
|
|
|
4
4
|
import { Size, SizeLarge, SizeMedium, SizeSmall } from '../common';
|
|
5
5
|
import { useInputAttributes } from '../inputs/contexts';
|
|
6
6
|
import { SelectInput, SelectInputOptionContent, SelectInputProps } from '../inputs/SelectInput';
|
|
7
|
+
|
|
7
8
|
import messages from './PhoneNumberInput.messages';
|
|
8
9
|
import countries from './data/countries';
|
|
9
10
|
import {
|
|
@@ -63,25 +64,6 @@ const PhoneNumberInput = ({
|
|
|
63
64
|
|
|
64
65
|
const { locale, formatMessage } = useIntl();
|
|
65
66
|
|
|
66
|
-
const createId = (customID: string | undefined, backup: string): string => {
|
|
67
|
-
if (customID) {
|
|
68
|
-
return customID + (backup ? `-${backup}` : '');
|
|
69
|
-
}
|
|
70
|
-
const random = Math.random().toString(36).slice(2, 8);
|
|
71
|
-
return `${backup}-${random}`;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const ids = {
|
|
75
|
-
countryCode: {
|
|
76
|
-
label: createId(id, 'country-code-label'),
|
|
77
|
-
select: createId(id, 'country-code-select'),
|
|
78
|
-
},
|
|
79
|
-
phoneNumber: {
|
|
80
|
-
label: createId(id, 'phone-number-label'),
|
|
81
|
-
input: createId(id, id ? '' : 'phone-number-input'),
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
|
|
85
67
|
const [internalValue, setInternalValue] = useState<PhoneNumber>(() => {
|
|
86
68
|
const cleanValue = initialValue ? cleanNumber(initialValue) : null;
|
|
87
69
|
|
|
@@ -169,9 +151,6 @@ const PhoneNumberInput = ({
|
|
|
169
151
|
aria-labelledby={ariaLabelledBy}
|
|
170
152
|
className="tw-telephone"
|
|
171
153
|
>
|
|
172
|
-
<label className="sr-only" id={ids.countryCode.label}>
|
|
173
|
-
{formatMessage(messages.countryCodeLabel)}
|
|
174
|
-
</label>
|
|
175
154
|
<div className="tw-telephone__country-select">
|
|
176
155
|
<SelectInput
|
|
177
156
|
placeholder={formatMessage(messages.selectInputPlaceholder)}
|
|
@@ -202,13 +181,6 @@ const PhoneNumberInput = ({
|
|
|
202
181
|
filterPlaceholder={searchPlaceholder}
|
|
203
182
|
disabled={disabled}
|
|
204
183
|
size={size}
|
|
205
|
-
id={ids.countryCode.select}
|
|
206
|
-
UNSAFE_triggerButtonProps={{
|
|
207
|
-
id: ids.countryCode.select,
|
|
208
|
-
'aria-labelledby': ids.countryCode.label,
|
|
209
|
-
'aria-describedby': undefined,
|
|
210
|
-
'aria-invalid': undefined,
|
|
211
|
-
}}
|
|
212
184
|
onChange={(prefix) => {
|
|
213
185
|
const country = prefix != null ? findCountryByPrefix(prefix) : null;
|
|
214
186
|
setInternalValue((prev) => ({ ...prev, prefix, format: country?.phoneFormat }));
|
|
@@ -221,13 +193,10 @@ const PhoneNumberInput = ({
|
|
|
221
193
|
{...selectProps}
|
|
222
194
|
/>
|
|
223
195
|
</div>
|
|
224
|
-
<label className="sr-only" id={ids.phoneNumber.label} htmlFor={ids.phoneNumber.input}>
|
|
225
|
-
{formatMessage(messages.phoneNumberLabel)}
|
|
226
|
-
</label>
|
|
227
196
|
<div className="tw-telephone__number-input">
|
|
228
197
|
<div className={`input-group input-group-${size}`}>
|
|
229
198
|
<Input
|
|
230
|
-
id={
|
|
199
|
+
id={id}
|
|
231
200
|
autoComplete="tel-national"
|
|
232
201
|
name="phoneNumber"
|
|
233
202
|
inputMode="numeric"
|
|
@@ -235,7 +204,6 @@ const PhoneNumberInput = ({
|
|
|
235
204
|
disabled={disabled}
|
|
236
205
|
required={required}
|
|
237
206
|
placeholder={placeholder}
|
|
238
|
-
aria-labelledby={ids.phoneNumber.label}
|
|
239
207
|
onChange={onSuffixChange}
|
|
240
208
|
onPaste={onPaste}
|
|
241
209
|
onFocus={onFocus}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import util from 'node:util';
|
|
2
2
|
import '@testing-library/jest-dom';
|
|
3
3
|
|
|
4
|
-
import Adapter from '@cfaester/enzyme-adapter-react-18';
|
|
5
|
-
import Enzyme from 'enzyme';
|
|
6
4
|
import fetchMock from 'jest-fetch-mock';
|
|
7
5
|
|
|
8
6
|
global.fetch = fetchMock as unknown as typeof global.fetch;
|
|
9
7
|
|
|
10
|
-
Enzyme.configure({ adapter: new Adapter() });
|
|
11
|
-
|
|
12
8
|
global.requestAnimationFrame = (callback: (time: number) => void): number => {
|
|
13
9
|
callback(performance.now());
|
|
14
10
|
return 0;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Field } from '../field/Field';
|
|
2
|
+
import { mockMatchMedia, render, screen, fireEvent } from '../test-utils';
|
|
3
|
+
import { wait } from '../test-utils/wait';
|
|
4
|
+
import Typeahead from './Typeahead';
|
|
5
|
+
|
|
6
|
+
mockMatchMedia();
|
|
7
|
+
|
|
8
|
+
describe('Typeahead', () => {
|
|
9
|
+
it('supports `Field` for labeling', () => {
|
|
10
|
+
render(
|
|
11
|
+
<Field id="test" label="Tags">
|
|
12
|
+
<Typeahead id="test" name="test" options={[{ label: 'Test' }]} onChange={() => {}} />
|
|
13
|
+
</Field>,
|
|
14
|
+
);
|
|
15
|
+
expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Tags/);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('when no options are provided', () => {
|
|
19
|
+
it('does not render a dropdown when no options and no footer are provided', () => {
|
|
20
|
+
render(
|
|
21
|
+
<Field id="test" label="Tags">
|
|
22
|
+
<Typeahead id="test" name="test" options={[]} onChange={() => {}} />
|
|
23
|
+
</Field>,
|
|
24
|
+
);
|
|
25
|
+
expect(screen.queryByRole('menu')).not.toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
it('does render a dropdown when only a footer is provided', () => {
|
|
28
|
+
render(
|
|
29
|
+
<Field id="test" label="Tags">
|
|
30
|
+
<Typeahead id="test" name="test" options={[]} footer={<p>hello</p>} onChange={() => {}} />
|
|
31
|
+
</Field>,
|
|
32
|
+
);
|
|
33
|
+
expect(screen.getByRole('menu')).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('renders input with placeholder', () => {
|
|
38
|
+
render(
|
|
39
|
+
<Typeahead id="test" name="test" options={[]} placeholder="Type here" onChange={() => {}} />,
|
|
40
|
+
);
|
|
41
|
+
expect(screen.getByPlaceholderText('Type here')).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('renders chips when multiple is true and selected has items', () => {
|
|
45
|
+
const initialValue = [{ label: 'Chip 1' }, { label: 'Chip 2' }];
|
|
46
|
+
render(
|
|
47
|
+
<Typeahead
|
|
48
|
+
id="test"
|
|
49
|
+
name="test"
|
|
50
|
+
options={[]}
|
|
51
|
+
multiple
|
|
52
|
+
initialValue={initialValue}
|
|
53
|
+
onChange={() => {}}
|
|
54
|
+
/>,
|
|
55
|
+
);
|
|
56
|
+
expect(screen.getByText('Chip 1')).toBeInTheDocument();
|
|
57
|
+
expect(screen.getByText('Chip 2')).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('calls onChange when selecting an option', () => {
|
|
61
|
+
const onChange = jest.fn();
|
|
62
|
+
render(
|
|
63
|
+
<Typeahead
|
|
64
|
+
id="test"
|
|
65
|
+
name="test"
|
|
66
|
+
options={[{ label: 'Option 1' }, { label: 'Option 2' }]}
|
|
67
|
+
minQueryLength={0}
|
|
68
|
+
onChange={onChange}
|
|
69
|
+
/>,
|
|
70
|
+
);
|
|
71
|
+
const input = screen.getByRole('combobox');
|
|
72
|
+
fireEvent.change(input, { target: { value: 'Option 1' } });
|
|
73
|
+
fireEvent.click(screen.getByText('Option 1'));
|
|
74
|
+
expect(onChange).toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('shows clear button when there is a value', () => {
|
|
78
|
+
render(
|
|
79
|
+
<Typeahead
|
|
80
|
+
id="test"
|
|
81
|
+
name="test"
|
|
82
|
+
options={[]}
|
|
83
|
+
initialValue={[{ label: 'Chip' }]}
|
|
84
|
+
onChange={() => {}}
|
|
85
|
+
/>,
|
|
86
|
+
);
|
|
87
|
+
expect(screen.getByRole('button', { name: /clear/i })).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('clears value when clear button is clicked', () => {
|
|
91
|
+
const onChange = jest.fn();
|
|
92
|
+
render(
|
|
93
|
+
<Typeahead
|
|
94
|
+
id="test"
|
|
95
|
+
name="test"
|
|
96
|
+
options={[]}
|
|
97
|
+
initialValue={[{ label: 'Chip' }]}
|
|
98
|
+
onChange={onChange}
|
|
99
|
+
/>,
|
|
100
|
+
);
|
|
101
|
+
fireEvent.click(screen.getByRole('button', { name: /clear/i }));
|
|
102
|
+
expect(onChange).toHaveBeenCalledWith([]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('shows InlineAlert when alert prop is provided', () => {
|
|
106
|
+
render(
|
|
107
|
+
<Typeahead
|
|
108
|
+
id="test"
|
|
109
|
+
name="test"
|
|
110
|
+
options={[]}
|
|
111
|
+
alert={{ message: 'Something went wrong', type: 'error' }}
|
|
112
|
+
onChange={() => {}}
|
|
113
|
+
/>,
|
|
114
|
+
);
|
|
115
|
+
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('calls onFocus when input is focused', () => {
|
|
119
|
+
const onFocus = jest.fn();
|
|
120
|
+
render(<Typeahead id="test" name="test" options={[]} onChange={() => {}} onFocus={onFocus} />);
|
|
121
|
+
fireEvent.focus(screen.getByRole('combobox'));
|
|
122
|
+
expect(onFocus).toHaveBeenCalled();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('calls onInputChange when input value changes', () => {
|
|
126
|
+
const onInputChange = jest.fn();
|
|
127
|
+
render(
|
|
128
|
+
<Typeahead
|
|
129
|
+
id="test"
|
|
130
|
+
name="test"
|
|
131
|
+
options={[]}
|
|
132
|
+
minQueryLength={0}
|
|
133
|
+
onChange={() => {}}
|
|
134
|
+
onInputChange={onInputChange}
|
|
135
|
+
/>,
|
|
136
|
+
);
|
|
137
|
+
fireEvent.change(screen.getByRole('combobox'), { target: { value: 'abc' } });
|
|
138
|
+
expect(onInputChange).toHaveBeenCalledWith('abc');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('calls onSearch when input value changes', async () => {
|
|
142
|
+
const onSearch = jest.fn();
|
|
143
|
+
render(
|
|
144
|
+
<Typeahead
|
|
145
|
+
id="test"
|
|
146
|
+
name="test"
|
|
147
|
+
options={[]}
|
|
148
|
+
minQueryLength={0}
|
|
149
|
+
onChange={() => {}}
|
|
150
|
+
onSearch={onSearch}
|
|
151
|
+
/>,
|
|
152
|
+
);
|
|
153
|
+
fireEvent.change(screen.getByRole('combobox'), { target: { value: 'abc' } });
|
|
154
|
+
// wait for debounce
|
|
155
|
+
await wait(500);
|
|
156
|
+
expect(onSearch).toHaveBeenCalledWith('abc');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('adds a new chip when allowNew and multiple are true and separator is pasted', () => {
|
|
160
|
+
const onChange = jest.fn();
|
|
161
|
+
render(
|
|
162
|
+
<Typeahead
|
|
163
|
+
id="test"
|
|
164
|
+
name="test"
|
|
165
|
+
options={[]}
|
|
166
|
+
allowNew
|
|
167
|
+
multiple
|
|
168
|
+
chipSeparators={[',']}
|
|
169
|
+
onChange={onChange}
|
|
170
|
+
/>,
|
|
171
|
+
);
|
|
172
|
+
const input = screen.getByRole('combobox');
|
|
173
|
+
fireEvent.paste(input, {
|
|
174
|
+
clipboardData: {
|
|
175
|
+
getData: () => 'foo,bar',
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
expect(onChange).toHaveBeenCalledWith(
|
|
179
|
+
expect.arrayContaining([{ label: 'foo' }, { label: 'bar' }]),
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
});
|