@transferwise/components 46.67.2 → 46.68.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/button/Button.js +22 -6
- package/build/button/Button.js.map +1 -1
- package/build/button/Button.mjs +22 -6
- package/build/button/Button.mjs.map +1 -1
- package/build/main.css +212 -210
- package/build/styles/button/Button.css +3 -0
- package/build/styles/main.css +212 -210
- package/build/styles/uploadInput/UploadInput.css +13 -81
- package/build/styles/uploadInput/uploadButton/UploadButton.css +77 -31
- package/build/styles/uploadInput/uploadItem/UploadItem.css +130 -109
- package/build/typeahead/Typeahead.js +22 -8
- package/build/typeahead/Typeahead.js.map +1 -1
- package/build/typeahead/Typeahead.mjs +22 -9
- package/build/typeahead/Typeahead.mjs.map +1 -1
- package/build/typeahead/typeaheadInput/TypeaheadInput.js +5 -2
- package/build/typeahead/typeaheadInput/TypeaheadInput.js.map +1 -1
- package/build/typeahead/typeaheadInput/TypeaheadInput.mjs +5 -2
- package/build/typeahead/typeaheadInput/TypeaheadInput.mjs.map +1 -1
- package/build/typeahead/typeaheadOption/TypeaheadOption.js +9 -6
- package/build/typeahead/typeaheadOption/TypeaheadOption.js.map +1 -1
- package/build/typeahead/typeaheadOption/TypeaheadOption.mjs +9 -6
- package/build/typeahead/typeaheadOption/TypeaheadOption.mjs.map +1 -1
- package/build/types/button/Button.d.ts.map +1 -1
- package/build/types/typeahead/Typeahead.d.ts +1 -1
- package/build/types/typeahead/Typeahead.d.ts.map +1 -1
- package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts +2 -0
- package/build/types/typeahead/typeaheadInput/TypeaheadInput.d.ts.map +1 -1
- package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts +2 -1
- package/build/types/typeahead/typeaheadOption/TypeaheadOption.d.ts.map +1 -1
- package/build/types/uploadInput/UploadInput.d.ts.map +1 -1
- package/build/types/uploadInput/uploadButton/UploadButton.d.ts +5 -0
- package/build/types/uploadInput/uploadButton/UploadButton.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/uploadInput/UploadInput.js +30 -20
- package/build/uploadInput/UploadInput.js.map +1 -1
- package/build/uploadInput/UploadInput.mjs +30 -20
- package/build/uploadInput/UploadInput.mjs.map +1 -1
- package/build/uploadInput/uploadButton/UploadButton.js +25 -32
- package/build/uploadInput/uploadButton/UploadButton.js.map +1 -1
- package/build/uploadInput/uploadButton/UploadButton.mjs +25 -32
- package/build/uploadInput/uploadButton/UploadButton.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.js +32 -38
- package/build/uploadInput/uploadItem/UploadItem.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItem.mjs +33 -39
- package/build/uploadInput/uploadItem/UploadItem.mjs.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js +2 -1
- package/build/uploadInput/uploadItem/UploadItemLink.js.map +1 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs +2 -1
- package/build/uploadInput/uploadItem/UploadItemLink.mjs.map +1 -1
- package/package.json +4 -4
- package/src/button/Button.css +3 -0
- package/src/button/Button.less +6 -0
- package/src/button/Button.spec.js +81 -45
- package/src/button/Button.story.tsx +54 -20
- package/src/button/Button.tsx +32 -7
- package/src/button/__snapshots__/Button.spec.js.snap +56 -12
- package/src/main.css +212 -210
- package/src/typeahead/Typeahead.spec.js +8 -0
- package/src/typeahead/Typeahead.tsx +29 -13
- package/src/typeahead/typeaheadInput/TypeaheadInput.tsx +9 -0
- package/src/typeahead/typeaheadOption/TypeaheadOption.spec.js +8 -0
- package/src/typeahead/typeaheadOption/TypeaheadOption.tsx +9 -6
- package/src/uploadInput/UploadInput.css +13 -81
- package/src/uploadInput/UploadInput.less +18 -80
- package/src/uploadInput/UploadInput.tests.story.tsx +5 -5
- package/src/uploadInput/UploadInput.tsx +43 -32
- package/src/uploadInput/uploadButton/UploadButton.css +77 -31
- package/src/uploadInput/uploadButton/UploadButton.less +77 -35
- package/src/uploadInput/uploadButton/UploadButton.tsx +37 -26
- package/src/uploadInput/uploadItem/UploadItem.css +130 -109
- package/src/uploadInput/uploadItem/UploadItem.less +130 -118
- package/src/uploadInput/uploadItem/UploadItem.tsx +26 -28
- package/src/uploadInput/uploadItem/UploadItemLink.tsx +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "46.
|
|
3
|
+
"version": "46.68.0",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"rollup": "^4.18.1",
|
|
93
93
|
"rollup-preserve-directives": "^1.1.1",
|
|
94
94
|
"storybook": "^8.2.2",
|
|
95
|
-
"@transferwise/
|
|
96
|
-
"@
|
|
97
|
-
"@
|
|
95
|
+
"@transferwise/less-config": "3.1.0",
|
|
96
|
+
"@transferwise/neptune-css": "14.17.0",
|
|
97
|
+
"@wise/components-theming": "1.6.0"
|
|
98
98
|
},
|
|
99
99
|
"peerDependencies": {
|
|
100
100
|
"@transferwise/icons": "^3.7.0",
|
package/src/button/Button.css
CHANGED
package/src/button/Button.less
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
1
|
import { createRef } from 'react';
|
|
3
2
|
|
|
4
3
|
import { ControlType, Type, Priority, Size } from '../common';
|
|
5
|
-
import { render,
|
|
4
|
+
import { render, screen, userEvent } from '../test-utils';
|
|
6
5
|
|
|
7
6
|
import Button from '.';
|
|
7
|
+
import messages from './Button.messages';
|
|
8
8
|
|
|
9
9
|
const { ACCENT, POSITIVE, NEGATIVE } = ControlType;
|
|
10
10
|
const { PAY, LINK, DANGER } = Type;
|
|
@@ -12,51 +12,50 @@ const { PRIMARY, SECONDARY, TERTIARY } = Priority;
|
|
|
12
12
|
const { SMALL, MEDIUM, LARGE } = Size;
|
|
13
13
|
|
|
14
14
|
describe('Button', () => {
|
|
15
|
+
// eslint-disable-next-line no-console
|
|
16
|
+
const originalWarn = console.warn;
|
|
17
|
+
let mockedWarn;
|
|
18
|
+
|
|
15
19
|
const props = {
|
|
16
20
|
onClick: jest.fn(),
|
|
21
|
+
onFocus: jest.fn(),
|
|
22
|
+
onBlur: jest.fn(),
|
|
17
23
|
children: 'Send money',
|
|
18
24
|
};
|
|
19
25
|
|
|
20
|
-
const origWarn = console.warn;
|
|
21
|
-
let mockedWarn;
|
|
22
|
-
|
|
23
26
|
beforeAll(() => {
|
|
24
|
-
mockedWarn = jest.fn()
|
|
27
|
+
mockedWarn = jest.fn().mockImplementation((args) => {
|
|
28
|
+
if (typeof args !== 'string' || !args.startsWith('Button has deprecated the')) {
|
|
29
|
+
originalWarn(args);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
// eslint-disable-next-line no-console
|
|
25
33
|
console.warn = mockedWarn;
|
|
26
34
|
});
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
cleanup();
|
|
30
|
-
jest.clearAllMocks();
|
|
31
|
-
});
|
|
36
|
+
beforeEach(jest.clearAllMocks);
|
|
32
37
|
|
|
33
38
|
afterAll(() => {
|
|
34
|
-
|
|
39
|
+
// eslint-disable-next-line no-console
|
|
40
|
+
console.warn = originalWarn;
|
|
35
41
|
});
|
|
36
42
|
|
|
37
43
|
describe('by default', () => {
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
render(<Button {...props} />);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
44
|
it('renders the text', () => {
|
|
43
|
-
|
|
45
|
+
render(<Button {...props} />);
|
|
46
|
+
expect(screen.getByText(props.children)).toBeInTheDocument();
|
|
44
47
|
});
|
|
45
48
|
|
|
46
49
|
it('set `ref` to be true on Button', () => {
|
|
47
50
|
const reference = createRef();
|
|
48
|
-
const props = {
|
|
49
|
-
ref: reference,
|
|
50
|
-
};
|
|
51
51
|
|
|
52
52
|
expect(reference.current).toBeFalsy();
|
|
53
|
-
|
|
54
|
-
render(<Button {...props}>Click me!</Button>);
|
|
55
|
-
|
|
53
|
+
render(<Button ref={reference}>Click me!</Button>);
|
|
56
54
|
expect(reference.current).toBeTruthy();
|
|
57
55
|
});
|
|
58
56
|
|
|
59
57
|
it('is not disabled', () => {
|
|
58
|
+
render(<Button {...props} />);
|
|
60
59
|
expect(screen.getByRole('button')).toBeEnabled();
|
|
61
60
|
});
|
|
62
61
|
|
|
@@ -70,19 +69,14 @@ describe('Button', () => {
|
|
|
70
69
|
});
|
|
71
70
|
|
|
72
71
|
describe('button attributes', () => {
|
|
73
|
-
it('disables the button if disabled', () => {
|
|
74
|
-
render(<Button {...props} disabled />);
|
|
75
|
-
expect(screen.getByRole('button')).toBeDisabled();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
72
|
it('sets the htmlType if set', () => {
|
|
79
73
|
render(<Button {...props} htmlType="submit" />);
|
|
80
74
|
expect(screen.getByRole('button')).toHaveAttribute('type', 'submit');
|
|
81
75
|
});
|
|
82
76
|
|
|
83
77
|
it('passes through custom classes if set', () => {
|
|
84
|
-
render(<Button {...props} className="
|
|
85
|
-
expect(screen.getByRole('button')).toHaveClass('
|
|
78
|
+
render(<Button {...props} className="donkeysarethebest" />);
|
|
79
|
+
expect(screen.getByRole('button')).toHaveClass('donkeysarethebest');
|
|
86
80
|
});
|
|
87
81
|
|
|
88
82
|
it('passes through aria-label if set', () => {
|
|
@@ -94,17 +88,47 @@ describe('Button', () => {
|
|
|
94
88
|
|
|
95
89
|
describe('onClick', () => {
|
|
96
90
|
it('calls onClick when clicked', async () => {
|
|
97
|
-
|
|
98
|
-
render(<Button {...props} onClick={onClick} />);
|
|
91
|
+
render(<Button {...props} />);
|
|
99
92
|
await userEvent.click(screen.getByRole('button'));
|
|
100
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
93
|
+
expect(props.onClick).toHaveBeenCalledTimes(1);
|
|
101
94
|
});
|
|
102
95
|
|
|
103
96
|
it('does not call onClick when clicked if disabled', async () => {
|
|
104
|
-
|
|
105
|
-
render(<Button {...props} disabled onClick={onClick} />);
|
|
97
|
+
render(<Button {...props} disabled />);
|
|
106
98
|
await userEvent.click(screen.getByRole('button'));
|
|
107
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
99
|
+
expect(props.onClick).toHaveBeenCalledTimes(0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('does not call onClick when clicked if loading', async () => {
|
|
103
|
+
render(<Button {...props} loading />);
|
|
104
|
+
await userEvent.click(screen.getByRole('button'));
|
|
105
|
+
expect(props.onClick).toHaveBeenCalledTimes(0);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('onFocus and onBlur', () => {
|
|
110
|
+
it('calls both handlers by default', async () => {
|
|
111
|
+
render(<Button {...props} />);
|
|
112
|
+
await userEvent.tab();
|
|
113
|
+
expect(props.onFocus).toHaveBeenCalledTimes(1);
|
|
114
|
+
await userEvent.tab();
|
|
115
|
+
expect(props.onFocus).toHaveBeenCalledTimes(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('does not call either handler if disabled', async () => {
|
|
119
|
+
render(<Button {...props} disabled />);
|
|
120
|
+
await userEvent.tab();
|
|
121
|
+
expect(props.onFocus).not.toHaveBeenCalled();
|
|
122
|
+
await userEvent.tab();
|
|
123
|
+
expect(props.onFocus).not.toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('calls both handlers if loading', async () => {
|
|
127
|
+
render(<Button {...props} loading />);
|
|
128
|
+
await userEvent.tab();
|
|
129
|
+
expect(props.onFocus).toHaveBeenCalledTimes(1);
|
|
130
|
+
await userEvent.tab();
|
|
131
|
+
expect(props.onFocus).toHaveBeenCalledTimes(1);
|
|
108
132
|
});
|
|
109
133
|
});
|
|
110
134
|
|
|
@@ -168,17 +192,29 @@ describe('Button', () => {
|
|
|
168
192
|
});
|
|
169
193
|
});
|
|
170
194
|
|
|
171
|
-
describe('
|
|
172
|
-
it('renders as loading if loading is true', () => {
|
|
173
|
-
const { container } = render(<Button {...props} loading />);
|
|
174
|
-
expect(container.querySelector('.btn-loader')).toBeInTheDocument();
|
|
175
|
-
expect(screen.getByRole('button', { name: 'loading' })).toBeInTheDocument();
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('loading button has aria-label of loading', () => {
|
|
195
|
+
describe('other states', () => {
|
|
196
|
+
it('renders as loading if `loading` is true', () => {
|
|
179
197
|
render(<Button {...props} loading />);
|
|
180
|
-
const
|
|
181
|
-
|
|
198
|
+
const button = screen.queryByRole('button', {
|
|
199
|
+
name: messages.loadingAriaLabel.defaultMessage,
|
|
200
|
+
});
|
|
201
|
+
expect(button).toBeInTheDocument();
|
|
202
|
+
expect(button).toBeEnabled();
|
|
203
|
+
expect(button).toHaveClass('btn-loading');
|
|
204
|
+
expect(button).toHaveAttribute('aria-disabled', 'true');
|
|
205
|
+
expect(button).toHaveAttribute('aria-busy', 'true');
|
|
206
|
+
expect(button).toHaveAttribute('aria-live', 'polite');
|
|
207
|
+
expect(screen.getByTestId('ButtonProgressIndicator')).toBeInTheDocument();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('disables the button', () => {
|
|
211
|
+
render(<Button {...props} disabled />);
|
|
212
|
+
const button = screen.queryByRole('button');
|
|
213
|
+
expect(button).toBeDisabled();
|
|
214
|
+
expect(button).toHaveClass('disabled');
|
|
215
|
+
expect(button).toHaveAttribute('aria-disabled', 'false');
|
|
216
|
+
expect(button).toHaveAttribute('aria-busy', 'false');
|
|
217
|
+
expect(button).toHaveAttribute('aria-live', 'off');
|
|
182
218
|
});
|
|
183
219
|
|
|
184
220
|
it('renders as block if block is true', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import { userEvent, within } from '@storybook/test';
|
|
2
|
+
import { userEvent, within, fn } from '@storybook/test';
|
|
3
3
|
|
|
4
4
|
import { ControlType, Priority } from '../common';
|
|
5
5
|
import { storyConfig } from '../test-utils';
|
|
@@ -11,6 +11,10 @@ export default {
|
|
|
11
11
|
title: 'Actions/Button',
|
|
12
12
|
args: {
|
|
13
13
|
children: 'Button text',
|
|
14
|
+
loading: false,
|
|
15
|
+
onClick: fn(),
|
|
16
|
+
onBlur: fn(),
|
|
17
|
+
onFocus: fn(),
|
|
14
18
|
},
|
|
15
19
|
argTypes: {
|
|
16
20
|
as: {
|
|
@@ -46,39 +50,38 @@ export const Focused = storyConfig<Story>(
|
|
|
46
50
|
|
|
47
51
|
export const Variants = storyConfig<Story>(
|
|
48
52
|
{
|
|
49
|
-
args: {
|
|
50
|
-
className: 'm-r-2',
|
|
51
|
-
},
|
|
52
53
|
render: (args) => {
|
|
53
54
|
return (
|
|
54
55
|
<>
|
|
55
56
|
<div className="m-b-2">
|
|
56
57
|
<div className="title-4 m-b-1">Accent</div>
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
<div className="d-flex flex-wrap" style={{ gap: 'var(--size-16)' }}>
|
|
59
|
+
<Button {...args} priority={Priority.PRIMARY} type={ControlType.ACCENT} />
|
|
60
|
+
<Button {...args} priority={Priority.SECONDARY} type={ControlType.ACCENT} />
|
|
61
|
+
<Button {...args} priority={Priority.TERTIARY} type={ControlType.ACCENT} />
|
|
62
|
+
</div>
|
|
60
63
|
</div>
|
|
61
64
|
<div className="m-b-2">
|
|
62
65
|
<div className="title-4 m-b-1">Positive</div>
|
|
63
|
-
<
|
|
64
|
-
|
|
66
|
+
<div className="d-flex flex-wrap" style={{ gap: 'var(--size-16)' }}>
|
|
67
|
+
<Button {...args} priority={Priority.PRIMARY} type={ControlType.POSITIVE} />
|
|
68
|
+
<Button {...args} priority={Priority.SECONDARY} type={ControlType.POSITIVE} />
|
|
69
|
+
</div>
|
|
65
70
|
</div>
|
|
66
71
|
<div className="m-b-2">
|
|
67
72
|
<div className="title-4 m-b-1">Negative</div>
|
|
68
|
-
<
|
|
69
|
-
|
|
73
|
+
<div className="d-flex flex-wrap" style={{ gap: 'var(--size-16)' }}>
|
|
74
|
+
<Button {...args} priority={Priority.PRIMARY} type={ControlType.NEGATIVE} />
|
|
75
|
+
<Button {...args} priority={Priority.SECONDARY} type={ControlType.NEGATIVE} />
|
|
76
|
+
</div>
|
|
70
77
|
</div>
|
|
71
78
|
<div className="m-b-2">
|
|
72
79
|
<div className="title-4 m-b-1">Disabled</div>
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
<div className="title-4 m-b-1">Loading</div>
|
|
79
|
-
<Button {...args} priority={Priority.PRIMARY} loading />
|
|
80
|
-
<Button {...args} priority={Priority.SECONDARY} loading />
|
|
81
|
-
<Button {...args} priority={Priority.TERTIARY} loading />
|
|
80
|
+
<div className="d-flex flex-wrap" style={{ gap: 'var(--size-16)' }}>
|
|
81
|
+
<Button {...args} priority={Priority.PRIMARY} disabled />
|
|
82
|
+
<Button {...args} priority={Priority.SECONDARY} disabled />
|
|
83
|
+
<Button {...args} priority={Priority.TERTIARY} disabled />
|
|
84
|
+
</div>
|
|
82
85
|
</div>
|
|
83
86
|
</>
|
|
84
87
|
);
|
|
@@ -87,6 +90,37 @@ export const Variants = storyConfig<Story>(
|
|
|
87
90
|
{ variants: ['default', 'dark', 'rtl'] },
|
|
88
91
|
);
|
|
89
92
|
|
|
93
|
+
/**
|
|
94
|
+
* The purpose of the `loading` mode is to convey a message to the
|
|
95
|
+
* user that some asynchronous process has been triggered, likely
|
|
96
|
+
* in response to their previous action.
|
|
97
|
+
*
|
|
98
|
+
* Although it carries some similarities with the `disabled` mode
|
|
99
|
+
* (users cannot activate a loading button), it's not hidden from
|
|
100
|
+
* the keyboard and assistive tech users (users can focus on it,
|
|
101
|
+
* and it's announced by screen readers), and is also much more
|
|
102
|
+
* accessible to sighted users due to its default, high contrast.
|
|
103
|
+
*/
|
|
104
|
+
export const Loading = storyConfig<Story>(
|
|
105
|
+
{
|
|
106
|
+
render: (args) => {
|
|
107
|
+
return (
|
|
108
|
+
<div className="d-flex flex-wrap" style={{ gap: 'var(--size-16)' }}>
|
|
109
|
+
<Button {...args} loading priority={Priority.PRIMARY} />
|
|
110
|
+
<Button {...args} loading priority={Priority.SECONDARY} />
|
|
111
|
+
<Button {...args} loading priority={Priority.TERTIARY} />
|
|
112
|
+
<Button {...args} loading priority={Priority.PRIMARY} type={ControlType.NEGATIVE} />
|
|
113
|
+
<Button {...args} loading priority={Priority.SECONDARY} type={ControlType.NEGATIVE} />
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
},
|
|
117
|
+
args: {
|
|
118
|
+
loading: true,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{ variants: ['default', 'dark', 'rtl'] },
|
|
122
|
+
);
|
|
123
|
+
|
|
90
124
|
export const SocialMedia = storyConfig<Story>(
|
|
91
125
|
{
|
|
92
126
|
render: () => {
|
package/src/button/Button.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
|
-
import {
|
|
2
|
+
import { ElementType, forwardRef, MouseEvent } from 'react';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
4
|
|
|
5
5
|
import {
|
|
@@ -65,6 +65,7 @@ const Button = forwardRef<ButtonReferenceType, Props>(
|
|
|
65
65
|
priority = Priority.PRIMARY,
|
|
66
66
|
size = Size.MEDIUM,
|
|
67
67
|
type = ControlType.ACCENT,
|
|
68
|
+
onClick,
|
|
68
69
|
...rest
|
|
69
70
|
}: Props,
|
|
70
71
|
reference,
|
|
@@ -85,9 +86,7 @@ const Button = forwardRef<ButtonReferenceType, Props>(
|
|
|
85
86
|
{
|
|
86
87
|
'btn-loading': loading,
|
|
87
88
|
'btn-block np-btn-block': block,
|
|
88
|
-
|
|
89
|
-
{
|
|
90
|
-
disabled: disabled || loading,
|
|
89
|
+
disabled,
|
|
91
90
|
},
|
|
92
91
|
// @ts-expect-error fix when refactor `typeClassMap` to TypeScript
|
|
93
92
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
@@ -109,23 +108,49 @@ const Button = forwardRef<ButtonReferenceType, Props>(
|
|
|
109
108
|
const { htmlType = 'button', ...restProps } = rest as ButtonProps;
|
|
110
109
|
props = {
|
|
111
110
|
...restProps,
|
|
112
|
-
disabled
|
|
111
|
+
disabled,
|
|
112
|
+
'aria-disabled': loading,
|
|
113
113
|
type: htmlType,
|
|
114
114
|
};
|
|
115
115
|
} else {
|
|
116
|
-
props = {
|
|
116
|
+
props = {
|
|
117
|
+
...rest,
|
|
118
|
+
'aria-disabled': loading,
|
|
119
|
+
} as AnchorProps;
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Ensures that the button cannot be activated in loading or disabled mode,
|
|
124
|
+
* when `aria-disabled` might be used over the `disabled` HTML attribute
|
|
125
|
+
*/
|
|
126
|
+
const handleClick =
|
|
127
|
+
(handler: Props['onClick']) =>
|
|
128
|
+
(event: MouseEvent<HTMLButtonElement> & MouseEvent<HTMLAnchorElement>) => {
|
|
129
|
+
if (disabled || loading) {
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
} else if (typeof handler === 'function') {
|
|
132
|
+
handler(event);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
119
136
|
return (
|
|
120
137
|
<Element
|
|
121
138
|
ref={reference}
|
|
122
139
|
className={classes}
|
|
140
|
+
onClick={handleClick(onClick)}
|
|
123
141
|
{...props}
|
|
124
142
|
aria-live={loading ? 'polite' : 'off'}
|
|
143
|
+
aria-busy={loading}
|
|
125
144
|
aria-label={loading ? intl.formatMessage(messages.loadingAriaLabel) : rest['aria-label']}
|
|
126
145
|
>
|
|
127
146
|
{children}
|
|
128
|
-
{loading &&
|
|
147
|
+
{loading && (
|
|
148
|
+
<ProcessIndicator
|
|
149
|
+
size={processIndicatorSize()}
|
|
150
|
+
className="btn-loader"
|
|
151
|
+
data-testid="ButtonProgressIndicator"
|
|
152
|
+
/>
|
|
153
|
+
)}
|
|
129
154
|
</Element>
|
|
130
155
|
);
|
|
131
156
|
},
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`Button alternative states renders as block if block is true 1`] = `
|
|
4
|
-
<div>
|
|
5
|
-
<button
|
|
6
|
-
aria-live="off"
|
|
7
|
-
class="btn btn-md np-btn np-btn-md btn-block np-btn-block btn-accent btn-priority-1"
|
|
8
|
-
type="button"
|
|
9
|
-
>
|
|
10
|
-
Send money
|
|
11
|
-
</button>
|
|
12
|
-
</div>
|
|
13
|
-
`;
|
|
14
|
-
|
|
15
3
|
exports[`Button by default renders a medium button of type accent and priority primary 1`] = `
|
|
16
4
|
<div>
|
|
17
5
|
<button
|
|
6
|
+
aria-busy="false"
|
|
7
|
+
aria-disabled="false"
|
|
18
8
|
aria-live="off"
|
|
19
9
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-1"
|
|
20
10
|
type="button"
|
|
@@ -27,6 +17,8 @@ exports[`Button by default renders a medium button of type accent and priority p
|
|
|
27
17
|
exports[`Button by default renders an anchor tag with button styles of type accent and priority primary 1`] = `
|
|
28
18
|
<div>
|
|
29
19
|
<a
|
|
20
|
+
aria-busy="false"
|
|
21
|
+
aria-disabled="false"
|
|
30
22
|
aria-live="off"
|
|
31
23
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-1"
|
|
32
24
|
href="#"
|
|
@@ -39,6 +31,8 @@ exports[`Button by default renders an anchor tag with button styles of type acce
|
|
|
39
31
|
exports[`Button deprecated types renders danger as negative buttons with priority secondary and logs a warning 1`] = `
|
|
40
32
|
<div>
|
|
41
33
|
<button
|
|
34
|
+
aria-busy="false"
|
|
35
|
+
aria-disabled="false"
|
|
42
36
|
aria-live="off"
|
|
43
37
|
class="btn btn-md np-btn np-btn-md btn-negative btn-priority-2"
|
|
44
38
|
type="button"
|
|
@@ -51,6 +45,8 @@ exports[`Button deprecated types renders danger as negative buttons with priorit
|
|
|
51
45
|
exports[`Button deprecated types renders link as accent buttons with priority tertiary and logs a warning 1`] = `
|
|
52
46
|
<div>
|
|
53
47
|
<button
|
|
48
|
+
aria-busy="false"
|
|
49
|
+
aria-disabled="false"
|
|
54
50
|
aria-live="off"
|
|
55
51
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-3"
|
|
56
52
|
type="button"
|
|
@@ -63,6 +59,8 @@ exports[`Button deprecated types renders link as accent buttons with priority te
|
|
|
63
59
|
exports[`Button deprecated types renders pay as positive buttons and logs a warning 1`] = `
|
|
64
60
|
<div>
|
|
65
61
|
<button
|
|
62
|
+
aria-busy="false"
|
|
63
|
+
aria-disabled="false"
|
|
66
64
|
aria-live="off"
|
|
67
65
|
class="btn btn-md np-btn np-btn-md btn-positive btn-priority-1"
|
|
68
66
|
type="button"
|
|
@@ -75,6 +73,8 @@ exports[`Button deprecated types renders pay as positive buttons and logs a warn
|
|
|
75
73
|
exports[`Button deprecated types renders primary as accent buttons and logs a warning 1`] = `
|
|
76
74
|
<div>
|
|
77
75
|
<button
|
|
76
|
+
aria-busy="false"
|
|
77
|
+
aria-disabled="false"
|
|
78
78
|
aria-live="off"
|
|
79
79
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-1"
|
|
80
80
|
type="button"
|
|
@@ -84,9 +84,25 @@ exports[`Button deprecated types renders primary as accent buttons and logs a wa
|
|
|
84
84
|
</div>
|
|
85
85
|
`;
|
|
86
86
|
|
|
87
|
+
exports[`Button other states renders as block if block is true 1`] = `
|
|
88
|
+
<div>
|
|
89
|
+
<button
|
|
90
|
+
aria-busy="false"
|
|
91
|
+
aria-disabled="false"
|
|
92
|
+
aria-live="off"
|
|
93
|
+
class="btn btn-md np-btn np-btn-md btn-block np-btn-block btn-accent btn-priority-1"
|
|
94
|
+
type="button"
|
|
95
|
+
>
|
|
96
|
+
Send money
|
|
97
|
+
</button>
|
|
98
|
+
</div>
|
|
99
|
+
`;
|
|
100
|
+
|
|
87
101
|
exports[`Button priorities defaults tertiary buttons to secondary for positive buttons 1`] = `
|
|
88
102
|
<div>
|
|
89
103
|
<button
|
|
104
|
+
aria-busy="false"
|
|
105
|
+
aria-disabled="false"
|
|
90
106
|
aria-live="off"
|
|
91
107
|
class="btn btn-md np-btn np-btn-md btn-positive btn-priority-2"
|
|
92
108
|
type="button"
|
|
@@ -99,6 +115,8 @@ exports[`Button priorities defaults tertiary buttons to secondary for positive b
|
|
|
99
115
|
exports[`Button priorities defaults tertiary buttons to secondary for positive buttons 2`] = `
|
|
100
116
|
<div>
|
|
101
117
|
<button
|
|
118
|
+
aria-busy="false"
|
|
119
|
+
aria-disabled="false"
|
|
102
120
|
aria-live="off"
|
|
103
121
|
class="btn btn-md np-btn np-btn-md btn-negative btn-priority-2"
|
|
104
122
|
type="button"
|
|
@@ -111,6 +129,8 @@ exports[`Button priorities defaults tertiary buttons to secondary for positive b
|
|
|
111
129
|
exports[`Button priorities renders primary buttons 1`] = `
|
|
112
130
|
<div>
|
|
113
131
|
<button
|
|
132
|
+
aria-busy="false"
|
|
133
|
+
aria-disabled="false"
|
|
114
134
|
aria-live="off"
|
|
115
135
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-1"
|
|
116
136
|
type="button"
|
|
@@ -123,6 +143,8 @@ exports[`Button priorities renders primary buttons 1`] = `
|
|
|
123
143
|
exports[`Button priorities renders primary buttons 2`] = `
|
|
124
144
|
<div>
|
|
125
145
|
<button
|
|
146
|
+
aria-busy="false"
|
|
147
|
+
aria-disabled="false"
|
|
126
148
|
aria-live="off"
|
|
127
149
|
class="btn btn-md np-btn np-btn-md btn-positive btn-priority-1"
|
|
128
150
|
type="button"
|
|
@@ -135,6 +157,8 @@ exports[`Button priorities renders primary buttons 2`] = `
|
|
|
135
157
|
exports[`Button priorities renders primary buttons 3`] = `
|
|
136
158
|
<div>
|
|
137
159
|
<button
|
|
160
|
+
aria-busy="false"
|
|
161
|
+
aria-disabled="false"
|
|
138
162
|
aria-live="off"
|
|
139
163
|
class="btn btn-md np-btn np-btn-md btn-negative btn-priority-1"
|
|
140
164
|
type="button"
|
|
@@ -147,6 +171,8 @@ exports[`Button priorities renders primary buttons 3`] = `
|
|
|
147
171
|
exports[`Button priorities renders secondary buttons 1`] = `
|
|
148
172
|
<div>
|
|
149
173
|
<button
|
|
174
|
+
aria-busy="false"
|
|
175
|
+
aria-disabled="false"
|
|
150
176
|
aria-live="off"
|
|
151
177
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-2"
|
|
152
178
|
type="button"
|
|
@@ -159,6 +185,8 @@ exports[`Button priorities renders secondary buttons 1`] = `
|
|
|
159
185
|
exports[`Button priorities renders secondary buttons 2`] = `
|
|
160
186
|
<div>
|
|
161
187
|
<button
|
|
188
|
+
aria-busy="false"
|
|
189
|
+
aria-disabled="false"
|
|
162
190
|
aria-live="off"
|
|
163
191
|
class="btn btn-md np-btn np-btn-md btn-positive btn-priority-2"
|
|
164
192
|
type="button"
|
|
@@ -171,6 +199,8 @@ exports[`Button priorities renders secondary buttons 2`] = `
|
|
|
171
199
|
exports[`Button priorities renders secondary buttons 3`] = `
|
|
172
200
|
<div>
|
|
173
201
|
<button
|
|
202
|
+
aria-busy="false"
|
|
203
|
+
aria-disabled="false"
|
|
174
204
|
aria-live="off"
|
|
175
205
|
class="btn btn-md np-btn np-btn-md btn-negative btn-priority-2"
|
|
176
206
|
type="button"
|
|
@@ -183,6 +213,8 @@ exports[`Button priorities renders secondary buttons 3`] = `
|
|
|
183
213
|
exports[`Button priorities renders tertiary buttons 1`] = `
|
|
184
214
|
<div>
|
|
185
215
|
<button
|
|
216
|
+
aria-busy="false"
|
|
217
|
+
aria-disabled="false"
|
|
186
218
|
aria-live="off"
|
|
187
219
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-3"
|
|
188
220
|
type="button"
|
|
@@ -195,6 +227,8 @@ exports[`Button priorities renders tertiary buttons 1`] = `
|
|
|
195
227
|
exports[`Button sizes renders large buttons 1`] = `
|
|
196
228
|
<div>
|
|
197
229
|
<button
|
|
230
|
+
aria-busy="false"
|
|
231
|
+
aria-disabled="false"
|
|
198
232
|
aria-live="off"
|
|
199
233
|
class="btn btn-lg np-btn np-btn-lg btn-accent btn-priority-1"
|
|
200
234
|
type="button"
|
|
@@ -207,6 +241,8 @@ exports[`Button sizes renders large buttons 1`] = `
|
|
|
207
241
|
exports[`Button sizes renders medium buttons 1`] = `
|
|
208
242
|
<div>
|
|
209
243
|
<button
|
|
244
|
+
aria-busy="false"
|
|
245
|
+
aria-disabled="false"
|
|
210
246
|
aria-live="off"
|
|
211
247
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-1"
|
|
212
248
|
type="button"
|
|
@@ -219,6 +255,8 @@ exports[`Button sizes renders medium buttons 1`] = `
|
|
|
219
255
|
exports[`Button sizes renders small buttons 1`] = `
|
|
220
256
|
<div>
|
|
221
257
|
<button
|
|
258
|
+
aria-busy="false"
|
|
259
|
+
aria-disabled="false"
|
|
222
260
|
aria-live="off"
|
|
223
261
|
class="btn btn-sm np-btn np-btn-sm btn-accent btn-priority-1"
|
|
224
262
|
type="button"
|
|
@@ -231,6 +269,8 @@ exports[`Button sizes renders small buttons 1`] = `
|
|
|
231
269
|
exports[`Button types renders accent buttons 1`] = `
|
|
232
270
|
<div>
|
|
233
271
|
<button
|
|
272
|
+
aria-busy="false"
|
|
273
|
+
aria-disabled="false"
|
|
234
274
|
aria-live="off"
|
|
235
275
|
class="btn btn-md np-btn np-btn-md btn-accent btn-priority-1"
|
|
236
276
|
type="button"
|
|
@@ -243,6 +283,8 @@ exports[`Button types renders accent buttons 1`] = `
|
|
|
243
283
|
exports[`Button types renders negative buttons 1`] = `
|
|
244
284
|
<div>
|
|
245
285
|
<button
|
|
286
|
+
aria-busy="false"
|
|
287
|
+
aria-disabled="false"
|
|
246
288
|
aria-live="off"
|
|
247
289
|
class="btn btn-md np-btn np-btn-md btn-negative btn-priority-1"
|
|
248
290
|
type="button"
|
|
@@ -255,6 +297,8 @@ exports[`Button types renders negative buttons 1`] = `
|
|
|
255
297
|
exports[`Button types renders positive buttons 1`] = `
|
|
256
298
|
<div>
|
|
257
299
|
<button
|
|
300
|
+
aria-busy="false"
|
|
301
|
+
aria-disabled="false"
|
|
258
302
|
aria-live="off"
|
|
259
303
|
class="btn btn-md np-btn np-btn-md btn-positive btn-priority-1"
|
|
260
304
|
type="button"
|