@transferwise/components 0.0.0-experimental-75fc27b → 0.0.0-experimental-8a932bb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/build/avatarLayout/AvatarLayout.js +10 -2
  2. package/build/avatarLayout/AvatarLayout.js.map +1 -1
  3. package/build/avatarLayout/AvatarLayout.mjs +10 -2
  4. package/build/avatarLayout/AvatarLayout.mjs.map +1 -1
  5. package/build/button/Button/src/Button.js +93 -0
  6. package/build/button/Button/src/Button.js.map +1 -0
  7. package/build/button/Button/src/Button.mjs +91 -0
  8. package/build/button/Button/src/Button.mjs.map +1 -0
  9. package/build/button/{Button.js → LegacyButton/Button.js} +25 -24
  10. package/build/button/LegacyButton/Button.js.map +1 -0
  11. package/build/button/{Button.mjs → LegacyButton/Button.mjs} +25 -24
  12. package/build/button/LegacyButton/Button.mjs.map +1 -0
  13. package/build/button/LegacyButton/classMap.js +42 -0
  14. package/build/button/LegacyButton/classMap.js.map +1 -0
  15. package/build/button/LegacyButton/classMap.mjs +39 -0
  16. package/build/button/LegacyButton/classMap.mjs.map +1 -0
  17. package/build/button/{legacyUtils → LegacyButton/legacyUtils}/legacyUtils.js +21 -21
  18. package/build/button/LegacyButton/legacyUtils/legacyUtils.js.map +1 -0
  19. package/build/button/{legacyUtils → LegacyButton/legacyUtils}/legacyUtils.mjs +21 -21
  20. package/build/button/LegacyButton/legacyUtils/legacyUtils.mjs.map +1 -0
  21. package/build/button/src/Button.js +76 -0
  22. package/build/button/src/Button.js.map +1 -0
  23. package/build/button/src/Button.mjs +74 -0
  24. package/build/button/src/Button.mjs.map +1 -0
  25. package/build/circularButton/CircularButton.js +1 -1
  26. package/build/circularButton/CircularButton.js.map +1 -1
  27. package/build/circularButton/CircularButton.mjs +1 -1
  28. package/build/circularButton/CircularButton.mjs.map +1 -1
  29. package/build/common/action/Action.js +1 -1
  30. package/build/common/action/Action.js.map +1 -1
  31. package/build/common/action/Action.mjs +1 -1
  32. package/build/common/action/Action.mjs.map +1 -1
  33. package/build/criticalBanner/CriticalCommsBanner.js +1 -1
  34. package/build/criticalBanner/CriticalCommsBanner.mjs +1 -1
  35. package/build/header/Header.js +1 -1
  36. package/build/header/Header.mjs +1 -1
  37. package/build/index.js +1 -1
  38. package/build/index.mjs +1 -1
  39. package/build/link/Link.js +8 -3
  40. package/build/link/Link.js.map +1 -1
  41. package/build/link/Link.mjs +8 -3
  42. package/build/link/Link.mjs.map +1 -1
  43. package/build/main.css +288 -29
  44. package/build/nudge/Nudge.js +1 -1
  45. package/build/nudge/Nudge.js.map +1 -1
  46. package/build/nudge/Nudge.mjs +1 -1
  47. package/build/nudge/Nudge.mjs.map +1 -1
  48. package/build/select/Select.js +4 -2
  49. package/build/select/Select.js.map +1 -1
  50. package/build/select/Select.mjs +4 -2
  51. package/build/select/Select.mjs.map +1 -1
  52. package/build/styles/avatarLayout/AvatarLayout.css +11 -0
  53. package/build/styles/button/Button/less/Button.css +253 -0
  54. package/build/styles/button/Button/less/Button.vars.css +57 -0
  55. package/build/styles/iconButton/IconButton.css +24 -29
  56. package/build/styles/main.css +288 -29
  57. package/build/types/avatarLayout/AvatarLayout.d.ts +1 -2
  58. package/build/types/avatarLayout/AvatarLayout.d.ts.map +1 -1
  59. package/build/types/avatarLayout/index.d.ts +1 -0
  60. package/build/types/avatarLayout/index.d.ts.map +1 -1
  61. package/build/types/button/Button/index.d.ts +3 -0
  62. package/build/types/button/Button/index.d.ts.map +1 -0
  63. package/build/types/button/Button/src/Button.d.ts +4 -0
  64. package/build/types/button/Button/src/Button.d.ts.map +1 -0
  65. package/build/types/button/Button/src/Button.types.d.ts +50 -0
  66. package/build/types/button/Button/src/Button.types.d.ts.map +1 -0
  67. package/build/types/button/Button/src/index.d.ts +2 -0
  68. package/build/types/button/Button/src/index.d.ts.map +1 -0
  69. package/build/types/button/{Button.d.ts → LegacyButton/Button.d.ts} +6 -4
  70. package/build/types/button/LegacyButton/Button.d.ts.map +1 -0
  71. package/build/types/button/LegacyButton/classMap.d.ts.map +1 -0
  72. package/build/types/button/LegacyButton/index.d.ts +3 -0
  73. package/build/types/button/LegacyButton/index.d.ts.map +1 -0
  74. package/build/types/button/LegacyButton/legacyUtils/index.d.ts.map +1 -0
  75. package/build/types/button/{legacyUtils → LegacyButton/legacyUtils}/legacyUtils.d.ts +1 -1
  76. package/build/types/button/LegacyButton/legacyUtils/legacyUtils.d.ts.map +1 -0
  77. package/build/types/button/index.d.ts +2 -2
  78. package/build/types/button/index.d.ts.map +1 -1
  79. package/build/types/button/src/Button.d.ts +30 -0
  80. package/build/types/button/src/Button.d.ts.map +1 -0
  81. package/build/types/button/src/index.d.ts +3 -0
  82. package/build/types/button/src/index.d.ts.map +1 -0
  83. package/build/types/link/Link.d.ts +2 -2
  84. package/build/types/link/Link.d.ts.map +1 -1
  85. package/build/types/select/Select.d.ts.map +1 -1
  86. package/build/types/test-utils/index.d.ts.map +1 -1
  87. package/build/upload/steps/completeStep/completeStep.js +1 -1
  88. package/build/upload/steps/completeStep/completeStep.mjs +1 -1
  89. package/build/upload/steps/processingStep/processingStep.js +1 -1
  90. package/build/upload/steps/processingStep/processingStep.mjs +1 -1
  91. package/build/uploadInput/UploadInput.js +1 -1
  92. package/build/uploadInput/UploadInput.mjs +1 -1
  93. package/package.json +5 -5
  94. package/src/avatarLayout/AvatarLayout.css +11 -0
  95. package/src/avatarLayout/AvatarLayout.less +18 -1
  96. package/src/avatarLayout/AvatarLayout.story.tsx +2 -0
  97. package/src/avatarLayout/AvatarLayout.tsx +14 -4
  98. package/src/avatarLayout/index.ts +1 -0
  99. package/src/avatarWrapper/AvatarWrapper.story.tsx +2 -0
  100. package/src/button/Button/index.ts +2 -0
  101. package/src/button/Button/less/Button.css +253 -0
  102. package/src/button/Button/less/Button.less +221 -0
  103. package/src/button/Button/less/Button.vars.css +57 -0
  104. package/src/button/Button/less/Button.vars.less +65 -0
  105. package/src/button/Button/src/Button.tsx +116 -0
  106. package/src/button/Button/src/Button.types.ts +70 -0
  107. package/src/button/Button/src/index.ts +1 -0
  108. package/src/button/Button/stories/Button.story.tsx +314 -0
  109. package/src/button/Button/stories/Button.tests.story.tsx +288 -0
  110. package/src/button/Button/test/Button.spec.tsx +328 -0
  111. package/src/button/{Button.less → LegacyButton/Button.less} +1 -1
  112. package/src/button/{Button.spec.tsx → LegacyButton/Button.spec.tsx} +3 -3
  113. package/src/button/LegacyButton/Button.story.tsx +224 -0
  114. package/src/button/{Button.tsx → LegacyButton/Button.tsx} +12 -8
  115. package/src/button/{classMap.ts → LegacyButton/classMap.ts} +1 -1
  116. package/src/button/LegacyButton/index.ts +3 -0
  117. package/src/button/{legacyUtils → LegacyButton/legacyUtils}/legacyUtils.spec.tsx +2 -2
  118. package/src/button/{legacyUtils → LegacyButton/legacyUtils}/legacyUtils.ts +2 -2
  119. package/src/button/index.ts +2 -3
  120. package/src/button/src/Button.tsx +118 -0
  121. package/src/button/src/index.ts +2 -0
  122. package/src/button/test/Button.spec.tsx +66 -0
  123. package/src/circularButton/CircularButton.tsx +1 -1
  124. package/src/common/action/Action.tsx +1 -1
  125. package/src/iconButton/IconButton.css +24 -29
  126. package/src/iconButton/IconButton.less +4 -4
  127. package/src/link/Link.tsx +15 -6
  128. package/src/main.css +288 -29
  129. package/src/main.less +2 -1
  130. package/src/nudge/Nudge.tsx +1 -1
  131. package/src/primitives/PrimitiveAnchor/stories/PrimitiveAnchor.story.tsx +1 -1
  132. package/src/primitives/PrimitiveAnchor/test/PrimitiveAnchor.spec.tsx +1 -1
  133. package/src/primitives/PrimitiveButton/stories/PrimitiveButton.story.tsx +1 -1
  134. package/src/primitives/PrimitiveButton/test/PrimitiveButton.spec.tsx +2 -3
  135. package/src/select/Select.tsx +1 -0
  136. package/src/test-utils/index.tsx +0 -1
  137. package/build/button/Button.js.map +0 -1
  138. package/build/button/Button.mjs.map +0 -1
  139. package/build/button/classMap.js +0 -42
  140. package/build/button/classMap.js.map +0 -1
  141. package/build/button/classMap.mjs +0 -39
  142. package/build/button/classMap.mjs.map +0 -1
  143. package/build/button/legacyUtils/legacyUtils.js.map +0 -1
  144. package/build/button/legacyUtils/legacyUtils.mjs.map +0 -1
  145. package/build/types/button/Button.d.ts.map +0 -1
  146. package/build/types/button/classMap.d.ts.map +0 -1
  147. package/build/types/button/legacyUtils/index.d.ts.map +0 -1
  148. package/build/types/button/legacyUtils/legacyUtils.d.ts.map +0 -1
  149. package/src/button/Button.story.tsx +0 -163
  150. /package/build/styles/button/{Button.css → LegacyButton/Button.css} +0 -0
  151. /package/build/types/button/{classMap.d.ts → LegacyButton/classMap.d.ts} +0 -0
  152. /package/build/types/button/{legacyUtils → LegacyButton/legacyUtils}/index.d.ts +0 -0
  153. /package/src/button/{Button.css → LegacyButton/Button.css} +0 -0
  154. /package/src/button/{__snapshots__ → LegacyButton/__snapshots__}/Button.spec.tsx.snap +0 -0
  155. /package/src/button/{legacyUtils → LegacyButton/legacyUtils}/index.ts +0 -0
