@transferwise/components 0.0.0-experimental-ffbd2fc → 0.0.0-experimental-d211fa1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-ffbd2fc",
3
+ "version": "0.0.0-experimental-d211fa1",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react';
2
- import { action } from 'storybook/actions';
2
+ import { fn } from 'storybook/test';
3
3
  import { Meta, StoryObj } from '@storybook/react-webpack5';
4
4
 
5
5
  import CheckboxButton from './CheckboxButton';
@@ -24,9 +24,9 @@ export default {
24
24
 
25
25
  args: {
26
26
  disabled: false,
27
- onBlur: action('blur'),
28
- onClick: action('click'),
29
- onFocus: action('focus'),
27
+ onBlur: fn(),
28
+ onClick: fn(),
29
+ onFocus: fn(),
30
30
  },
31
31
  parameters: {
32
32
  docs: { toc: true },
@@ -3,7 +3,6 @@ import type { Meta, StoryObj } from '@storybook/react-webpack5';
3
3
  import { expect, userEvent, within } from 'storybook/test';
4
4
 
5
5
  import { withVariantConfig } from '../../.storybook/helpers';
6
- import { allModes } from '../../.storybook/modes';
7
6
  import CheckboxButton from './CheckboxButton';
8
7
 
9
8
  export default {
@@ -35,31 +34,7 @@ export const Variants: Story = {
35
34
  <CheckboxButton aria-label="Disabled checked" checked disabled onChange={() => {}} />
36
35
  </div>
37
36
  ),
38
- parameters: {
39
- variants: ['default', 'dark', 'bright-green', 'forest-green'],
40
- chromatic: {
41
- dark: allModes.dark,
42
- brightGreen: allModes.brightGreen,
43
- forestGreen: allModes.forestGreen,
44
- },
45
- },
46
- };
47
-
48
- /** Checkbox states at 400% zoom for accessibility testing. */
49
- export const Zoom400: Story = {
50
- render: () => (
51
- <div style={{ display: 'flex', gap: '16px', alignItems: 'center', padding: '16px' }}>
52
- <CheckboxButton aria-label="Unchecked" checked={false} onChange={() => {}} />
53
- <CheckboxButton aria-label="Checked" checked onChange={() => {}} />
54
- <CheckboxButton
55
- aria-label="Indeterminate"
56
- checked={false}
57
- indeterminate
58
- onChange={() => {}}
59
- />
60
- </div>
61
- ),
62
- ...withVariantConfig(['400%']),
37
+ ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green']),
63
38
  };
64
39
 
65
40
  /** Tab through all checkbox variants and toggle each on and off. */
@@ -189,3 +164,20 @@ export const KeyboardInteraction: Story = {
189
164
  });
190
165
  },
191
166
  };
167
+
168
+ /** Checkbox states at 400% zoom for accessibility testing. */
169
+ export const Zoom400: Story = {
170
+ render: () => (
171
+ <div style={{ display: 'flex', gap: '16px', alignItems: 'center', padding: '16px' }}>
172
+ <CheckboxButton aria-label="Unchecked" checked={false} onChange={() => {}} />
173
+ <CheckboxButton aria-label="Checked" checked onChange={() => {}} />
174
+ <CheckboxButton
175
+ aria-label="Indeterminate"
176
+ checked={false}
177
+ indeterminate
178
+ onChange={() => {}}
179
+ />
180
+ </div>
181
+ ),
182
+ ...withVariantConfig(['400%']),
183
+ };
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { fn } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
- import Chips, { type ChipValue } from './Chips';
5
+ import Chips, { type ChipValue, type ChipsProps } from './Chips';
6
6
 
7
7
  /**
8
8
  * Chips allow users to filter content or make a choice from a set of options
@@ -24,6 +24,7 @@ export default {
24
24
  component: Chips,
25
25
  title: 'Actions/Chips',
26
26
  args: {
27
+ multiple: false,
27
28
  onChange: fn(),
28
29
  },
29
30
  argTypes: {
@@ -56,7 +57,11 @@ const amountChips = [
56
57
  * and choice (single-select) modes.
57
58
  */
