@transferwise/components 46.17.3 → 46.19.0
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/index.esm.js +24 -29
- package/build/index.esm.js.map +1 -1
- package/build/index.js +24 -29
- package/build/index.js.map +1 -1
- package/build/main.css +4 -0
- package/build/styles/instructionsList/InstructionsList.css +4 -0
- package/build/styles/main.css +4 -0
- package/build/types/accordion/Accordion.d.ts +3 -7
- package/build/types/accordion/Accordion.d.ts.map +1 -1
- package/build/types/accordion/index.d.ts +1 -0
- package/build/types/accordion/index.d.ts.map +1 -1
- package/build/types/actionButton/ActionButton.d.ts +1 -1
- package/build/types/body/Body.d.ts +1 -1
- package/build/types/circularButton/CircularButton.d.ts +16 -20
- package/build/types/circularButton/CircularButton.d.ts.map +1 -1
- package/build/types/circularButton/index.d.ts +2 -1
- package/build/types/circularButton/index.d.ts.map +1 -1
- package/build/types/dateLookup/DateLookup.d.ts +1 -0
- package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
- package/build/types/index.d.ts +3 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts +2 -1
- package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
- package/build/types/radioGroup/RadioGroup.d.ts +2 -1
- package/build/types/radioGroup/RadioGroup.d.ts.map +1 -1
- package/build/types/radioGroup/index.d.ts +1 -1
- package/build/types/radioGroup/index.d.ts.map +1 -1
- package/build/types/summary/Summary.d.ts.map +1 -1
- package/build/types/typeahead/Typeahead.d.ts +3 -1
- package/build/types/typeahead/Typeahead.d.ts.map +1 -1
- package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts +1 -1
- package/package.json +1 -1
- package/src/accordion/Accordion.tsx +6 -7
- package/src/accordion/index.ts +1 -0
- package/src/circularButton/{CircularButton.story.js → CircularButton.story.tsx} +2 -2
- package/src/circularButton/CircularButton.tsx +51 -0
- package/src/circularButton/index.ts +2 -0
- package/src/dateLookup/DateLookup.js +2 -0
- package/src/dateLookup/DateLookup.story.js +3 -0
- package/src/dateLookup/DateLookup.view.spec.js +5 -0
- package/src/index.ts +3 -1
- package/src/instructionsList/InstructionsList.css +4 -0
- package/src/instructionsList/InstructionsList.less +5 -0
- package/src/instructionsList/InstructionsList.tsx +3 -3
- package/src/main.css +4 -0
- package/src/phoneNumberInput/PhoneNumberInput.rtl.spec.tsx +22 -0
- package/src/phoneNumberInput/PhoneNumberInput.tsx +3 -1
- package/src/radioGroup/RadioGroup.tsx +6 -1
- package/src/radioGroup/index.ts +1 -1
- package/src/summary/Summary.tsx +7 -1
- package/src/typeahead/Typeahead.spec.js +9 -0
- package/src/typeahead/Typeahead.story.tsx +109 -0
- package/src/typeahead/Typeahead.tsx +13 -4
- package/src/typeahead/typeaheadInput/TypeaheadInput.tsx +3 -3
- package/src/circularButton/CircularButton.js +0 -57
- package/src/circularButton/index.js +0 -1
- /package/src/circularButton/{CircularButton.spec.js → CircularButton.spec.tsx} +0 -0
- /package/src/circularButton/__snapshots__/{CircularButton.spec.js.snap → CircularButton.spec.tsx.snap} +0 -0
|
@@ -3,9 +3,14 @@ import { useState } from 'react';
|
|
|
3
3
|
import Radio from '../radio';
|
|
4
4
|
import { RadioProps } from '../radio/Radio';
|
|
5
5
|
|
|
6
|
+
export type RadioGroupRadio<T extends string | number = string> = Omit<
|
|
7
|
+
RadioProps<T>,
|
|
8
|
+
'name' | 'checked' | 'onChange' | 'className'
|
|
9
|
+
>;
|
|
10
|
+
|
|
6
11
|
export interface RadioGroupProps<T extends string | number = string> {
|
|
7
12
|
name: string;
|
|
8
|
-
radios: readonly
|
|
13
|
+
radios: readonly RadioGroupRadio<T>[];
|
|
9
14
|
selectedValue?: T; // TODO: `NoInfer<T>` from TypeScript 5.4
|
|
10
15
|
onChange: NonNullable<RadioProps<T>['onChange']>;
|
|
11
16
|
}
|
package/src/radioGroup/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default } from './RadioGroup';
|
|
2
|
-
export type { RadioGroupProps } from './RadioGroup';
|
|
2
|
+
export type { RadioGroupProps, RadioGroupRadio } from './RadioGroup';
|
package/src/summary/Summary.tsx
CHANGED
|
@@ -137,7 +137,13 @@ const Summary = ({
|
|
|
137
137
|
</div>
|
|
138
138
|
<div className="np-summary__body m-l-2">
|
|
139
139
|
<div className="np-summary__title d-flex">
|
|
140
|
-
<Body
|
|
140
|
+
<Body
|
|
141
|
+
as="span"
|
|
142
|
+
role="heading"
|
|
143
|
+
aria-level={4}
|
|
144
|
+
type={Typography.BODY_LARGE_BOLD}
|
|
145
|
+
className="text-primary m-b-1"
|
|
146
|
+
>
|
|
141
147
|
{title}
|
|
142
148
|
</Body>
|
|
143
149
|
{info && (
|
|
@@ -370,5 +370,14 @@ describe('Typeahead', () => {
|
|
|
370
370
|
input().simulate('change', { target: { value: 'test' } });
|
|
371
371
|
expect(menu().is('.open')).toBe(true);
|
|
372
372
|
});
|
|
373
|
+
|
|
374
|
+
it('sets aria-expanded to true when options are shown', () => {
|
|
375
|
+
expect(input().prop('aria-expanded')).toBe(false);
|
|
376
|
+
// we don't want aria-expanded to be true on focus or before 3 characters are entered (that's when the menu is shown)
|
|
377
|
+
input().simulate('change', { target: { value: 'aa' } });
|
|
378
|
+
expect(input().prop('aria-expanded')).toBe(false);
|
|
379
|
+
input().simulate('change', { target: { value: 'aaa' } });
|
|
380
|
+
expect(input().prop('aria-expanded')).toBe(true);
|
|
381
|
+
});
|
|
373
382
|
});
|
|
374
383
|
});
|
|
@@ -5,6 +5,7 @@ import { Search as SearchIcon } from '@transferwise/icons';
|
|
|
5
5
|
import { useState } from 'react';
|
|
6
6
|
|
|
7
7
|
import { Sentiment } from '../common';
|
|
8
|
+
import { Input } from '../inputs/Input';
|
|
8
9
|
|
|
9
10
|
import Typeahead, { type TypeaheadOption } from './Typeahead';
|
|
10
11
|
|
|
@@ -120,3 +121,111 @@ Basic.play = async ({ canvasElement }: StoryContext) => {
|
|
|
120
121
|
const canvas = within(canvasElement);
|
|
121
122
|
await userEvent.type(canvas.getByRole('combobox'), 'abc{ArrowDown}');
|
|
122
123
|
};
|
|
124
|
+
|
|
125
|
+
type Result =
|
|
126
|
+
| {
|
|
127
|
+
type: 'action';
|
|
128
|
+
value: string;
|
|
129
|
+
}
|
|
130
|
+
| {
|
|
131
|
+
type: 'search';
|
|
132
|
+
value: string;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
type SearchState = 'success' | 'idle' | 'error' | 'loading';
|
|
136
|
+
|
|
137
|
+
export const Search = () => {
|
|
138
|
+
const [results, setResults] = useState<Result[]>([]);
|
|
139
|
+
const [state, setState] = useState<SearchState>('idle');
|
|
140
|
+
const [filledValue, setFilledValue] = useState<string | null>(null);
|
|
141
|
+
|
|
142
|
+
const onChange = (query: string) => {
|
|
143
|
+
if (query === 'loading') {
|
|
144
|
+
setState('loading');
|
|
145
|
+
setResults([]);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (query === 'error') {
|
|
149
|
+
setState('error');
|
|
150
|
+
setResults([]);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (query === 'nothing') {
|
|
154
|
+
setState('success');
|
|
155
|
+
setResults([]);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
setState('success');
|
|
160
|
+
setResults(getResults(query));
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const onResultSelected = (option: Result) => {
|
|
164
|
+
if (option.type === 'search') {
|
|
165
|
+
setResults([
|
|
166
|
+
{ type: 'action', value: `${option.value} Result #1` },
|
|
167
|
+
{ type: 'action', value: `${option.value} Result #2` },
|
|
168
|
+
{ type: 'action', value: `${option.value} Result #3` },
|
|
169
|
+
]);
|
|
170
|
+
}
|
|
171
|
+
if (option.type === 'action') {
|
|
172
|
+
setFilledValue(option.value);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const getResults = (query: string): Result[] => {
|
|
177
|
+
return [
|
|
178
|
+
{ type: 'action', value: `${query} Result #1` },
|
|
179
|
+
{ type: 'action', value: `${query} Result #2` },
|
|
180
|
+
{ type: 'action', value: `${query} Result #3` },
|
|
181
|
+
{ type: 'search', value: `Search for more: '${query}'` },
|
|
182
|
+
];
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<>
|
|
187
|
+
<Typeahead<Result>
|
|
188
|
+
id="typeahead-input-id"
|
|
189
|
+
name="typeahead-input-name"
|
|
190
|
+
size="md"
|
|
191
|
+
maxHeight={100}
|
|
192
|
+
footer={<SearchFooter options={results} state={state} />}
|
|
193
|
+
multiple={false}
|
|
194
|
+
clearable={false}
|
|
195
|
+
addon={<SearchIcon />}
|
|
196
|
+
options={results.map((option) => ({
|
|
197
|
+
value: option,
|
|
198
|
+
label: option.value,
|
|
199
|
+
keepFocusOnSelect: option.type === 'search',
|
|
200
|
+
clearQueryOnSelect: option.type === 'action',
|
|
201
|
+
}))}
|
|
202
|
+
onChange={(values) => {
|
|
203
|
+
if (values.length > 0) {
|
|
204
|
+
const [updatedValue] = values;
|
|
205
|
+
if (updatedValue.value) {
|
|
206
|
+
onResultSelected(updatedValue.value);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}}
|
|
210
|
+
onInputChange={onChange}
|
|
211
|
+
/>
|
|
212
|
+
{filledValue != null ? <Input value={filledValue} /> : null}
|
|
213
|
+
</>
|
|
214
|
+
);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
function SearchFooter({ options, state }: { options: Result[]; state: SearchState }) {
|
|
218
|
+
if (state === 'loading') {
|
|
219
|
+
return <p className="m-y-2 m-x-2">Loading...</p>;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (state === 'success' && options.length === 0) {
|
|
223
|
+
return <p className="m-y-2 m-x-2">No results found</p>;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (state === 'error' && options.length === 0) {
|
|
227
|
+
return <div className="m-y-2 m-x-2">Something went wrong</div>;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
@@ -30,6 +30,8 @@ export type TypeaheadOption<T = string> = {
|
|
|
30
30
|
note?: string;
|
|
31
31
|
secondary?: string;
|
|
32
32
|
value?: T;
|
|
33
|
+
clearQueryOnSelect?: boolean;
|
|
34
|
+
keepFocusOnSelect?: boolean;
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
export interface TypeaheadProps<T> {
|
|
@@ -250,7 +252,15 @@ export default class Typeahead<T> extends Component<TypeaheadProps<T>, Typeahead
|
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
this.updateSelectedValue(selected);
|
|
253
|
-
|
|
255
|
+
|
|
256
|
+
if (!item.keepFocusOnSelect) {
|
|
257
|
+
this.hideMenu();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (item.clearQueryOnSelect) {
|
|
261
|
+
query = '';
|
|
262
|
+
}
|
|
263
|
+
|
|
254
264
|
this.setState({
|
|
255
265
|
query,
|
|
256
266
|
});
|
|
@@ -474,7 +484,7 @@ export default class Typeahead<T> extends Component<TypeaheadProps<T>, Typeahead
|
|
|
474
484
|
{...{
|
|
475
485
|
autoFocus,
|
|
476
486
|
multiple,
|
|
477
|
-
|
|
487
|
+
dropdownOpen,
|
|
478
488
|
placeholder,
|
|
479
489
|
selected,
|
|
480
490
|
maxHeight,
|
|
@@ -499,8 +509,7 @@ export default class Typeahead<T> extends Component<TypeaheadProps<T>, Typeahead
|
|
|
499
509
|
</div>
|
|
500
510
|
)}
|
|
501
511
|
</div>
|
|
502
|
-
{displayAlert
|
|
503
|
-
{menu}
|
|
512
|
+
{displayAlert ? <InlineAlert type={alert.type}>{alert.message}</InlineAlert> : menu}
|
|
504
513
|
</div>
|
|
505
514
|
</div>
|
|
506
515
|
);
|
|
@@ -13,7 +13,7 @@ export type TypeaheadInputProps<T> = {
|
|
|
13
13
|
typeaheadId: string;
|
|
14
14
|
value: string;
|
|
15
15
|
selected: readonly TypeaheadOption<T>[];
|
|
16
|
-
|
|
16
|
+
dropdownOpen?: boolean;
|
|
17
17
|
autoComplete: string;
|
|
18
18
|
onChange: React.ChangeEventHandler<HTMLInputElement>;
|
|
19
19
|
onKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
|
|
@@ -67,7 +67,7 @@ export default class TypeaheadInput<T> extends Component<
|
|
|
67
67
|
autoFocus,
|
|
68
68
|
multiple,
|
|
69
69
|
name,
|
|
70
|
-
|
|
70
|
+
dropdownOpen,
|
|
71
71
|
placeholder,
|
|
72
72
|
selected,
|
|
73
73
|
value,
|
|
@@ -89,7 +89,7 @@ export default class TypeaheadInput<T> extends Component<
|
|
|
89
89
|
autoFocus={autoFocus}
|
|
90
90
|
placeholder={hasPlaceholder ? placeholder : ''}
|
|
91
91
|
aria-autocomplete="list"
|
|
92
|
-
aria-expanded={
|
|
92
|
+
aria-expanded={dropdownOpen}
|
|
93
93
|
aria-haspopup="listbox"
|
|
94
94
|
aria-controls={`menu-${typeaheadId}`}
|
|
95
95
|
autoComplete={autoComplete}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import classNames from 'classnames';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
import { cloneElement } from 'react';
|
|
4
|
-
|
|
5
|
-
import Body from '../body/Body';
|
|
6
|
-
import { typeClassMap, priorityClassMap } from '../button/classMap';
|
|
7
|
-
import { ControlType, Priority } from '../common';
|
|
8
|
-
import { Typography } from '../common';
|
|
9
|
-
|
|
10
|
-
const CircularButton = ({ className, children, disabled, icon, priority, type, ...rest }) => {
|
|
11
|
-
const classes = classNames('btn np-btn', typeClassMap[type], priorityClassMap[priority]);
|
|
12
|
-
|
|
13
|
-
const iconElement = icon.props.size !== 24 ? cloneElement(icon, { size: 24 }) : icon;
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<label
|
|
17
|
-
className={classNames(
|
|
18
|
-
'np-circular-btn',
|
|
19
|
-
priority,
|
|
20
|
-
type,
|
|
21
|
-
disabled ? 'disabled' : '',
|
|
22
|
-
className,
|
|
23
|
-
)}
|
|
24
|
-
>
|
|
25
|
-
<input
|
|
26
|
-
type="button"
|
|
27
|
-
aria-label={children}
|
|
28
|
-
className={classes}
|
|
29
|
-
disabled={disabled}
|
|
30
|
-
{...rest}
|
|
31
|
-
/>
|
|
32
|
-
{iconElement}
|
|
33
|
-
<Body as="span" className="np-circular-btn__label" type={Typography.BODY_DEFAULT_BOLD}>
|
|
34
|
-
{children}
|
|
35
|
-
</Body>
|
|
36
|
-
</label>
|
|
37
|
-
);
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
CircularButton.propTypes = {
|
|
41
|
-
className: PropTypes.string,
|
|
42
|
-
children: PropTypes.string.isRequired,
|
|
43
|
-
disabled: PropTypes.bool,
|
|
44
|
-
icon: PropTypes.element.isRequired,
|
|
45
|
-
onClick: PropTypes.func,
|
|
46
|
-
priority: PropTypes.oneOf(['primary', 'secondary']),
|
|
47
|
-
type: PropTypes.oneOf(['accent', 'positive', 'negative']),
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
CircularButton.defaultProps = {
|
|
51
|
-
className: undefined,
|
|
52
|
-
disabled: false,
|
|
53
|
-
priority: Priority.PRIMARY,
|
|
54
|
-
type: ControlType.ACCENT,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export default CircularButton;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from './CircularButton';
|
|
File without changes
|
|
File without changes
|