@@ -0,0 +1,328 @@
1
+ import { fireEvent, screen } from '@testing-library/react';
2
+ import { userEvent } from '@testing-library/user-event';
3
+ import Button from '..';
4
+ import messages from '../../../i18n/commonMessages/Button.messages';
5
+ import { render } from '../../../test-utils';
6
+ import { Freeze, ArrowRight } from '@transferwise/icons';
7
+
8
+ beforeAll(() => {
9
+ Object.defineProperty(window, 'matchMedia', {
10
+ writable: true,
11
+ value: jest.fn().mockImplementation((query: string) => ({
12
+ matches: false,
13
+ media: query,
14
+ onchange: null,
15
+ addListener: jest.fn(), // deprecated
16
+ removeListener: jest.fn(), // deprecated
17
+ addEventListener: jest.fn(),
18
+ removeEventListener: jest.fn(),
19
+ dispatchEvent: jest.fn(),
20
+ })),
21
+ });
22
+ });
23
+
24
+ describe('Button', () => {
25
+ const defaultProps = {
26
+ children: 'Click me',
27
+ };
28
+
29
+ const renderButton = (
30
+ props?: Partial<typeof defaultProps>,
31
+ locale = 'en',
32
+ localeMessages = messages,
33
+ ) => {
34
+ return render(
35
+ <Button {...defaultProps} {...props} />,
36
+ // @ts-expect-error: props be missing properties from type
37
+ { locale, messages: localeMessages },
38
+ );
39
+ };
40
+
41
+ it('renders a button by default', () => {
42
+ renderButton();
43
+ expect(screen.getByRole('button')).toBeInTheDocument();
44
+ expect(screen.getByRole('button')).toHaveTextContent('Click me');
45
+ });
46
+
47
+ it('applies the correct classes based on props', () => {
48
+ const props = {
49
+ ...defaultProps,
50
+ className: 'custom-class',
51
+ };
52
+
53
+ renderButton(props);
54
+
55
+ const button = screen.getByRole('button');
56
+ expect(button).toHaveClass('wds-Button');
57
+ expect(button).toHaveClass('custom-class');
58
+ });
59
+
60
+ it('disables the button when disabled is true', () => {
61
+ const props = {
62
+ ...defaultProps,
63
+ disabled: true,
64
+ };
65
+
66
+ renderButton(props);
67
+
68
+ const button = screen.getByRole('button');
69
+ expect(button).toHaveClass('wds-Button--disabled');
70
+ expect(button).toBeDisabled();
71
+ });
72
+
73
+ it('calls onClick when button is clicked', async () => {
74
+ const handleClick = jest.fn();
75
+ const props = {
76
+ ...defaultProps,
77
+ onClick: handleClick,
78
+ };
79
+
80
+ renderButton(props);
81
+
82
+ const button = screen.getByRole('button');
83
+ await userEvent.click(button);
84
+ expect(handleClick).toHaveBeenCalledTimes(1);
85
+ });
86
+
87
+ it('calls onFocus when button is focused', () => {
88
+ const handleFocus = jest.fn();
89
+ const props = {
90
+ ...defaultProps,
91
+ onFocus: handleFocus,
92
+ };
93
+
94
+ renderButton(props);
95
+
96
+ const button = screen.getByRole('button');
97
+ fireEvent.focus(button);
98
+ expect(handleFocus).toHaveBeenCalledTimes(1);
99
+ });
100
+
101
+ it('calls onKeyDown when a key is pressed', async () => {
102
+ const handleKeyDown = jest.fn();
103
+ const props = {
104
+ ...defaultProps,
105
+ onKeyDown: handleKeyDown,
106
+ };
107
+
108
+ renderButton(props);
109
+
110
+ const button = screen.getByRole('button');
111
+ await userEvent.type(button, '{enter}');
112
+ expect(handleKeyDown).toHaveBeenCalledTimes(1);
113
+ });
114
+
115
+ it('calls onBlur when button loses focus', () => {
116
+ const handleBlur = jest.fn();
117
+ const props = {
118
+ ...defaultProps,
119
+ onBlur: handleBlur,
120
+ };
121
+
122
+ renderButton(props);
123
+
124
+ const button = screen.getByRole('button');
125
+ fireEvent.blur(button);
126
+ expect(handleBlur).toHaveBeenCalledTimes(1);
127
+ });
128
+
129
+ it('calls onMouseEnter when mouse enters', async () => {
130
+ const handleMouseEnter = jest.fn();
131
+ const props = {
132
+ ...defaultProps,
133
+ onMouseEnter: handleMouseEnter,
134
+ };
135
+
136
+ renderButton(props);
137
+
138
+ const button = screen.getByRole('button');
139
+ await userEvent.hover(button);
140
+ expect(handleMouseEnter).toHaveBeenCalledTimes(1);
141
+ });
142
+
143
+ it('calls onMouseLeave when mouse leaves', async () => {
144
+ const handleMouseLeave = jest.fn();
145
+ const props = {
146
+ ...defaultProps,
147
+ onMouseLeave: handleMouseLeave,
148
+ };
149
+
150
+ renderButton(props);
151
+
152
+ const button = screen.getByRole('button');
153
+ await userEvent.unhover(button);
154
+ expect(handleMouseLeave).toHaveBeenCalledTimes(1);
155
+ });
156
+
157
+ it('sets data-testid attribute', () => {
158
+ const props = {
159
+ ...defaultProps,
160
+ testId: 'custom-id',
161
+ };
162
+
163
+ renderButton(props);
164
+
165
+ const button = screen.getByTestId('custom-id');
166
+ expect(button).toBeInTheDocument();
167
+ });
168
+
169
+ it('sets the type attribute to submit', () => {
170
+ const props = {
171
+ ...defaultProps,
172
+ type: 'submit',
173
+ };
174
+
175
+ renderButton(props);
176
+
177
+ const button = screen.getByRole('button');
178
+ expect(button).toHaveAttribute('type', 'submit');
179
+ });
180
+
181
+ it('sets the type attribute to reset', () => {
182
+ const props = {
183
+ ...defaultProps,
184
+ type: 'reset',
185
+ };
186
+
187
+ renderButton(props);
188
+
189
+ const button = screen.getByRole('button');
190
+ expect(button).toHaveAttribute('type', 'reset');
191
+ });
192
+
193
+ it('sets the type attribute to button by default', () => {
194
+ renderButton();
195
+ const button = screen.getByRole('button');
196
+ expect(button).toHaveAttribute('type', 'button');
197
+ });
198
+
199
+ it('displays the aria-label in Spanish when loading', () => {
200
+ const props = {
201
+ ...defaultProps,
202
+ loading: true,
203
+ };
204
+
205
+ const spanishMessages = {
206
+ ...messages,
207
+ 'neptune.Button.loadingAriaLabel': 'cargando',
208
+ };
209
+
210
+ renderButton(props, 'es', spanishMessages);
211
+
212
+ const button = screen.getByRole('button');
213
+ expect(button).toHaveAttribute('aria-label', 'cargando');
214
+ });
215
+
216
+ it('displays with one avatar', () => {
217
+ const props = {
218
+ ...defaultProps,
219
+ avatars: [{ asset: <Freeze /> }],
220
+ };
221
+
222
+ renderButton(props);
223
+
224
+ const avatar = screen.getByTestId('freeze-icon');
225
+ expect(avatar).toBeInTheDocument();
226
+ });
227
+
228
+ it('displays with one avatar and no left icon', () => {
229
+ const props = {
230
+ ...defaultProps,
231
+ avatars: [{ asset: <Freeze /> }],
232
+ iconLeft: ArrowRight,
233
+ };
234
+
235
+ renderButton(props);
236
+
237
+ const avatar = screen.getByTestId('freeze-icon');
238
+
239
+ expect(avatar).toBeInTheDocument();
240
+ expect(screen.queryByTestId('arrow-left-icon')).not.toBeInTheDocument();
241
+ });
242
+
243
+ it('displays with two avatars', () => {
244
+ const props = {
245
+ ...defaultProps,
246
+ avatars: [{ asset: <Freeze /> }, { asset: <Freeze /> }],
247
+ };
248
+
249
+ renderButton(props);
250
+
251
+ const avatars = screen.getAllByTestId('freeze-icon');
252
+ avatars.forEach((avatar) => {
253
+ expect(avatar).toBeInTheDocument();
254
+ });
255
+ });
256
+
257
+ it('displays with avatar and icon', () => {
258
+ const props = {
259
+ ...defaultProps,
260
+ avatars: [{ asset: <Freeze /> }],
261
+ iconRight: ArrowRight,
262
+ };
263
+
264
+ renderButton(props);
265
+
266
+ const iconRight = screen.getByTestId('arrow-right-icon');
267
+ const avatar = screen.getByTestId('freeze-icon');
268
+
269
+ expect(avatar).toBeInTheDocument();
270
+ expect(iconRight).toHaveClass('wds-Button-icon');
271
+ expect(iconRight).toHaveClass('wds-Button-icon--right');
272
+ });
273
+
274
+ it('displays with a profile name', () => {
275
+ const props = {
276
+ ...defaultProps,
277
+ avatars: [{ profileName: 'John Doe' }],
278
+ };
279
+
280
+ renderButton(props);
281
+
282
+ const avatar = screen.getByText('JD');
283
+ expect(avatar).toBeInTheDocument();
284
+ });
285
+
286
+ it('displays with a profile image', () => {
287
+ const props = {
288
+ ...defaultProps,
289
+ avatars: [{ imgSrc: '../avatar-rectangle-fox.webp' }],
290
+ };
291
+
292
+ renderButton(props);
293
+
294
+ const avatar = screen.getByRole('presentation');
295
+ expect(avatar).toHaveAttribute('src', '../avatar-rectangle-fox.webp');
296
+ });
297
+
298
+ it('displays with one icon', () => {
299
+ const props = {
300
+ ...defaultProps,
301
+ iconRight: ArrowRight,
302
+ };
303
+
304
+ renderButton(props);
305
+
306
+ const iconRight = screen.getByTestId('arrow-right-icon');
307
+ expect(iconRight).toHaveClass('wds-Button-icon');
308
+ expect(iconRight).toHaveClass('wds-Button-icon--right');
309
+ });
310
+
311
+ it('displays with two icons', () => {
312
+ const props = {
313
+ ...defaultProps,
314
+ iconRight: ArrowRight,
315
+ iconLeft: Freeze,
316
+ };
317
+
318
+ renderButton(props);
319
+
320
+ const iconRight = screen.getByTestId('arrow-right-icon');
321
+ const iconLeft = screen.getByTestId('freeze-icon');
322
+
323
+ expect(iconRight).toHaveClass('wds-Button-icon');
324
+ expect(iconRight).toHaveClass('wds-Button-icon--right');
325
+ expect(iconLeft).toHaveClass('wds-Button-icon');
326
+ expect(iconLeft).toHaveClass('wds-Button-icon--left');
327
+ });
328
+ });
@@ -1,4 +1,4 @@
1
- @import (reference) "../../node_modules/@transferwise/neptune-css/src/less/mixins/_logical-properties.less";
1
+ @import (reference) "../../../node_modules/@transferwise/neptune-css/src/less/mixins/_logical-properties.less";
2
2
 