58
59
  export const Playground: Story = {
59
- render: function Render({ onChange, chips, multiple }) {
60
+ render: function Render({
61
+ onChange,
62
+ chips,
63
+ multiple,
64
+ }: Pick<ChipsProps, 'onChange' | 'chips' | 'multiple'>) {
60
65
  const [selectedMulti, setSelectedMulti] = useState<readonly ChipValue[]>(['accounting']);
61
66
  const [selectedSingle, setSelectedSingle] = useState<ChipValue>('accounting');
62
67
 
@@ -100,12 +105,12 @@ export const Playground: Story = {
100
105
  * results by one or more categories — e.g. an app marketplace or payment list.
101
106
  */
102
107
  export const Filter: Story = {
103
- render: function Render({ onChange, ...args }) {
108
+ render: function Render({ onChange, chips }: Pick<ChipsProps, 'onChange' | 'chips'>) {
104
109
  const [selected, setSelected] = useState<readonly ChipValue[]>(['accounting', 'payments']);
105
110
 
106
111
  return (
107
112
  <Chips
108
- {...args}
113
+ chips={chips}
109
114
  selected={selected}
110
115
  multiple
111
116
  aria-label="Category filter"
@@ -121,6 +126,9 @@ export const Filter: Story = {
121
126
  args: {
122
127
  chips: categoryChips,
123
128
  },
129
+ argTypes: {
130
+ multiple: { table: { disable: true } },
131
+ },
124
132
  parameters: {
125
133
  docs: {
126
134
  source: {
@@ -157,12 +165,12 @@ export const Filter: Story = {
157
165
  * Useful for selecting a single value from a small set, such as a transfer amount.
158
166
  */
159
167
  export const Choice: Story = {
160
- render: function Render({ onChange, ...args }) {
168
+ render: function Render({ onChange, chips }: Pick<ChipsProps, 'onChange' | 'chips'>) {
161
169
  const [selected, setSelected] = useState<ChipValue>(300);
162
170
 
163
171
  return (
164
172
  <Chips
165
- {...args}
173
+ chips={chips}
166
174
  selected={selected}
167
175
  aria-label="Transfer amount"
168
176
  onChange={({ selectedValue, isEnabled }) => {
@@ -175,6 +183,9 @@ export const Choice: Story = {
175
183
  args: {
176
184
  chips: amountChips,
177
185
  },
186
+ argTypes: {
187
+ multiple: { table: { disable: true } },
188
+ },
178
189
  parameters: {
179
190
  docs: {
180
191
  source: {
@@ -3,7 +3,6 @@ import { userEvent } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { withVariantConfig } from '../../.storybook/helpers';
6
- import { allModes } from '../../.storybook/modes';
7
6
  import Chips, { type ChipValue } from './Chips';
8
7
 
9
8
  export default {
@@ -64,35 +63,7 @@ export const Variants: Story = {
64
63
  </div>
65
64
  );
66
65
  },
67
- parameters: {
68
- variants: ['default', 'dark', 'bright-green', 'forest-green'],
69
- chromatic: {
70
- dark: allModes.dark,
71
- brightGreen: allModes.brightGreen,
72
- forestGreen: allModes.forestGreen,
73
- },
74
- },
75
- };
76
-
77
- /** Filter chips at 400% zoom for accessibility testing. */
78
- export const Zoom400: Story = {
79
- render: function Render() {
80
- const [selected, setSelected] = useState<readonly ChipValue[]>(['accounting']);
81
- return (
82
- <Chips
83
- chips={filterChips}
84
- multiple
85
- selected={selected}
86
- aria-label="Category filter"
87
- onChange={({ selectedValue, isEnabled }) => {
88
- setSelected((prev) =>
89
- isEnabled ? [...prev, selectedValue] : prev.filter((v) => v !== selectedValue),
90
- );
91
- }}
92
- />
93
- );
94
- },
95
- ...withVariantConfig(['400%']),
66
+ ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green']),
96
67
  };
97
68
 
98
69
  /** Tab through choice chips and select one with Enter. */
@@ -145,3 +116,24 @@ export const FilterKeyboardInteraction: Story = {
145
116
  await userEvent.keyboard('{Enter}');
146
117
  },
147
118
  };
119
+
120
+ /** Filter chips at 400% zoom for accessibility testing. */
121
+ export const Zoom400: Story = {
122
+ render: function Render() {
123
+ const [selected, setSelected] = useState<readonly ChipValue[]>(['accounting']);
124
+ return (
125
+ <Chips
126
+ chips={filterChips}
127
+ multiple
128
+ selected={selected}
129
+ aria-label="Category filter"
130
+ onChange={({ selectedValue, isEnabled }) => {
131
+ setSelected((prev) =>
132
+ isEnabled ? [...prev, selectedValue] : prev.filter((v) => v !== selectedValue),
133
+ );
134
+ }}
135
+ />
136
+ );
137
+ },
138
+ ...withVariantConfig(['400%']),
139
+ };
@@ -1,9 +1,9 @@
1
1
  import * as Icons from '@transferwise/icons';
2
2
 
3
3
  import { Meta, StoryObj } from '@storybook/react-webpack5';
4
+ import { fn } from 'storybook/test';
4
5
  import CircularButton from './CircularButton';
5
6
  import Title from '../title';
6
- import Body from '../body';
7
7
 
8
8
  /**
9
9
  * A circular icon button with a text label below it. Use when the user can perform
@@ -28,6 +28,7 @@ export default {
28
28
  args: {
29
29
  children: 'Button text',
30
30
  icon: <Icons.Freeze />,
31
+ onClick: fn(),
31
32
  },
32
33
  argTypes: {
33
34
  icon: {
@@ -55,51 +56,88 @@ export const Playground: Story = {
55
56
 
56
57
  /** All priority × type combinations, including deprecated types. */
57
58
  export const AllTypes: Story = {
58
- args: {
59
- className: 'm-r-2',
60
- },
61
- render: (props) => {
59
+ render: () => {
60
+ const gridStyle = {
61
+ display: 'grid',
62
+ gridTemplateColumns: 'repeat(4, minmax(0, 100px))',
63
+ gap: '16px',
64
+ textAlign: 'center' as const,
65
+ };
66
+ const icon = <Icons.Freeze />;
67
+
62
68
  return (
63
69
  <>
64
70
  <Title type="title-subsection" className="m-y-2">
65
71
  Default (Primary and secondary)
66
72
  </Title>
67
- <Body>
68
- <CircularButton {...props} priority="primary" type="default" />
69
- <CircularButton {...props} priority="secondary" type="default" />
70
- <CircularButton {...props} priority="primary" type="default" disabled />
71
- <CircularButton {...props} priority="secondary" type="default" disabled />
72
- </Body>
73
+ <div style={gridStyle}>
74
+ <CircularButton icon={icon} priority="primary" type="default">
75
+ Primary
76
+ </CircularButton>
77
+ <CircularButton icon={icon} priority="secondary" type="default">
78
+ Secondary
79
+ </CircularButton>
80
+ <CircularButton disabled icon={icon} priority="primary" type="default">
81
+ Primary disabled
82
+ </CircularButton>
83
+ <CircularButton disabled icon={icon} priority="secondary" type="default">
84
+ Secondary disabled
85
+ </CircularButton>
86
+ </div>
73
87
 
74
88
  <Title type="title-subsection" className="m-y-2">
75
89
  Negative (Primary and secondary)
76
90
  </Title>
77
- <Body>
78
- <CircularButton {...props} priority="primary" type="negative" />
79
- <CircularButton {...props} priority="secondary" type="negative" />
80
- <CircularButton {...props} priority="primary" type="negative" disabled />
81
- <CircularButton {...props} priority="secondary" type="negative" disabled />
82
- </Body>
91
+ <div style={gridStyle}>
92
+ <CircularButton icon={icon} priority="primary" type="negative">
93
+ Primary
94
+ </CircularButton>
95
+ <CircularButton icon={icon} priority="secondary" type="negative">
96
+ Secondary
97
+ </CircularButton>
98
+ <CircularButton disabled icon={icon} priority="primary" type="negative">
99
+ Primary disabled
100
+ </CircularButton>
101
+ <CircularButton disabled icon={icon} priority="secondary" type="negative">
102
+ Secondary disabled
103
+ </CircularButton>
104
+ </div>
83
105
 
84
106
  <Title type="title-body" className="m-y-2">
85
107
  Accent (Deprecated)
86
108
  </Title>
87
- <Body>
88
- <CircularButton {...props} priority="primary" type="accent" />
89
- <CircularButton {...props} priority="secondary" type="accent" />
90
- <CircularButton {...props} priority="primary" type="accent" disabled />
91
- <CircularButton {...props} priority="secondary" type="accent" disabled />
92
- </Body>
109
+ <div style={gridStyle}>
110
+ <CircularButton icon={icon} priority="primary" type="accent">
111
+ Primary
112
+ </CircularButton>
113
+ <CircularButton icon={icon} priority="secondary" type="accent">
114
+ Secondary
115
+ </CircularButton>
116
+ <CircularButton disabled icon={icon} priority="primary" type="accent">
117
+ Primary disabled
118
+ </CircularButton>
119
+ <CircularButton disabled icon={icon} priority="secondary" type="accent">
120
+ Secondary disabled
121
+ </CircularButton>
122
+ </div>
93
123
 
94
124
  <Title type="title-body" className="m-y-2">
95
125
  Positive (Deprecated)
96
126
  </Title>
97
- <Body>
98
- <CircularButton {...props} priority="primary" type="positive" />
99
- <CircularButton {...props} priority="secondary" type="positive" />
100
- <CircularButton {...props} priority="primary" type="positive" disabled />
101
- <CircularButton {...props} priority="secondary" type="positive" disabled />
102
- </Body>
127
+ <div style={gridStyle}>
128
+ <CircularButton icon={icon} priority="primary" type="positive">
129
+ Primary
130
+ </CircularButton>
131
+ <CircularButton icon={icon} priority="secondary" type="positive">
132
+ Secondary
133
+ </CircularButton>
134
+ <CircularButton disabled icon={icon} priority="primary" type="positive">
135
+ Primary disabled
136
+ </CircularButton>
137
+ <CircularButton disabled icon={icon} priority="secondary" type="positive">
138
+ Secondary disabled
139
+ </CircularButton>
140
+ </div>
103
141
  </>
104
142
  );
105
143
  },
@@ -7,8 +7,6 @@ import Title from '../title';
7
7
  import Body from '../body';
8
8
  import { withVariantConfig } from '../../.storybook/helpers';
9
9
 
10
- import { allModes } from '../../.storybook/modes';
11
-
12
10
  const wait = async (ms: number) =>
13
11
  new Promise<void>((resolve) => {
14
12
  setTimeout(resolve, ms);
@@ -24,45 +22,48 @@ type Story = StoryObj<typeof CircularButton>;
24
22
 
25
23
  /** All priorities, types, and states across all themes. */
26
24
  export const Variants: Story = {
27
- render: () => (
28
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: '24px', padding: '16px' }}>
29
- <CircularButton priority="primary" type="default" icon={<Send />}>
30
- Send
31
- </CircularButton>
32
- <CircularButton priority="secondary" type="default" icon={<Plus />}>
33
- Add funds
34
- </CircularButton>
35
- <CircularButton priority="primary" type="negative" icon={<Convert />}>
36
- Convert
37
- </CircularButton>
38
- <CircularButton priority="primary" type="default" icon={<Card />} disabled>
39
- Disabled
40
- </CircularButton>
41
- </div>
42
- ),
43
- parameters: {
44
- variants: ['default', 'dark', 'bright-green', 'forest-green'],
45
- chromatic: {
46
- dark: allModes.dark,
47
- brightGreen: allModes.brightGreen,
48
- forestGreen: allModes.forestGreen,
49
- },
50
- },
51
- };
25
+ render: () => {
26
+ const rowStyle = {
27
+ display: 'grid',
28
+ gridTemplateColumns: 'repeat(4, minmax(0, 100px))',
29
+ gap: '16px',
30
+ textAlign: 'center' as const,
31
+ };
52
32
 
53
- /** CircularButton at 400% zoom — icon shrinks from 56px to 32px. */
54
- export const Zoom400: Story = {
55
- render: () => (
56
- <div style={{ display: 'flex', gap: '24px', padding: '16px' }}>
57
- <CircularButton priority="primary" type="default" icon={<Send />}>
58
- Send
59
- </CircularButton>
60
- <CircularButton priority="secondary" type="default" icon={<Plus />}>
61
- Add funds
62
- </CircularButton>
63
- </div>
64
- ),
65
- ...withVariantConfig(['400%']),
33
+ return (
34
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '24px', padding: '16px' }}>
35
+ <div style={rowStyle}>
36
+ <CircularButton priority="primary" type="default" icon={<Send />}>
37
+ Primary
38
+ </CircularButton>
39
+ <CircularButton priority="secondary" type="default" icon={<Plus />}>
40
+ Secondary
41
+ </CircularButton>
42
+ <CircularButton disabled priority="primary" type="default" icon={<Card />}>
43
+ Primary disabled
44
+ </CircularButton>
45
+ <CircularButton disabled priority="secondary" type="default" icon={<Card />}>
46
+ Secondary disabled
47
+ </CircularButton>
48
+ </div>
49
+ <div style={rowStyle}>
50
+ <CircularButton priority="primary" type="negative" icon={<Send />}>
51
+ Primary
52
+ </CircularButton>
53
+ <CircularButton priority="secondary" type="negative" icon={<Convert />}>
54
+ Secondary
55
+ </CircularButton>
56
+ <CircularButton disabled priority="primary" type="negative" icon={<Card />}>
57
+ Primary disabled
58
+ </CircularButton>
59
+ <CircularButton disabled priority="secondary" type="negative" icon={<Card />}>
60
+ Secondary disabled
61
+ </CircularButton>
62
+ </div>
63
+ </div>
64
+ );
65
+ },
66
+ ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green']),
66
67
  };
67
68
 
68
69
  /** Tab through all variants and activate each with Space. */
@@ -13,8 +13,8 @@ import {
13
13
  Bank,
14
14
  Freeze,
15
15
  } from '@transferwise/icons';
16
+ import { fn } from 'storybook/test';
16
17
  import IconButton, { Props } from './IconButton';
17
- import { action } from 'storybook/actions';
18
18
  import Body from '../body';
19
19
  import SentimentSurface from '../sentimentSurface';
20
20
 
@@ -40,7 +40,7 @@ export default {
40
40
  title: 'Actions/IconButton',
41
41
  component: IconButton,
42
42
  args: {
43
- onClick: action('button click'),
43
+ onClick: fn(),
44
44
  'aria-label': 'Action',
45
45
  },
46
46
  parameters: {
@@ -61,7 +61,7 @@ const Template = ({ size, disabled }: Props) => {
61
61
  aria-label="One step back"
62
62
  priority="primary"
63
63
  type="default"
64
- onClick={action('button click')}
64
+ onClick={fn()}
65
65
  >
66
66
  <Plus />
67
67
  </IconButton>
@@ -71,7 +71,7 @@ const Template = ({ size, disabled }: Props) => {
71
71
  aria-label="One step back"
72
72
  priority="secondary"
73
73
  type="default"
74
- onClick={action('button click')}
74
+ onClick={fn()}
75
75
  >
76
76
  <Defrost />
77
77
  </IconButton>
@@ -81,7 +81,7 @@ const Template = ({ size, disabled }: Props) => {
81
81
  aria-label="One step back"
82
82
  priority="tertiary"
83
83
  type="default"
84
- onClick={action('button click')}
84
+ onClick={fn()}
85
85
  >
86
86
  <ArrowLeft />
87
87
  </IconButton>
@@ -91,7 +91,7 @@ const Template = ({ size, disabled }: Props) => {
91
91
  aria-label="One step back"
92
92
  priority="minimal"
93
93
  type="default"
94
- onClick={action('button click')}
94
+ onClick={fn()}
95
95
  >
96
96
  <Menu />
97
97
  </IconButton>
@@ -101,7 +101,7 @@ const Template = ({ size, disabled }: Props) => {
101
101
  aria-label="One step back"
102
102
  priority="primary"
103
103
  type="negative"
104
- onClick={action('button click')}
104
+ onClick={fn()}
105
105
  >
106
106
  <Cross />
107
107
  </IconButton>
@@ -111,7 +111,7 @@ const Template = ({ size, disabled }: Props) => {
111
111
  aria-label="One step back"
112
112
  priority="secondary"
113
113
  type="negative"
114
- onClick={action('button click')}
114
+ onClick={fn()}
115
115
  >
116
116
  <Edit />
117
117
  </IconButton>
@@ -224,7 +224,7 @@ export const SentimentAwareness: Story = {
224
224
  aria-label="Primary action"
225
225
  priority="primary"
226
226
  type="default"
227
- onClick={action('button click')}
227
+ onClick={fn()}
228
228
  >
229
229
  <Plus />
230
230
  </IconButton>
@@ -233,7 +233,7 @@ export const SentimentAwareness: Story = {
233
233
  aria-label="Secondary action"
234
234
  priority="secondary"
235
235
  type="default"
236
- onClick={action('button click')}
236
+ onClick={fn()}
237
237
  >
238
238
  <Settings />
239
239
  </IconButton>
@@ -242,7 +242,7 @@ export const SentimentAwareness: Story = {
242
242
  aria-label="Tertiary action"
243
243
  priority="tertiary"
244
244
  type="default"
245
- onClick={action('button click')}
245
+ onClick={fn()}
246
246
  >
247
247
  <Star />
248
248
  </IconButton>
@@ -251,7 +251,7 @@ export const SentimentAwareness: Story = {
251
251
  aria-label="Minimal action"
252
252
  priority="minimal"
253
253
  type="default"
254
- onClick={action('button click')}
254
+ onClick={fn()}
255
255
  >
256
256
  <Travel />
257
257
  </IconButton>
@@ -261,7 +261,7 @@ export const SentimentAwareness: Story = {
261
261
  priority="primary"
262
262
  type="default"
263
263
  disabled
264
- onClick={action('button click')}
264
+ onClick={fn()}
265
265
  >
266
266
  <Menu />
267
267
  </IconButton>
@@ -288,7 +288,7 @@ export const SentimentAwareness: Story = {
288
288
  aria-label="Primary action"
289
289
  priority="primary"
290
290
  type="default"
291
- onClick={action('button click')}
291
+ onClick={fn()}
292
292
  >
293
293
  <Briefcase />
294
294
  </IconButton>
@@ -297,7 +297,7 @@ export const SentimentAwareness: Story = {
297
297
  aria-label="Secondary action"
298
298
  priority="secondary"
299
299
  type="default"
300
- onClick={action('button click')}
300
+ onClick={fn()}
301
301
  >
302
302
  <Bank />
303
303
  </IconButton>
@@ -306,7 +306,7 @@ export const SentimentAwareness: Story = {
306
306
  aria-label="Tertiary action"
307
307
  priority="tertiary"
308
308
  type="default"
309
- onClick={action('button click')}
309
+ onClick={fn()}
310
310
  >
311
311
  <Freeze />
312
312
  </IconButton>
@@ -315,7 +315,7 @@ export const SentimentAwareness: Story = {
315
315
  aria-label="Minimal action"
316
316
  priority="minimal"
317
317
  type="default"
318
- onClick={action('button click')}
318
+ onClick={fn()}
319
319
  >
320
320
  <Edit />
321
321
  </IconButton>
@@ -325,7 +325,7 @@ export const SentimentAwareness: Story = {
325
325
  priority="primary"
326
326
  type="default"
327
327
  disabled
328
- onClick={action('button click')}
328
+ onClick={fn()}
329
329
  >
330
330
  <Cross />
331
331
  </IconButton>
@@ -336,10 +336,7 @@ export const SentimentAwareness: Story = {
336
336
  },
337
337
  parameters: {
338
338
  docs: {
339
- source: { type: 'dynamic' },
340
- canvas: {
341
- sourceState: 'hidden',
342
- },
339
+ canvas: { sourceState: 'hidden' },
343
340
  },
344
341
  },
345
342
  };
@@ -1,11 +1,9 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { Menu, Plus, Settings, Star, Travel } from '@transferwise/icons';
3
- import { action } from 'storybook/actions';
4
- import { expect, userEvent, within } from 'storybook/test';
3
+ import { expect, fn, userEvent, within } from 'storybook/test';
5
4
  import IconButton from './IconButton';
6
5
  import SentimentSurface from '../sentimentSurface';
7
6
  import { withVariantConfig } from '../../.storybook/helpers';
8
- import { allModes } from '../../.storybook/modes';
9
7
 
10
8
  const wait = async (ms: number) =>
11
9
  new Promise<void>((resolve) => {
@@ -78,7 +76,7 @@ export const Variants: Story = {
78
76
  aria-label="Primary action"
79
77
  priority="primary"
80
78
  type="default"
81
- onClick={action('button click')}
79
+ onClick={fn()}
82
80
  >
83
81
  <Plus />
84
82
  </IconButton>
@@ -87,7 +85,7 @@ export const Variants: Story = {
87
85
  aria-label="Secondary action"
88
86
  priority="secondary"
89
87
  type="default"
90
- onClick={action('button click')}
88
+ onClick={fn()}
91
89
  >
92
90
  <Settings />
93
91
  </IconButton>
@@ -96,7 +94,7 @@ export const Variants: Story = {
96
94
  aria-label="Tertiary action"
97
95
  priority="tertiary"
98
96
  type="default"
99
- onClick={action('button click')}
97
+ onClick={fn()}
100
98
  >
101
99
  <Star />
102
100
  </IconButton>
@@ -105,7 +103,7 @@ export const Variants: Story = {
105
103
  aria-label="Minimal action"
106
104
  priority="minimal"
107
105
  type="default"
108
- onClick={action('button click')}
106
+ onClick={fn()}
109
107
  >
110
108
  <Travel />
111
109
  </IconButton>
@@ -115,7 +113,7 @@ export const Variants: Story = {
115
113
  priority="primary"
116
114
  type="default"
117
115
  disabled
118
- onClick={action('button click')}
116
+ onClick={fn()}
119
117
  >
120
118
  <Menu />
121
119
  </IconButton>
@@ -142,7 +140,7 @@ export const Variants: Story = {
142
140
  aria-label="Primary action"
143
141
  priority="primary"
144
142
  type="default"
145
- onClick={action('button click')}
143
+ onClick={fn()}
146
144
  >
147
145
  <Plus />
148
146
  </IconButton>
@@ -151,7 +149,7 @@ export const Variants: Story = {
151
149
  aria-label="Secondary action"
152
150
  priority="secondary"
153
151
  type="default"
154
- onClick={action('button click')}
152
+ onClick={fn()}
155
153
  >
156
154
  <Settings />
157
155
  </IconButton>
@@ -160,7 +158,7 @@ export const Variants: Story = {
160
158
  aria-label="Tertiary action"
161
159
  priority="tertiary"
162
160
  type="default"
163
- onClick={action('button click')}
161
+ onClick={fn()}
164
162
  >
165
163
  <Star />
166
164
  </IconButton>
@@ -169,7 +167,7 @@ export const Variants: Story = {
169
167
  aria-label="Minimal action"
170
168
  priority="minimal"
171
169
  type="default"
172
- onClick={action('button click')}
170
+ onClick={fn()}
173
171
  >
174
172
  <Travel />
175
173
  </IconButton>
@@ -179,7 +177,7 @@ export const Variants: Story = {
179
177
  priority="primary"
180
178
  type="default"
181
179
  disabled
182
- onClick={action('button click')}
180
+ onClick={fn()}
183
181
  >
184
182
  <Menu />
185
183
  </IconButton>
@@ -188,83 +186,14 @@ export const Variants: Story = {
188
186
  </div>
189
187
  );
190
188
  },
191
- parameters: {
192
- padding: '16px',
193
- variants: ['default', 'dark', 'bright-green', 'forest-green'],
194
- chromatic: {
195
- dark: allModes.dark,
196
- brightGreen: allModes.brightGreen,
197
- forestGreen: allModes.forestGreen,
198
- },
199
- },
200
- };
201
-
202
- /** IconButton at 400% zoom for accessibility testing. */
203
- export const Zoom400: Story = {
204
- render: () => (
205
- <div style={{ display: 'flex', gap: '8px', padding: '16px', flexWrap: 'wrap' }}>
206
- <IconButton
207
- size={40}
208
- aria-label="Primary"
209
- priority="primary"
210
- type="default"
211
- onClick={action('click')}
212
- >
213
- <Plus />
214
- </IconButton>
215
- <IconButton
216
- size={40}
217
- aria-label="Secondary"
218
- priority="secondary"
219
- type="default"
220
- onClick={action('click')}
221
- >
222
- <Settings />
223
- </IconButton>
224
- <IconButton
225
- size={40}
226
- aria-label="Tertiary"
227
- priority="tertiary"
228
- type="default"
229
- onClick={action('click')}
230
- >
231
- <Star />
232
- </IconButton>
233
- <IconButton
234
- size={40}
235
- aria-label="Minimal"
236
- priority="minimal"
237
- type="default"
238
- onClick={action('click')}
239
- >
240
- <Travel />
241
- </IconButton>
242
- <IconButton
243
- size={40}
244
- aria-label="Disabled"
245
- priority="primary"
246
- type="default"
247
- disabled
248
- onClick={action('click')}
249
- >
250
- <Menu />
251
- </IconButton>
252
- </div>
253
- ),
254
- ...withVariantConfig(['400%']),
189
+ ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green']),
255
190
  };
256
191
 
257
192
  /** Tab through each priority variant and activate with Space. */
258
193
  export const KeyboardInteraction: Story = {
259
194
  render: () => (
260
195
  <div style={{ display: 'flex', gap: '12px', padding: '16px' }}>
261
- <IconButton
262
- size={48}
263
- aria-label="Primary"
264
- priority="primary"
265
- type="default"
266
- onClick={action('click')}
267
- >
196
+ <IconButton size={48} aria-label="Primary" priority="primary" type="default" onClick={fn()}>
268
197
  <Plus />
269
198
  </IconButton>
270
199
  <IconButton
@@ -272,26 +201,14 @@ export const KeyboardInteraction: Story = {
272
201
  aria-label="Secondary"
273
202
  priority="secondary"
274
203
  type="default"
275
- onClick={action('click')}
204
+ onClick={fn()}
276
205
  >
277
206
  <Settings />
278
207
  </IconButton>
279
- <IconButton
280
- size={48}
281
- aria-label="Tertiary"
282
- priority="tertiary"
283
- type="default"
284
- onClick={action('click')}
285
- >
208
+ <IconButton size={48} aria-label="Tertiary" priority="tertiary" type="default" onClick={fn()}>
286
209
  <Star />
287
210
  </IconButton>
288
- <IconButton
289
- size={48}
290
- aria-label="Minimal"
291
- priority="minimal"
292
- type="default"
293
- onClick={action('click')}
294
- >
211
+ <IconButton size={48} aria-label="Minimal" priority="minimal" type="default" onClick={fn()}>
295
212
  <Travel />
296
213
  </IconButton>
297
214
  <IconButton
@@ -300,7 +217,7 @@ export const KeyboardInteraction: Story = {
300
217
  priority="primary"
301
218
  type="default"
302
219
  disabled
303
- onClick={action('click')}
220
+ onClick={fn()}
304
221
  >
305
222
  <Menu />
306
223
  </IconButton>
@@ -353,3 +270,40 @@ export const KeyboardInteraction: Story = {
353
270
  });
354
271
  },
355
272
  };
273
+
274
+ /** IconButton at 400% zoom for accessibility testing. */
275
+ export const Zoom400: Story = {
276
+ render: () => (
277
+ <div style={{ display: 'flex', gap: '8px', padding: '16px', flexWrap: 'wrap' }}>
278
+ <IconButton size={40} aria-label="Primary" priority="primary" type="default" onClick={fn()}>
279
+ <Plus />
280
+ </IconButton>
281
+ <IconButton
282
+ size={40}
283
+ aria-label="Secondary"
284
+ priority="secondary"
285
+ type="default"
286
+ onClick={fn()}
287
+ >
288
+ <Settings />
289
+ </IconButton>
290
+ <IconButton size={40} aria-label="Tertiary" priority="tertiary" type="default" onClick={fn()}>
291
+ <Star />
292
+ </IconButton>
293
+ <IconButton size={40} aria-label="Minimal" priority="minimal" type="default" onClick={fn()}>
294
+ <Travel />
295
+ </IconButton>
296
+ <IconButton
297
+ size={40}
298
+ aria-label="Disabled"
299
+ disabled
300
+ priority="primary"
301
+ type="default"
302
+ onClick={fn()}
303
+ >
304
+ <Menu />
305
+ </IconButton>
306
+ </div>
307
+ ),
308
+ ...withVariantConfig(['400%']),
309
+ };
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import { useState } from 'react';
2
2
  import { fn } from 'storybook/test';
3
3
 
4
4
  import Switch, { SwitchProps } from './Switch';
@@ -39,11 +39,11 @@ type Story = StoryObj<typeof Switch>;
39
39
 
40
40
  /** Interactive playground — toggle checked and disabled via controls. */
41
41
  export const Playground: Story = {
42
- render: function Render(args) {
42
+ render: function Render(args: SwitchProps) {
43
43
  const [checked, setChecked] = useState(args.checked ?? false);
44
44
  return (
45
45
  <Field id="playground-field" label="Switch label">
46
- <Switch {...args} checked={checked} onClick={() => setChecked((v) => !v)} />
46
+ <Switch {...args} checked={checked} onClick={() => setChecked((v: boolean) => !v)} />
47
47
  </Field>
48
48
  );
49
49
  },
@@ -61,7 +61,7 @@ export const LabelPatterns: Story = {
61
61
  const [checked3, setCheck3] = useState(true);
62
62
 
63
63
  return (
64
- <>
64
+ <div className="d-flex flex-column" style={{ gap: '1rem' }}>
65
65
  <div>
66
66
  <Label htmlFor="labelId">Using Label component</Label>
67
67
  <Switch
@@ -87,7 +87,7 @@ export const LabelPatterns: Story = {
87
87
  <Field id="fieldId" label="Using Field component">
88
88
  <Switch checked={checked3} disabled={disabled} onClick={() => setCheck3(!checked3)} />
89
89
  </Field>
90
- </>
90
+ </div>
91
91
  );
92
92
  },
93
93
  parameters: {
@@ -98,7 +98,7 @@ function Render() {
98
98
  const [checked1, setCheck1] = useState(false);
99
99
  const [checked2, setCheck2] = useState(true);
100
100
  const [checked3, setCheck3] = useState(false);
101
-
101
+
102
102
  return (
103
103
  <>
104
104
  <Field id="fieldId" label="Using Field component">
@@ -107,7 +107,7 @@ function Render() {
107
107
  onClick={() => setCheck1(!checked1)}
108
108
  />
109
109
  </Field>
110
-
110
+
111
111
  <div>
112
112
  <Label htmlFor="labelId">Using standalone Label component</Label>
113
113
  <Switch
@@ -116,7 +116,7 @@ function Render() {
116
116
  onClick={() => setCheck2(!checked2)}
117
117
  />
118
118
  </div>
119
-
119
+
120
120
  <div>
121
121
  <strong id="ariaId" className="d-block">Using \`aria-labelledby\`</strong>
122
122
  <Switch
@@ -131,13 +131,6 @@ function Render() {
131
131
  },
132
132
  },
133
133
  },
134
- decorators: [
135
- (Story: React.FC) => (
136
- <div className="d-flex flex-column" style={{ gap: '1rem' }}>
137
- <Story />
138
- </div>
139
- ),
140
- ],
141
134
  args: {},
142
135
  argTypes: {
143
136
  checked: { table: { disable: true } },
@@ -3,7 +3,6 @@ import { expect, userEvent, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { withVariantConfig } from '../../.storybook/helpers';
6
- import { allModes } from '../../.storybook/modes';
7
6
  import { Field } from '../field/Field';
8
7
  import Switch from './Switch';
9
8
 
@@ -38,27 +37,7 @@ export const Variants: Story = {
38
37
  </div>
39
38
  );
40
39
  },
41
- parameters: {
42
- variants: ['default', 'dark', 'bright-green', 'forest-green'],
43
- chromatic: {
44
- dark: allModes.dark,
45
- brightGreen: allModes.brightGreen,
46
- forestGreen: allModes.forestGreen,
47
- },
48
- },
49
- };
50
-
51
- /** Switch at 400% zoom for accessibility testing. */
52
- export const Zoom400: Story = {
53
- render: function Render() {
54
- const [checked, setChecked] = useState(false);
55
- return (
56
- <Field label="Email notifications">
57
- <Switch checked={checked} onClick={() => setChecked((v) => !v)} />
58
- </Field>
59
- );
60
- },
61
- ...withVariantConfig(['400%']),
40
+ ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green']),
62
41
  };
63
42
 
64
43
  /** Tab to the switch and use Space to toggle it. */
@@ -99,3 +78,16 @@ export const KeyboardInteraction: Story = {
99
78
  });
100
79
  },
101
80
  };
81
+
82
+ /** Switch at 400% zoom for accessibility testing. */
83
+ export const Zoom400: Story = {
84
+ render: function Render() {
85
+ const [checked, setChecked] = useState(false);
86
+ return (
87
+ <Field label="Email notifications">
88
+ <Switch checked={checked} onClick={() => setChecked((v) => !v)} />
89
+ </Field>
90
+ );
91
+ },
92
+ ...withVariantConfig(['400%']),
93
+ };