@transferwise/components 46.8.0 → 46.10.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 +76 -127
- package/build/index.esm.js.map +1 -1
- package/build/index.js +76 -127
- package/build/index.js.map +1 -1
- package/build/types/checkboxOption/CheckboxOption.d.ts +2 -2
- package/build/types/checkboxOption/CheckboxOption.d.ts.map +1 -1
- package/build/types/common/index.d.ts +0 -1
- package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
- package/build/types/index.d.ts +2 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts +2 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
- package/build/types/select/Select.d.ts.map +1 -1
- package/build/types/snackbar/Snackbar.d.ts +30 -22
- package/build/types/snackbar/Snackbar.d.ts.map +1 -1
- package/build/types/snackbar/SnackbarContext.d.ts +7 -2
- package/build/types/snackbar/SnackbarContext.d.ts.map +1 -1
- package/build/types/snackbar/SnackbarProvider.d.ts +7 -12
- package/build/types/snackbar/SnackbarProvider.d.ts.map +1 -1
- package/build/types/snackbar/index.d.ts +2 -0
- package/build/types/snackbar/index.d.ts.map +1 -0
- package/build/types/snackbar/useSnackbar.d.ts +1 -1
- package/build/types/snackbar/useSnackbar.d.ts.map +1 -1
- package/build/types/switch/Switch.d.ts.map +1 -1
- package/build/types/tabs/Tabs.d.ts.map +1 -1
- package/build/types/typeahead/Typeahead.d.ts.map +1 -1
- package/build/types/withNextPortal/withNextPortal.d.ts +1 -1
- package/build/types/withNextPortal/withNextPortal.d.ts.map +1 -1
- package/package.json +16 -19
- package/src/button/Button.story.tsx +3 -3
- package/src/checkboxOption/CheckboxOption.tsx +2 -2
- package/src/common/fakeEvents.js +2 -2
- package/src/common/index.js +0 -1
- package/src/dateInput/DateInput.story.tsx +4 -3
- package/src/dateLookup/DateLookup.js +6 -7
- package/src/dateLookup/DateLookup.keyboardEvents.spec.js +24 -25
- package/src/dateLookup/DateLookup.story.js +4 -3
- package/src/dateLookup/dateTrigger/DateTrigger.spec.js +3 -3
- package/src/index.ts +2 -0
- package/src/info/Info.story.tsx +3 -3
- package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.js +2 -7
- package/src/inputs/SelectInput.spec.tsx +7 -0
- package/src/inputs/SelectInput.story.tsx +7 -7
- package/src/inputs/SelectInput.tsx +4 -0
- package/src/logo/Logo.js +4 -4
- package/src/moneyInput/MoneyInput.story.tsx +3 -3
- package/src/moneyInput/MoneyInput.tsx +14 -24
- package/src/select/Select.js +8 -9
- package/src/snackbar/{Snackbar.story.js → Snackbar.story.tsx} +4 -3
- package/src/snackbar/{Snackbar.js → Snackbar.tsx} +31 -32
- package/src/snackbar/SnackbarContext.ts +11 -0
- package/src/snackbar/SnackbarProvider.tsx +39 -0
- package/src/switch/Switch.spec.js +2 -3
- package/src/switch/Switch.tsx +1 -2
- package/src/switchOption/SwitchOption.spec.js +1 -4
- package/src/tabs/Tabs.js +1 -2
- package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.story.tsx +5 -4
- package/src/tile/Tile.js +2 -2
- package/src/tile/Tile.spec.js +5 -5
- package/src/tooltip/Tooltip.story.tsx +3 -3
- package/src/typeahead/Typeahead.js +5 -6
- package/src/typeahead/Typeahead.spec.js +3 -8
- package/src/typeahead/Typeahead.story.js +3 -4
- package/src/withNextPortal/withNextPortal.tsx +1 -1
- package/build/types/common/key.d.ts +0 -9
- package/build/types/common/key.d.ts.map +0 -1
- package/build/types/common/keyCodes.d.ts +0 -16
- package/build/types/common/keyCodes.d.ts.map +0 -1
- package/src/common/key.js +0 -8
- package/src/common/keyCodes.js +0 -19
- package/src/snackbar/SnackbarContext.js +0 -4
- package/src/snackbar/SnackbarProvider.js +0 -51
- /package/src/snackbar/{index.js → index.ts} +0 -0
- /package/src/snackbar/{useSnackbar.js → useSnackbar.ts} +0 -0
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { mount } from 'enzyme';
|
|
3
3
|
|
|
4
4
|
import { fakeKeyDownEventForKey } from '../common/fakeEvents';
|
|
5
|
-
import KEY_CODES from '../common/keyCodes';
|
|
6
5
|
import { mockMatchMedia } from '../test-utils';
|
|
7
6
|
|
|
8
7
|
import DateLookup from '.';
|
|
@@ -31,28 +30,28 @@ describe('DateLookup (keyboard events)', () => {
|
|
|
31
30
|
});
|
|
32
31
|
|
|
33
32
|
it('can be opened by LEFT arrow', () => {
|
|
34
|
-
pressKey(
|
|
33
|
+
pressKey('ArrowLeft');
|
|
35
34
|
expect(component.instance().state.open).toBe(true);
|
|
36
35
|
});
|
|
37
36
|
|
|
38
37
|
it('can be opened by UP arrow', () => {
|
|
39
|
-
pressKey(
|
|
38
|
+
pressKey('ArrowUp');
|
|
40
39
|
expect(component.instance().state.open).toBe(true);
|
|
41
40
|
});
|
|
42
41
|
|
|
43
42
|
it('can be opened by RIGHT arrow', () => {
|
|
44
|
-
pressKey(
|
|
43
|
+
pressKey('ArrowRight');
|
|
45
44
|
expect(component.instance().state.open).toBe(true);
|
|
46
45
|
});
|
|
47
46
|
|
|
48
47
|
it('can be opened by DOWN arrow', () => {
|
|
49
|
-
pressKey(
|
|
48
|
+
pressKey('ArrowDown');
|
|
50
49
|
expect(component.instance().state.open).toBe(true);
|
|
51
50
|
});
|
|
52
51
|
|
|
53
52
|
it('can be closed by pressing ESCAPE', () => {
|
|
54
53
|
component.setState({ open: true });
|
|
55
|
-
pressKey(
|
|
54
|
+
pressKey('Escape');
|
|
56
55
|
expect(component.instance().state.open).toBe(false);
|
|
57
56
|
});
|
|
58
57
|
|
|
@@ -62,33 +61,33 @@ describe('DateLookup (keyboard events)', () => {
|
|
|
62
61
|
});
|
|
63
62
|
|
|
64
63
|
it('moves 1 day back by pressing LEFT', () => {
|
|
65
|
-
pressKey(
|
|
64
|
+
pressKey('ArrowLeft');
|
|
66
65
|
onChangeCalledWith(new Date(2018, 11, 26));
|
|
67
66
|
});
|
|
68
67
|
|
|
69
68
|
it('moves 7 days back by pressing UP', () => {
|
|
70
|
-
pressKey(
|
|
69
|
+
pressKey('ArrowUp');
|
|
71
70
|
onChangeCalledWith(new Date(2018, 11, 20));
|
|
72
71
|
});
|
|
73
72
|
|
|
74
73
|
it('moves 1 day forward by pressing RIGHT', () => {
|
|
75
|
-
pressKey(
|
|
74
|
+
pressKey('ArrowRight');
|
|
76
75
|
onChangeCalledWith(new Date(2018, 11, 28));
|
|
77
76
|
});
|
|
78
77
|
|
|
79
78
|
it('moves 7 day forward by pressing DOWN', () => {
|
|
80
|
-
pressKey(
|
|
79
|
+
pressKey('ArrowDown');
|
|
81
80
|
onChangeCalledWith(new Date(2019, 0, 3));
|
|
82
81
|
});
|
|
83
82
|
|
|
84
83
|
it('resets to original date when escape key is pressed', () => {
|
|
85
|
-
pressKey(
|
|
86
|
-
pressKey(
|
|
84
|
+
pressKey('ArrowLeft');
|
|
85
|
+
pressKey('Escape');
|
|
87
86
|
onChangeCalledWith(date);
|
|
88
87
|
});
|
|
89
88
|
|
|
90
89
|
it('resets to original date when clicking outside modal', () => {
|
|
91
|
-
pressKey(
|
|
90
|
+
pressKey('ArrowLeft');
|
|
92
91
|
component.find('.dimmer').simulate('click');
|
|
93
92
|
onChangeCalledWith(date);
|
|
94
93
|
});
|
|
@@ -100,22 +99,22 @@ describe('DateLookup (keyboard events)', () => {
|
|
|
100
99
|
});
|
|
101
100
|
|
|
102
101
|
it('moves 1 month back by pressing LEFT', () => {
|
|
103
|
-
pressKey(
|
|
102
|
+
pressKey('ArrowLeft');
|
|
104
103
|
onChangeCalledWith(new Date(2018, 10, 27));
|
|
105
104
|
});
|
|
106
105
|
|
|
107
106
|
it('moves 4 months back by pressing UP', () => {
|
|
108
|
-
pressKey(
|
|
107
|
+
pressKey('ArrowUp');
|
|
109
108
|
onChangeCalledWith(new Date(2018, 7, 27));
|
|
110
109
|
});
|
|
111
110
|
|
|
112
111
|
it('moves 1 month forward by pressing RIGHT', () => {
|
|
113
|
-
pressKey(
|
|
112
|
+
pressKey('ArrowRight');
|
|
114
113
|
onChangeCalledWith(new Date(2019, 0, 27));
|
|
115
114
|
});
|
|
116
115
|
|
|
117
116
|
it('moves 4 months forward by pressing DOWN', () => {
|
|
118
|
-
pressKey(
|
|
117
|
+
pressKey('ArrowDown');
|
|
119
118
|
onChangeCalledWith(new Date(2019, 3, 27));
|
|
120
119
|
});
|
|
121
120
|
});
|
|
@@ -126,22 +125,22 @@ describe('DateLookup (keyboard events)', () => {
|
|
|
126
125
|
});
|
|
127
126
|
|
|
128
127
|
it('moves 1 year back by pressing LEFT', () => {
|
|
129
|
-
pressKey(
|
|
128
|
+
pressKey('ArrowLeft');
|
|
130
129
|
onChangeCalledWith(new Date(2017, 11, 27));
|
|
131
130
|
});
|
|
132
131
|
|
|
133
132
|
it('moves 4 years back by pressing UP', () => {
|
|
134
|
-
pressKey(
|
|
133
|
+
pressKey('ArrowUp');
|
|
135
134
|
onChangeCalledWith(new Date(2014, 11, 27));
|
|
136
135
|
});
|
|
137
136
|
|
|
138
137
|
it('moves 1 year forward by pressing RIGHT', () => {
|
|
139
|
-
pressKey(
|
|
138
|
+
pressKey('ArrowRight');
|
|
140
139
|
onChangeCalledWith(new Date(2019, 11, 27));
|
|
141
140
|
});
|
|
142
141
|
|
|
143
142
|
it('moves 4 year forward by pressing DOWN', () => {
|
|
144
|
-
pressKey(
|
|
143
|
+
pressKey('ArrowDown');
|
|
145
144
|
onChangeCalledWith(new Date(2022, 11, 27));
|
|
146
145
|
});
|
|
147
146
|
});
|
|
@@ -157,16 +156,16 @@ describe('DateLookup (keyboard events)', () => {
|
|
|
157
156
|
});
|
|
158
157
|
|
|
159
158
|
it('makes sure that date is >= min', () => {
|
|
160
|
-
pressKey(
|
|
159
|
+
pressKey('ArrowLeft');
|
|
161
160
|
onChangeCalledWith(new Date(2018, 11, 26));
|
|
162
|
-
pressKey(
|
|
161
|
+
pressKey('ArrowLeft');
|
|
163
162
|
onChangeCalledWith(new Date(2018, 11, 26));
|
|
164
163
|
});
|
|
165
164
|
|
|
166
165
|
it('makes sure that date is <= max', () => {
|
|
167
|
-
pressKey(
|
|
166
|
+
pressKey('ArrowRight');
|
|
168
167
|
onChangeCalledWith(new Date(2018, 11, 28));
|
|
169
|
-
pressKey(
|
|
168
|
+
pressKey('ArrowRight');
|
|
170
169
|
onChangeCalledWith(new Date(2018, 11, 28));
|
|
171
170
|
});
|
|
172
171
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { boolean, select, date, text } from '@storybook/addon-knobs';
|
|
2
|
+
import { userEvent, within } from '@storybook/test';
|
|
2
3
|
import { useState } from 'react';
|
|
3
4
|
|
|
4
5
|
import { Size } from '../common';
|
|
5
|
-
import {
|
|
6
|
+
import { storyConfig } from '../test-utils';
|
|
6
7
|
|
|
7
8
|
import DateLookup from './DateLookup';
|
|
8
9
|
|
|
@@ -48,8 +49,8 @@ export const Basic = () => {
|
|
|
48
49
|
Basic.play = async ({ canvasElement }) => {
|
|
49
50
|
// testing focus state on keyboard nav
|
|
50
51
|
const canvas = within(canvasElement);
|
|
51
|
-
userEvent.tab(canvas.getByRole('button'));
|
|
52
|
-
userEvent.keyboard('
|
|
52
|
+
await userEvent.tab(canvas.getByRole('button'));
|
|
53
|
+
await userEvent.keyboard(' ');
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
export const Basic400Zoom = storyConfig(
|
|
@@ -111,21 +111,21 @@ describe('DateTrigger', () => {
|
|
|
111
111
|
it('calls onClear when user press Space', () => {
|
|
112
112
|
const onClear = jest.fn();
|
|
113
113
|
component.setProps({ onClear });
|
|
114
|
-
clearButton().simulate('keypress', fakeKeyDownEventForKey(
|
|
114
|
+
clearButton().simulate('keypress', fakeKeyDownEventForKey(' '));
|
|
115
115
|
expect(onClear).toHaveBeenCalledTimes(1);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
118
|
it('calls onClear when user press Enter', () => {
|
|
119
119
|
const onClear = jest.fn();
|
|
120
120
|
component.setProps({ onClear });
|
|
121
|
-
clearButton().simulate('keypress', fakeKeyDownEventForKey(
|
|
121
|
+
clearButton().simulate('keypress', fakeKeyDownEventForKey('Enter'));
|
|
122
122
|
expect(onClear).toHaveBeenCalledTimes(1);
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
it(`doesn't call onClear when user press a random key`, () => {
|
|
126
126
|
const onClear = jest.fn();
|
|
127
127
|
component.setProps({ onClear });
|
|
128
|
-
clearButton().simulate('keypress', fakeKeyDownEventForKey(
|
|
128
|
+
clearButton().simulate('keypress', fakeKeyDownEventForKey('r'));
|
|
129
129
|
expect(onClear).not.toHaveBeenCalled();
|
|
130
130
|
});
|
|
131
131
|
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,8 @@ export type {
|
|
|
16
16
|
} from './inputs/SelectInput';
|
|
17
17
|
export type { TextAreaProps } from './inputs/TextArea';
|
|
18
18
|
export type { PhoneNumberInputProps } from './phoneNumberInput/PhoneNumberInput';
|
|
19
|
+
export type { SnackbarProps } from './snackbar/Snackbar';
|
|
20
|
+
export type { SnackbarContextType } from './snackbar/SnackbarContext';
|
|
19
21
|
export type { TextareaWithDisplayFormatProps } from './textareaWithDisplayFormat';
|
|
20
22
|
export type { UploadedFile, UploadError, UploadResponse } from './uploadInput/types';
|
|
21
23
|
export type { ModalProps } from './modal';
|
package/src/info/Info.story.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { userEvent, within } from '@storybook/
|
|
2
|
+
import { userEvent, within } from '@storybook/test';
|
|
3
3
|
|
|
4
4
|
import { lorem10, storyConfig } from '../test-utils';
|
|
5
5
|
|
|
@@ -35,9 +35,9 @@ export const OpenedPopover: Story = {
|
|
|
35
35
|
delay: 1000,
|
|
36
36
|
},
|
|
37
37
|
},
|
|
38
|
-
play: ({ canvasElement }) => {
|
|
38
|
+
play: async ({ canvasElement }) => {
|
|
39
39
|
const canvas = within(canvasElement);
|
|
40
|
-
userEvent.click(canvas.getByRole('button'));
|
|
40
|
+
await userEvent.click(canvas.getByRole('button'));
|
|
41
41
|
},
|
|
42
42
|
};
|
|
43
43
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { text } from '@storybook/addon-knobs';
|
|
2
|
-
|
|
3
|
-
import { within, userEvent } from '../test-utils';
|
|
2
|
+
import { userEvent, within } from '@storybook/test';
|
|
4
3
|
|
|
5
4
|
import InputWithDisplayFormat from '.';
|
|
6
5
|
|
|
@@ -86,9 +85,5 @@ SecurityPinPlay.args = {
|
|
|
86
85
|
|
|
87
86
|
SecurityPinPlay.play = async ({ canvasElement }) => {
|
|
88
87
|
const canvas = within(canvasElement);
|
|
89
|
-
|
|
90
|
-
while (i < 6) {
|
|
91
|
-
await userEvent.type(canvas.getByPlaceholderText('*-*-*-*-*-*'), `${i + 1}`, { delay: 5000 });
|
|
92
|
-
i++;
|
|
93
|
-
}
|
|
88
|
+
await userEvent.type(canvas.getByPlaceholderText('*-*-*-*-*-*'), '123456');
|
|
94
89
|
};
|
|
@@ -208,4 +208,11 @@ describe('SelectInput', () => {
|
|
|
208
208
|
|
|
209
209
|
expect(trigger).toHaveTextContent('USD, EUR');
|
|
210
210
|
});
|
|
211
|
+
|
|
212
|
+
it('supports custom `id` attribute', () => {
|
|
213
|
+
render(<SelectInput id="custom" items={[]} />);
|
|
214
|
+
|
|
215
|
+
const trigger = screen.getAllByRole('button')[0];
|
|
216
|
+
expect(trigger).toHaveAttribute('id', 'custom');
|
|
217
|
+
});
|
|
211
218
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { userEvent, within } from '@storybook/test';
|
|
2
3
|
import { Calendar, ChevronDown } from '@transferwise/icons';
|
|
3
4
|
import { Flag } from '@wise/art';
|
|
4
5
|
import classNames from 'classnames';
|
|
@@ -7,7 +8,6 @@ import { useState } from 'react';
|
|
|
7
8
|
import { getMonthNames } from '../common/dateUtils';
|
|
8
9
|
import Drawer from '../drawer';
|
|
9
10
|
import Modal from '../modal';
|
|
10
|
-
import { within, userEvent } from '../test-utils';
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
SelectInput,
|
|
@@ -131,9 +131,9 @@ export const Basic: StoryObj<{
|
|
|
131
131
|
action: 'cleared',
|
|
132
132
|
},
|
|
133
133
|
},
|
|
134
|
-
play: ({ canvasElement }) => {
|
|
134
|
+
play: async ({ canvasElement }) => {
|
|
135
135
|
const triggerButton = within(canvasElement).getByRole('button');
|
|
136
|
-
userEvent.click(triggerButton);
|
|
136
|
+
await userEvent.click(triggerButton);
|
|
137
137
|
},
|
|
138
138
|
};
|
|
139
139
|
|
|
@@ -184,9 +184,9 @@ export const Months: StoryObj<{
|
|
|
184
184
|
action: 'cleared',
|
|
185
185
|
},
|
|
186
186
|
},
|
|
187
|
-
play: ({ canvasElement }) => {
|
|
187
|
+
play: async ({ canvasElement }) => {
|
|
188
188
|
const triggerButton = within(canvasElement).getByText('January');
|
|
189
|
-
userEvent.click(triggerButton);
|
|
189
|
+
await userEvent.click(triggerButton);
|
|
190
190
|
},
|
|
191
191
|
};
|
|
192
192
|
|
|
@@ -402,9 +402,9 @@ export const CustomTrigger: StoryObj = {
|
|
|
402
402
|
</div>
|
|
403
403
|
);
|
|
404
404
|
},
|
|
405
|
-
play: ({ canvasElement }) => {
|
|
405
|
+
play: async ({ canvasElement }) => {
|
|
406
406
|
const triggerButton = within(canvasElement).getByRole('button');
|
|
407
|
-
userEvent.click(triggerButton);
|
|
407
|
+
await userEvent.click(triggerButton);
|
|
408
408
|
},
|
|
409
409
|
};
|
|
410
410
|
|
|
@@ -41,6 +41,7 @@ function inferSearchableStrings(value: unknown) {
|
|
|
41
41
|
|
|
42
42
|
const SelectInputTriggerButtonPropsContext = createContext<{
|
|
43
43
|
ref?: React.ForwardedRef<HTMLButtonElement>;
|
|
44
|
+
id?: string;
|
|
44
45
|
onClick?: (event: React.MouseEvent) => void;
|
|
45
46
|
onKeyDown?: (event: React.KeyboardEvent) => void;
|
|
46
47
|
[key: string]: unknown;
|
|
@@ -125,6 +126,7 @@ function filterSelectInputItems<T>(items: readonly SelectInputItem<T>[], needle:
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
export interface SelectInputProps<T = string, M extends boolean = false> {
|
|
129
|
+
id?: string;
|
|
128
130
|
name?: string;
|
|
129
131
|
multiple?: M;
|
|
130
132
|
placeholder?: string;
|
|
@@ -218,6 +220,7 @@ function SelectInputClearButton({ className, onClick }: SelectInputClearButtonPr
|
|
|
218
220
|
const noop = () => {};
|
|
219
221
|
|
|
220
222
|
export function SelectInput<T = string, M extends boolean = false>({
|
|
223
|
+
id,
|
|
221
224
|
name,
|
|
222
225
|
multiple,
|
|
223
226
|
placeholder,
|
|
@@ -288,6 +291,7 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
288
291
|
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
289
292
|
value={{
|
|
290
293
|
ref: mergeRefs([ref, triggerRef]),
|
|
294
|
+
id,
|
|
291
295
|
...mergeProps(
|
|
292
296
|
{
|
|
293
297
|
onClick: () => {
|
package/src/logo/Logo.js
CHANGED
|
@@ -2,10 +2,10 @@ import classNames from 'classnames';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
|
|
4
4
|
import { LogoType } from './logoTypes';
|
|
5
|
-
import { LogoFlagInverse } from './svg/flag-inverse.svg';
|
|
6
|
-
import { LogoFlag } from './svg/flag.svg';
|
|
7
|
-
import { LogoWiseInverse } from './svg/logo-inverse.svg';
|
|
8
|
-
import { LogoWise } from './svg/logo.svg';
|
|
5
|
+
import { ReactComponent as LogoFlagInverse } from './svg/flag-inverse.svg';
|
|
6
|
+
import { ReactComponent as LogoFlag } from './svg/flag.svg';
|
|
7
|
+
import { ReactComponent as LogoWiseInverse } from './svg/logo-inverse.svg';
|
|
8
|
+
import { ReactComponent as LogoWise } from './svg/logo.svg';
|
|
9
9
|
|
|
10
10
|
const svgPaths = {
|
|
11
11
|
WISE: LogoWise,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { within, userEvent } from '@storybook/
|
|
2
|
+
import { within, userEvent } from '@storybook/test';
|
|
3
3
|
import { Lock } from '@transferwise/icons';
|
|
4
4
|
import React, { useState } from 'react';
|
|
5
5
|
|
|
@@ -150,9 +150,9 @@ export const BalanceCurrencies: Story = {
|
|
|
150
150
|
|
|
151
151
|
export const OpenedInput: Story = {
|
|
152
152
|
...MultipleCurrencies,
|
|
153
|
-
play: ({ canvasElement }) => {
|
|
153
|
+
play: async ({ canvasElement }) => {
|
|
154
154
|
const canvas = within(canvasElement);
|
|
155
|
-
userEvent.click(canvas.getByRole('button'));
|
|
155
|
+
await userEvent.click(canvas.getByRole('button'));
|
|
156
156
|
},
|
|
157
157
|
};
|
|
158
158
|
|
|
@@ -5,8 +5,6 @@ import { Component } from 'react';
|
|
|
5
5
|
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
|
6
6
|
|
|
7
7
|
import { Typography } from '../common';
|
|
8
|
-
import { Key as keyValues } from '../common/key';
|
|
9
|
-
import keyCodes from '../common/keyCodes';
|
|
10
8
|
import { Size, SizeLarge, SizeMedium, SizeSmall } from '../common/propsValues/size';
|
|
11
9
|
import { Input } from '../inputs/Input';
|
|
12
10
|
import {
|
|
@@ -76,22 +74,20 @@ const parseNumber = ({
|
|
|
76
74
|
return Number(amount);
|
|
77
75
|
};
|
|
78
76
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
77
|
+
const allowedInputKeys = new Set([
|
|
78
|
+
'Backspace',
|
|
79
|
+
'Delete',
|
|
80
|
+
',',
|
|
81
|
+
'.',
|
|
82
|
+
'ArrowDown',
|
|
83
|
+
'ArrowUp',
|
|
84
|
+
'ArrowLeft',
|
|
85
|
+
'ArrowRight',
|
|
86
|
+
'Enter',
|
|
87
|
+
'Escape',
|
|
88
|
+
'Tab',
|
|
91
89
|
]);
|
|
92
90
|
|
|
93
|
-
const inputKeyAllowlist = new Set([keyValues.PERIOD, keyValues.COMMA]);
|
|
94
|
-
|
|
95
91
|
export interface MoneyInputProps extends WrappedComponentProps {
|
|
96
92
|
id?: string;
|
|
97
93
|
currencies: readonly CurrencyItem[];
|
|
@@ -162,16 +158,10 @@ class MoneyInput extends Component<MoneyInputProps, MoneyInputState> {
|
|
|
162
158
|
}
|
|
163
159
|
|
|
164
160
|
isInputAllowedForKeyEvent = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
165
|
-
const {
|
|
161
|
+
const { metaKey, key, ctrlKey } = event;
|
|
166
162
|
const isNumberKey = isNumber(parseInt(key, 10));
|
|
167
163
|
|
|
168
|
-
return (
|
|
169
|
-
isNumberKey ||
|
|
170
|
-
metaKey ||
|
|
171
|
-
ctrlKey ||
|
|
172
|
-
inputKeyCodeAllowlist.has(keyCode) ||
|
|
173
|
-
inputKeyAllowlist.has(key)
|
|
174
|
-
);
|
|
164
|
+
return isNumberKey || metaKey || ctrlKey || allowedInputKeys.has(key);
|
|
175
165
|
};
|
|
176
166
|
|
|
177
167
|
handleKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {
|
package/src/select/Select.js
CHANGED
|
@@ -10,7 +10,6 @@ import { Position, getSimpleRandomId } from '../common';
|
|
|
10
10
|
import BottomSheet from '../common/bottomSheet';
|
|
11
11
|
import { stopPropagation } from '../common/domHelpers';
|
|
12
12
|
import { useLayout } from '../common/hooks';
|
|
13
|
-
import KeyCodes from '../common/keyCodes';
|
|
14
13
|
import Panel from '../common/panel';
|
|
15
14
|
import Drawer from '../drawer';
|
|
16
15
|
|
|
@@ -204,17 +203,17 @@ export default function Select({
|
|
|
204
203
|
};
|
|
205
204
|
|
|
206
205
|
const handleKeyDown = (event) => {
|
|
207
|
-
switch (event.
|
|
208
|
-
case
|
|
209
|
-
case
|
|
206
|
+
switch (event.key) {
|
|
207
|
+
case 'ArrowUp':
|
|
208
|
+
case 'ArrowDown':
|
|
210
209
|
if (open) {
|
|
211
|
-
moveFocusWithDifference(event.
|
|
210
|
+
moveFocusWithDifference(event.key === 'ArrowUp' ? -1 : 1);
|
|
212
211
|
} else {
|
|
213
212
|
setOpen(true);
|
|
214
213
|
}
|
|
215
214
|
stopPropagation(event);
|
|
216
215
|
break;
|
|
217
|
-
case
|
|
216
|
+
case ' ':
|
|
218
217
|
if (event.target !== searchBoxReference.current) {
|
|
219
218
|
if (open) {
|
|
220
219
|
selectKeyboardFocusedOption();
|
|
@@ -224,7 +223,7 @@ export default function Select({
|
|
|
224
223
|
stopPropagation(event);
|
|
225
224
|
}
|
|
226
225
|
break;
|
|
227
|
-
case
|
|
226
|
+
case 'Enter':
|
|
228
227
|
if (open) {
|
|
229
228
|
selectKeyboardFocusedOption();
|
|
230
229
|
} else {
|
|
@@ -232,11 +231,11 @@ export default function Select({
|
|
|
232
231
|
}
|
|
233
232
|
stopPropagation(event);
|
|
234
233
|
break;
|
|
235
|
-
case
|
|
234
|
+
case 'Escape':
|
|
236
235
|
handleCloseOptions();
|
|
237
236
|
stopPropagation(event);
|
|
238
237
|
break;
|
|
239
|
-
case
|
|
238
|
+
case 'Tab':
|
|
240
239
|
if (open) {
|
|
241
240
|
selectKeyboardFocusedOption();
|
|
242
241
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { action } from '@storybook/addon-actions';
|
|
2
2
|
import { number } from '@storybook/addon-knobs';
|
|
3
|
+
import { StoryContext } from '@storybook/react';
|
|
4
|
+
import { userEvent, within } from '@storybook/test';
|
|
3
5
|
import { Mobile, Theme, Switch, Bulb, Info, Coins } from '@transferwise/icons';
|
|
4
6
|
|
|
5
7
|
import Button from '../button';
|
|
6
8
|
import CheckboxOption from '../checkboxOption/CheckboxOption';
|
|
7
|
-
import { within, userEvent } from '../test-utils';
|
|
8
9
|
|
|
9
10
|
import { Snackbar } from './Snackbar';
|
|
10
11
|
import { SnackbarConsumer } from './SnackbarContext';
|
|
@@ -120,7 +121,7 @@ export const basic = () => {
|
|
|
120
121
|
);
|
|
121
122
|
};
|
|
122
123
|
|
|
123
|
-
basic.play = async ({ canvasElement }) => {
|
|
124
|
+
basic.play = async ({ canvasElement }: StoryContext) => {
|
|
124
125
|
const canvas = within(canvasElement);
|
|
125
|
-
userEvent.click(canvas.getByRole('button'));
|
|
126
|
+
await userEvent.click(canvas.getByRole('button'));
|
|
126
127
|
};
|
|
@@ -1,21 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Component, createRef, RefObject } from 'react';
|
|
1
|
+
import { Component, createRef } from 'react';
|
|
3
2
|
import { CSSTransition } from 'react-transition-group';
|
|
4
3
|
|
|
5
4
|
import ActionButton from '../actionButton';
|
|
6
5
|
import Body from '../body';
|
|
7
|
-
import { Theme } from '../common';
|
|
6
|
+
import { Theme, ThemeDark, ThemeLight } from '../common';
|
|
8
7
|
import { DirectionContext } from '../provider/direction';
|
|
9
8
|
import withNextPortal from '../withNextPortal/withNextPortal';
|
|
10
9
|
|
|
11
10
|
export const CSS_TRANSITION_DURATION = 400;
|
|
12
11
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
export interface SnackbarProps {
|
|
13
|
+
action?: {
|
|
14
|
+
label: string;
|
|
15
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
16
|
+
};
|
|
17
|
+
text: React.ReactNode;
|
|
18
|
+
theme?: ThemeLight | ThemeDark;
|
|
19
|
+
timeout: number;
|
|
20
|
+
timestamp: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface SnackbarState extends Pick<SnackbarProps, 'action' | 'text' | 'theme'> {
|
|
24
|
+
visible: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class Snackbar extends Component<SnackbarProps, SnackbarState> {
|
|
28
|
+
bodyRef = createRef<HTMLSpanElement>();
|
|
29
|
+
timeout = 0;
|
|
30
|
+
transitionTimeout = 0;
|
|
16
31
|
|
|
17
|
-
constructor() {
|
|
18
|
-
super();
|
|
32
|
+
constructor(props: SnackbarProps) {
|
|
33
|
+
super(props);
|
|
19
34
|
this.state = {
|
|
20
35
|
visible: false,
|
|
21
36
|
text: '',
|
|
@@ -23,11 +38,11 @@ export class Snackbar extends Component {
|
|
|
23
38
|
}
|
|
24
39
|
|
|
25
40
|
componentWillUnmount() {
|
|
26
|
-
clearTimeout(this.timeout);
|
|
27
|
-
clearTimeout(this.transitionTimeout);
|
|
41
|
+
window.clearTimeout(this.timeout);
|
|
42
|
+
window.clearTimeout(this.transitionTimeout);
|
|
28
43
|
}
|
|
29
44
|
|
|
30
|
-
shouldComponentUpdate(nextProps, nextState) {
|
|
45
|
+
shouldComponentUpdate(nextProps: SnackbarProps, nextState: SnackbarState) {
|
|
31
46
|
if (!nextProps.text) {
|
|
32
47
|
return false;
|
|
33
48
|
}
|
|
@@ -45,12 +60,12 @@ export class Snackbar extends Component {
|
|
|
45
60
|
setLeaveTimeout = () => {
|
|
46
61
|
const { timeout } = this.props;
|
|
47
62
|
|
|
48
|
-
this.timeout = setTimeout(() => {
|
|
63
|
+
this.timeout = window.setTimeout(() => {
|
|
49
64
|
this.setState({ visible: false });
|
|
50
65
|
}, timeout);
|
|
51
66
|
};
|
|
52
67
|
|
|
53
|
-
componentDidUpdate(previousProps) {
|
|
68
|
+
componentDidUpdate(previousProps: SnackbarProps) {
|
|
54
69
|
const { action, text, theme, timestamp } = this.props;
|
|
55
70
|
|
|
56
71
|
if (!previousProps.text) {
|
|
@@ -58,11 +73,11 @@ export class Snackbar extends Component {
|
|
|
58
73
|
this.setLeaveTimeout();
|
|
59
74
|
});
|
|
60
75
|
} else if (previousProps.timestamp !== timestamp) {
|
|
61
|
-
clearTimeout(this.timeout);
|
|
76
|
+
window.clearTimeout(this.timeout);
|
|
62
77
|
|
|
63
78
|
if (this.state.visible) {
|
|
64
79
|
this.setState({ visible: false }, () => {
|
|
65
|
-
this.transitionTimeout = setTimeout(() => {
|
|
80
|
+
this.transitionTimeout = window.setTimeout(() => {
|
|
66
81
|
this.setState({ visible: true, action, text, theme });
|
|
67
82
|
this.setLeaveTimeout();
|
|
68
83
|
}, CSS_TRANSITION_DURATION);
|
|
@@ -75,7 +90,7 @@ export class Snackbar extends Component {
|
|
|
75
90
|
}
|
|
76
91
|
|
|
77
92
|
render() {
|
|
78
|
-
const { action, text, theme, visible } = this.state;
|
|
93
|
+
const { action, text, theme = Theme.LIGHT, visible } = this.state;
|
|
79
94
|
const { timeout } = this.props;
|
|
80
95
|
|
|
81
96
|
return (
|
|
@@ -112,20 +127,4 @@ export class Snackbar extends Component {
|
|
|
112
127
|
|
|
113
128
|
Snackbar.contextType = DirectionContext;
|
|
114
129
|
|
|
115
|
-
Snackbar.propTypes = {
|
|
116
|
-
action: PropTypes.shape({
|
|
117
|
-
label: PropTypes.string.isRequired,
|
|
118
|
-
onClick: PropTypes.func,
|
|
119
|
-
}),
|
|
120
|
-
text: PropTypes.node.isRequired,
|
|
121
|
-
theme: PropTypes.oneOf(['light', 'dark']),
|
|
122
|
-
timeout: PropTypes.number.isRequired,
|
|
123
|
-
timestamp: PropTypes.number.isRequired,
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
Snackbar.defaultProps = {
|
|
127
|
-
action: null,
|
|
128
|
-
theme: Theme.LIGHT,
|
|
129
|
-
};
|
|
130
|
-
|
|
131
130
|
export default withNextPortal(Snackbar);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import { SnackbarProps } from './Snackbar';
|
|
4
|
+
|
|
5
|
+
export type SnackbarContextType = {
|
|
6
|
+
createSnackbar: (props: Omit<SnackbarProps, 'timeout' | 'timestamp'>) => void;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const SnackbarContext = createContext<SnackbarContextType>({ createSnackbar: () => {} });
|
|
10
|
+
|
|
11
|
+
export const SnackbarConsumer = SnackbarContext.Consumer;
|