3
3
  .np-btn {
4
4
  position: relative;
@@ -1,10 +1,10 @@
1
1
  import { createRef } from 'react';
2
2
 
3
- import { ControlType, Type, Priority, Size } from '../common';
4
- import { render, screen, userEvent } from '../test-utils';
3
+ import { ControlType, Type, Priority, Size } from '../../common';
4
+ import { render, screen, userEvent } from '../../test-utils';
5
5
 
6
6
  import Button from '.';
7
- import messages from '../i18n/commonMessages/Button.messages';
7
+ import messages from '../../i18n/commonMessages/Button.messages';
8
8
  import { ButtonReferenceType } from './Button';
9
9
 
10
10
  const { ACCENT, POSITIVE, NEGATIVE } = ControlType;
@@ -0,0 +1,224 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { userEvent, within, fn, expect } from '@storybook/test';
3
+ import { useState } from 'react';
4
+
5
+ import Button from '..';
6
+
7
+ const withContainer = (Story: any) => (
8
+ <div
9
+ style={{
10
+ display: 'flex',
11
+ flexDirection: 'initial',
12
+ justifyContent: 'center',
13
+ flexFlow: 'column',
14
+ alignItems: 'center',
15
+ }}
16
+ >
17
+ <Story />
18
+ </div>
19
+ );
20
+
21
+ const meta: Meta<typeof Button> = {
22
+ component: Button,
23
+ title: 'Actions/Button/Legacy',
24
+ args: {
25
+ children: 'Button text',
26
+ loading: false,
27
+ type: undefined,
28
+ onClick: fn(),
29
+ onBlur: fn(),
30
+ onFocus: fn(),
31
+ href: 'https://example.com',
32
+ },
33
+ argTypes: {
34
+ as: {
35
+ control: {
36
+ type: 'select',
37
+ options: ['button', 'a'],
38
+ },
39
+ },
40
+ type: {
41
+ type: {
42
+ name: 'enum',
43
+ value: ['accent', 'positive', 'negative'],
44
+ },
45
+ },
46
+ size: {
47
+ type: {
48
+ name: 'enum',
49
+ value: ['xs', 'sm', 'md', 'lg'],
50
+ },
51
+ },
52
+ priority: {
53
+ type: {
54
+ name: 'enum',
55
+ value: ['primary', 'secondary', 'tertiary'],
56
+ },
57
+ },
58
+ appearance: {
59
+ table: {
60
+ disable: true,
61
+ },
62
+ },
63
+ iconLeft: {
64
+ table: {
65
+ disable: true,
66
+ },
67
+ },
68
+ iconRight: {
69
+ table: {
70
+ disable: true,
71
+ },
72
+ },
73
+ avatars: {
74
+ table: {
75
+ disable: true,
76
+ },
77
+ },
78
+ 'data-testid': {
79
+ table: {
80
+ disable: true,
81
+ },
82
+ },
83
+ },
84
+ tags: ['autodocs'],
85
+ decorators: [withContainer],
86
+ };
87
+
88
+ export default meta;
89
+
90
+ type Story = StoryObj<typeof Button>;
91
+
92
+ export const Basic: Story = {};
93
+
94
+ export const Secondary: Story = {
95
+ args: {
96
+ type: 'accent',
97
+ priority: 'secondary',
98
+ },
99
+ };
100
+
101
+ export const Tertiary: Story = {
102
+ args: {
103
+ type: 'accent',
104
+ priority: 'tertiary',
105
+ },
106
+ };
107
+
108
+ export const Negative: Story = {
109
+ args: {
110
+ type: 'negative',
111
+ priority: 'primary',
112
+ },
113
+ };
114
+
115
+ export const Loading: Story = {
116
+ args: {
117
+ loading: true,
118
+ },
119
+ };
120
+
121
+ export const Variants: Story = {
122
+ render: () => {
123
+ return (
124
+ <div className="d-flex flex-column p-b-2 align-items-start">
125
+ <div className="d-flex flex-row p-b-2" style={{ gap: 'var(--size-16)' }}>
126
+ <Button type="accent" priority="primary">
127
+ Primary Accent
128
+ </Button>
129
+ <Button type="accent" priority="secondary">
130
+ Secondary Accent
131
+ </Button>
132
+ <Button type="accent" priority="tertiary">
133
+ Tertiary Accent
134
+ </Button>
135
+ </div>
136
+ <div className="d-flex flex-row p-b-2" style={{ gap: 'var(--size-16)' }}>
137
+ <Button type="positive" priority="primary">
138
+ Primary Positive
139
+ </Button>
140
+ <Button type="positive" priority="secondary">
141
+ Secondary Accent
142
+ </Button>
143
+ </div>
144
+ <div className="d-flex flex-row flex- p-b-2" style={{ gap: 'var(--size-16)' }}>
145
+ <Button type="negative" priority="primary">
146
+ Primary Negative
147
+ </Button>
148
+ <Button type="negative" priority="secondary">
149
+ Secondary Negative
150
+ </Button>
151
+ </div>
152
+ <div className="d-flex flex-row p-b-1" style={{ gap: 'var(--size-16)' }}>
153
+ <Button type="accent" priority="primary" disabled>
154
+ Button Disabled
155
+ </Button>
156
+ <Button type="accent" priority="secondary" disabled>
157
+ Button Disabled
158
+ </Button>
159
+ <Button type="accent" priority="tertiary" disabled>
160
+ Button Disabled
161
+ </Button>
162
+ </div>
163
+ </div>
164
+ );
165
+ },
166
+ };
167
+
168
+ const wait = async (duration = 500) =>
169
+ new Promise<void>((resolve) => {
170
+ setTimeout(resolve, duration);
171
+ });
172
+
173
+ export const Focused: Story = {
174
+ play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
175
+ const canvas = within(canvasElement);
176
+ const button = canvas.getByRole('button');
177
+ await userEvent.tab();
178
+ await expect(button).toHaveFocus();
179
+ await expect(button).toHaveTextContent('Focused!');
180
+ },
181
+ render: function Render(args: React.ComponentProps<typeof Button>) {
182
+ const [focused, setFocused] = useState(false);
183
+
184
+ return (
185
+ <Button {...args} onFocus={() => setFocused(true)}>
186
+ {focused ? 'Focused!' : 'Button text'}
187
+ </Button>
188
+ );
189
+ },
190
+ };
191
+
192
+ export const SocialMedia: Story = {
193
+ render: () => {
194
+ return (
195
+ <>
196
+ <div className="m-b-2">
197
+ <button type="button" className="btn btn-google">
198
+ Login with Google
199
+ </button>
200
+ </div>
201
+ <div className="m-b-2">
202
+ <button type="button" className="btn btn-facebook">
203
+ Login with Facebook
204
+ </button>
205
+ </div>
206
+ <div className="m-b-2">
207
+ <button type="button" className="btn btn-lg btn-facebook">
208
+ Large Button
209
+ </button>
210
+ </div>
211
+ <div className="m-b-2">
212
+ <button type="button" className="btn btn-block btn-facebook">
213
+ Block Button
214
+ </button>
215
+ </div>
216
+ <div className="m-b-2">
217
+ <button type="button" className="btn btn-lg btn-block btn-facebook">
218
+ Large Block Button
219
+ </button>
220
+ </div>
221
+ </>
222
+ );
223
+ },
224
+ };
@@ -16,10 +16,10 @@ import {
16
16
  SizeSmall,
17
17
  SizeMedium,
18
18
  SizeLarge,
19
- } from '../common';
20
- import ProcessIndicator from '../processIndicator';
19
+ } from '../../common';
20
+ import ProcessIndicator from '../../processIndicator';
21
21
 
22
- import messages from '../i18n/commonMessages/Button.messages';
22
+ import messages from '../../i18n/commonMessages/Button.messages';
23
23
  import { typeClassMap, priorityClassMap } from './classMap';
24
24
  import { establishNewPriority, establishNewType, logDeprecationNotices } from './legacyUtils';
25
25
 
@@ -33,20 +33,22 @@ type CommonProps = {
33
33
  block?: boolean;
34
34
  disabled?: boolean;
35
35
  loading?: boolean;
36
+ /** @deprecated */
36
37
  type?: ControlTypeAccent | ControlTypeNegative | ControlTypePositive | DeprecatedTypes | null;
37
38
  priority?: PriorityPrimary | PrioritySecondary | PriorityTertiary | null;
38
39
  size?: SizeSmall | SizeMedium | SizeLarge | DeprecatedSizes;
40
+ htmlType?: 'submit' | 'reset' | 'button'; // Add this line
39
41
  };
40
42
 
41
- type ButtonProps = CommonProps &
43
+ export type ButtonProps = CommonProps &
42
44
  Omit<React.ComponentPropsWithRef<'button'>, 'type'> & {
43
45
  as?: 'button';
44
- htmlType?: 'submit' | 'reset' | 'button';
45
46
  };
46
47
 
47
- type AnchorProps = CommonProps &
48
+ export type AnchorProps = CommonProps &
48
49
  Omit<React.ComponentPropsWithRef<'a'>, 'type'> & {
49
50
  as?: 'a';
51
+ href?: string;
50
52
  };
51
53
 
52
54
  export type Props = ButtonProps | AnchorProps;
@@ -68,7 +70,7 @@ const Button = forwardRef<ButtonReferenceType, Props>(
68
70
  onClick,
69
71
  ...rest
70
72
  }: Props,
71
- reference,
73
+ ref,
72
74
  ) => {
73
75
  const intl = useIntl();
74
76
 
@@ -132,7 +134,7 @@ const Button = forwardRef<ButtonReferenceType, Props>(
132
134
 
133
135
  return (
134
136
  <Element
135
- ref={reference}
137
+ ref={ref as React.Ref<ButtonReferenceType>}
136
138
  className={classes}
137
139
  onClick={handleClick(onClick)}
138
140
  {...props}
@@ -153,4 +155,6 @@ const Button = forwardRef<ButtonReferenceType, Props>(
153
155
  },
154
156
  );
155
157
 
158
+ Button.displayName = 'Button';
159
+
156
160
  export default Button;
@@ -1,4 +1,4 @@
1
- import { ControlType, Priority } from '../common';
1
+ import { ControlType, Priority } from '../../common';
2
2
 
3
3
  export const typeClassMap = {
4
4
  [ControlType.ACCENT]: 'btn-accent',
@@ -0,0 +1,3 @@
1
+ export { default } from './Button';
2
+
3
+ export type { Props as ButtonProps } from './Button';
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-console */
2
- import { ControlType, Priority, Size, Type } from '../../common';
3
- import { cleanup } from '../../test-utils';
2
+ import { ControlType, Priority, Size, Type } from '../../../common';
3
+ import { cleanup } from '../../../test-utils';
4
4
 
5
5
  import { establishNewPriority, establishNewType, logDeprecationNotices } from '.';
6
6
 
@@ -1,5 +1,5 @@
1
- import { ControlType, Priority, Size, Type } from '../../common';
2
- import { logActionRequired, logActionRequiredIf } from '../../utilities';
1
+ import { ControlType, Priority, Size, Type } from '../../../common';
2
+ import { logActionRequired, logActionRequiredIf } from '../../../utilities';
3
3
 
4
4
  const deprecatedTypeMap: Record<Type, ControlType> = {
5
5
  [Type.PRIMARY]: ControlType.ACCENT,
@@ -1,3 +1,2 @@
1
- export { default } from './Button';
2
-
3
- export type { Props as ButtonProps } from './Button';
1
+ export { default } from './src';
2
+ export * from './src';