@transferwise/components 0.0.0-experimental-ff96697 → 0.0.0-experimental-ffbd2fc
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 +1 -1
- package/src/alert/Alert.story.tsx +6 -0
- package/src/button/_stories/Button.story.tsx +5 -0
- package/src/checkboxButton/CheckboxButton.story.tsx +117 -40
- package/src/checkboxButton/CheckboxButton.test.story.tsx +191 -0
- package/src/chips/Chips.story.tsx +177 -88
- package/src/chips/Chips.test.story.tsx +147 -0
- package/src/circularButton/CircularButton.story.tsx +23 -4
- package/src/circularButton/CircularButton.test.story.tsx +119 -1
- package/src/expressiveMoneyInput/ExpressiveMoneyInput.story.tsx +1 -0
- package/src/header/Header.story.tsx +5 -0
- package/src/iconButton/IconButton.story.tsx +45 -1
- package/src/iconButton/IconButton.test.story.tsx +163 -2
- package/src/inputs/SelectInput/_stories/SelectInput.story.tsx +1 -0
- package/src/listItem/AdditionalInfo/ListItemAdditionalInfo.story.tsx +5 -1
- package/src/listItem/AvatarLayout/ListItemAvatarLayout.story.tsx +5 -1
- package/src/listItem/AvatarView/ListItemAvatarView.story.tsx +5 -1
- package/src/listItem/Button/ListItemButton.story.tsx +5 -1
- package/src/listItem/Checkbox/ListItemCheckbox.story.tsx +5 -1
- package/src/listItem/IconButton/ListItemIconButton.story.tsx +5 -1
- package/src/listItem/Image/ListItemImage.story.tsx +5 -1
- package/src/listItem/Navigation/ListItemNavigation.story.tsx +5 -1
- package/src/listItem/Prompt/ListItemPrompt.story.tsx +5 -1
- package/src/listItem/Radio/ListItemRadio.story.tsx +5 -1
- package/src/listItem/Switch/ListItemSwitch.story.tsx +5 -1
- package/src/listItem/_stories/ListItem.disabled.story.tsx +1 -0
- package/src/listItem/_stories/ListItem.scenarios.story.tsx +1 -0
- package/src/listItem/_stories/ListItem.story.tsx +5 -1
- package/src/prompt/ActionPrompt/ActionPrompt.story.tsx +5 -0
- package/src/prompt/InfoPrompt/InfoPrompt.story.tsx +5 -0
- package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +5 -0
- package/src/provider/theme/ThemeProvider.story.tsx +0 -8
- package/src/sentimentSurface/SentimentSurface.story.tsx +5 -0
- package/src/switch/Switch.story.tsx +45 -25
- package/src/switch/Switch.test.story.tsx +101 -0
- package/src/tokens/tokens.story.tsx +1 -1
|
@@ -27,7 +27,11 @@ const hideControls = disableControls([
|
|
|
27
27
|
const meta: Meta<ListItemIconButtonProps> = {
|
|
28
28
|
component: ListItem.IconButton,
|
|
29
29
|
title: 'Content/ListItem/ListItem.IconButton',
|
|
30
|
-
|
|
30
|
+
parameters: {
|
|
31
|
+
docs: {
|
|
32
|
+
toc: true,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
31
35
|
args: {
|
|
32
36
|
partiallyInteractive: false,
|
|
33
37
|
priority: undefined,
|
|
@@ -12,7 +12,11 @@ import type { ListItemImageProps } from './ListItemImage';
|
|
|
12
12
|
export default {
|
|
13
13
|
component: ListItem.Image,
|
|
14
14
|
title: 'Content/ListItem/ListItem.Image',
|
|
15
|
-
|
|
15
|
+
parameters: {
|
|
16
|
+
docs: {
|
|
17
|
+
toc: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
16
20
|
args: {
|
|
17
21
|
size: 48,
|
|
18
22
|
loading: undefined,
|
|
@@ -13,7 +13,11 @@ import type { ListItemNavigationProps } from './ListItemNavigation';
|
|
|
13
13
|
const meta: Meta<ListItemNavigationProps> = {
|
|
14
14
|
component: ListItem.Navigation,
|
|
15
15
|
title: 'Content/ListItem/ListItem.Navigation',
|
|
16
|
-
|
|
16
|
+
parameters: {
|
|
17
|
+
docs: {
|
|
18
|
+
toc: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
17
21
|
args: {
|
|
18
22
|
href: 'https://wise.com',
|
|
19
23
|
onClick: fn(),
|
|
@@ -16,7 +16,11 @@ import { Clock } from '@transferwise/icons';
|
|
|
16
16
|
const meta: Meta<ListItemPromptProps> = {
|
|
17
17
|
component: Prompt,
|
|
18
18
|
title: 'Content/ListItem/ListItem.Prompt',
|
|
19
|
-
|
|
19
|
+
parameters: {
|
|
20
|
+
docs: {
|
|
21
|
+
toc: true,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
20
24
|
decorators: [withoutKey],
|
|
21
25
|
args: {
|
|
22
26
|
sentiment: undefined,
|
|
@@ -13,7 +13,11 @@ import { ProfileType } from '../../common';
|
|
|
13
13
|
const meta: Meta<ListItemRadioProps> = {
|
|
14
14
|
component: ListItem.Radio,
|
|
15
15
|
title: 'Content/ListItem/ListItem.Radio',
|
|
16
|
-
|
|
16
|
+
parameters: {
|
|
17
|
+
docs: {
|
|
18
|
+
toc: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
17
21
|
args: {
|
|
18
22
|
name: 'radio-group',
|
|
19
23
|
value: 'option1',
|
|
@@ -12,7 +12,11 @@ import type { ListItemSwitchProps } from './ListItemSwitch';
|
|
|
12
12
|
const meta: Meta<ListItemSwitchProps> = {
|
|
13
13
|
component: ListItem.Switch,
|
|
14
14
|
title: 'Content/ListItem/ListItem.Switch',
|
|
15
|
-
|
|
15
|
+
parameters: {
|
|
16
|
+
docs: {
|
|
17
|
+
toc: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
16
20
|
args: {
|
|
17
21
|
checked: false,
|
|
18
22
|
onClick: fn(),
|
|
@@ -24,14 +24,6 @@ export default {
|
|
|
24
24
|
component: ThemeProvider,
|
|
25
25
|
title: 'Foundations/ThemeProvider',
|
|
26
26
|
tags: ['!manifest'],
|
|
27
|
-
parameters: {
|
|
28
|
-
docs: {
|
|
29
|
-
description: {
|
|
30
|
-
component:
|
|
31
|
-
'Components require `ThemeProvider` from `@wise/components-theming` to be wrapped around your application for theming support. Available themes include: `personal`, `business`, `platform`, and variants with different color schemes.',
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
27
|
} satisfies Meta<typeof ThemeProvider>;
|
|
36
28
|
|
|
37
29
|
type Story = StoryObj<typeof ThemeProvider>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import { fn } from 'storybook/test';
|
|
3
3
|
|
|
4
4
|
import Switch, { SwitchProps } from './Switch';
|
|
@@ -6,6 +6,17 @@ import { Field } from '../field/Field';
|
|
|
6
6
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
7
7
|
import { Label } from '../label';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* A toggle switch representing an on/off state. Semantically a `role="switch"` button.
|
|
11
|
+
*
|
|
12
|
+
* Always pair with an accessible label using `Field`, a `<label>` element, or
|
|
13
|
+
* `aria-labelledby`. The deprecated `aria-label` prop is supported but prefer an
|
|
14
|
+
* external label.
|
|
15
|
+
*
|
|
16
|
+
* Keyboard: `Space` toggles the switch when focused.
|
|
17
|
+
*
|
|
18
|
+
* **Design guide**: [wise.design/components/switch](https://wise.design/components/switch)
|
|
19
|
+
*/
|
|
9
20
|
const meta: Meta<typeof Switch> = {
|
|
10
21
|
component: Switch,
|
|
11
22
|
title: 'Actions/Switch',
|
|
@@ -18,41 +29,46 @@ const meta: Meta<typeof Switch> = {
|
|
|
18
29
|
'aria-label': undefined,
|
|
19
30
|
onClick: fn(),
|
|
20
31
|
},
|
|
32
|
+
parameters: {
|
|
33
|
+
docs: { toc: true },
|
|
34
|
+
},
|
|
21
35
|
} satisfies Meta<typeof Switch>;
|
|
22
36
|
|
|
23
37
|
export default meta;
|
|
24
38
|
type Story = StoryObj<typeof Switch>;
|
|
25
39
|
|
|
26
|
-
|
|
27
|
-
tags: ['!autodocs', '!dev'],
|
|
28
|
-
};
|
|
29
|
-
|
|
40
|
+
/** Interactive playground — toggle checked and disabled via controls. */
|
|
30
41
|
export const Playground: Story = {
|
|
31
|
-
|
|
42
|
+
render: function Render(args) {
|
|
43
|
+
const [checked, setChecked] = useState(args.checked ?? false);
|
|
44
|
+
return (
|
|
45
|
+
<Field id="playground-field" label="Switch label">
|
|
46
|
+
<Switch {...args} checked={checked} onClick={() => setChecked((v) => !v)} />
|
|
47
|
+
</Field>
|
|
48
|
+
);
|
|
49
|
+
},
|
|
32
50
|
argTypes: {
|
|
33
51
|
onClick: { table: { disable: true } },
|
|
52
|
+
checked: { control: false },
|
|
34
53
|
},
|
|
35
54
|
};
|
|
36
55
|
|
|
37
|
-
|
|
56
|
+
/** Three labelling patterns: Field, Label, and aria-labelledby. */
|
|
57
|
+
export const LabelPatterns: Story = {
|
|
38
58
|
render: function Render({ disabled }: SwitchProps) {
|
|
39
|
-
const [checked1, setCheck1] = useState(
|
|
40
|
-
const [checked2, setCheck2] = useState(
|
|
41
|
-
const [checked3, setCheck3] = useState(
|
|
59
|
+
const [checked1, setCheck1] = useState(true);
|
|
60
|
+
const [checked2, setCheck2] = useState(false);
|
|
61
|
+
const [checked3, setCheck3] = useState(true);
|
|
42
62
|
|
|
43
63
|
return (
|
|
44
64
|
<>
|
|
45
|
-
<Field id="fieldId" label="Using Field component">
|
|
46
|
-
<Switch checked={checked1} disabled={disabled} onClick={() => setCheck1(!checked1)} />
|
|
47
|
-
</Field>
|
|
48
|
-
|
|
49
65
|
<div>
|
|
50
66
|
<Label htmlFor="labelId">Using Label component</Label>
|
|
51
67
|
<Switch
|
|
52
68
|
id="labelId"
|
|
53
|
-
checked={
|
|
69
|
+
checked={checked1}
|
|
54
70
|
disabled={disabled}
|
|
55
|
-
onClick={() =>
|
|
71
|
+
onClick={() => setCheck1(!checked1)}
|
|
56
72
|
/>
|
|
57
73
|
</div>
|
|
58
74
|
|
|
@@ -62,11 +78,15 @@ export const Interactivity: Story = {
|
|
|
62
78
|
</strong>
|
|
63
79
|
<Switch
|
|
64
80
|
aria-labelledby="ariaId"
|
|
65
|
-
checked={
|
|
81
|
+
checked={checked2}
|
|
66
82
|
disabled={disabled}
|
|
67
|
-
onClick={() =>
|
|
83
|
+
onClick={() => setCheck2(!checked2)}
|
|
68
84
|
/>
|
|
69
85
|
</div>
|
|
86
|
+
|
|
87
|
+
<Field id="fieldId" label="Using Field component">
|
|
88
|
+
<Switch checked={checked3} disabled={disabled} onClick={() => setCheck3(!checked3)} />
|
|
89
|
+
</Field>
|
|
70
90
|
</>
|
|
71
91
|
);
|
|
72
92
|
},
|
|
@@ -112,7 +132,7 @@ function Render() {
|
|
|
112
132
|
},
|
|
113
133
|
},
|
|
114
134
|
decorators: [
|
|
115
|
-
(Story:
|
|
135
|
+
(Story: React.FC) => (
|
|
116
136
|
<div className="d-flex flex-column" style={{ gap: '1rem' }}>
|
|
117
137
|
<Story />
|
|
118
138
|
</div>
|
|
@@ -126,17 +146,17 @@ function Render() {
|
|
|
126
146
|
};
|
|
127
147
|
|
|
128
148
|
export const Disabled: Story = {
|
|
129
|
-
render: function Render(
|
|
149
|
+
render: function Render() {
|
|
130
150
|
const [checked1, setCheck1] = useState(false);
|
|
131
151
|
const [checked2, setCheck2] = useState(true);
|
|
132
152
|
|
|
133
153
|
return (
|
|
134
154
|
<>
|
|
135
|
-
<Field label="
|
|
155
|
+
<Field label="Disabled (off)">
|
|
136
156
|
<Switch checked={checked1} disabled onClick={() => setCheck1(!checked1)} />
|
|
137
157
|
</Field>
|
|
138
158
|
|
|
139
|
-
<Field label="
|
|
159
|
+
<Field label="Disabled (on)">
|
|
140
160
|
<Switch checked={checked2} disabled onClick={() => setCheck2(!checked2)} />
|
|
141
161
|
</Field>
|
|
142
162
|
</>
|
|
@@ -152,14 +172,14 @@ function Render() {
|
|
|
152
172
|
|
|
153
173
|
return (
|
|
154
174
|
<>
|
|
155
|
-
<Field label="
|
|
175
|
+
<Field label="Disabled (off)">
|
|
156
176
|
<Switch
|
|
157
177
|
checked={checked1}
|
|
158
178
|
disabled
|
|
159
179
|
onClick={() => setCheck1(!checked1)}
|
|
160
180
|
/>
|
|
161
|
-
</
|
|
162
|
-
<Field label="
|
|
181
|
+
</Field>
|
|
182
|
+
<Field label="Disabled (on)">
|
|
163
183
|
<Switch
|
|
164
184
|
checked={checked2}
|
|
165
185
|
disabled
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { expect, userEvent, within } from 'storybook/test';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { withVariantConfig } from '../../.storybook/helpers';
|
|
6
|
+
import { allModes } from '../../.storybook/modes';
|
|
7
|
+
import { Field } from '../field/Field';
|
|
8
|
+
import Switch from './Switch';
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
component: Switch,
|
|
12
|
+
title: 'Actions/Switch/Tests',
|
|
13
|
+
tags: ['!autodocs', '!manifest'],
|
|
14
|
+
} satisfies Meta<typeof Switch>;
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof Switch>;
|
|
17
|
+
|
|
18
|
+
/** All switch states across all themes. */
|
|
19
|
+
export const Variants: Story = {
|
|
20
|
+
render: function Render() {
|
|
21
|
+
const [unchecked, setUnchecked] = useState(false);
|
|
22
|
+
const [checked, setChecked] = useState(true);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px', padding: '16px' }}>
|
|
26
|
+
<Field label="Unchecked">
|
|
27
|
+
<Switch checked={unchecked} onClick={() => setUnchecked((v) => !v)} />
|
|
28
|
+
</Field>
|
|
29
|
+
<Field label="Checked">
|
|
30
|
+
<Switch checked={checked} onClick={() => setChecked((v) => !v)} />
|
|
31
|
+
</Field>
|
|
32
|
+
<Field label="Disabled (off)">
|
|
33
|
+
<Switch checked={false} disabled onClick={() => {}} />
|
|
34
|
+
</Field>
|
|
35
|
+
<Field label="Disabled (on)">
|
|
36
|
+
<Switch checked disabled onClick={() => {}} />
|
|
37
|
+
</Field>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
},
|
|
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%']),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Tab to the switch and use Space to toggle it. */
|
|
65
|
+
export const KeyboardInteraction: Story = {
|
|
66
|
+
render: function Render() {
|
|
67
|
+
const [checked, setChecked] = useState(false);
|
|
68
|
+
return (
|
|
69
|
+
<Field id="notif-field" label="Email notifications">
|
|
70
|
+
<Switch checked={checked} onClick={() => setChecked((v) => !v)} />
|
|
71
|
+
</Field>
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
play: async ({ canvasElement, step }) => {
|
|
75
|
+
const wait = async (ms: number) =>
|
|
76
|
+
new Promise<void>((resolve) => {
|
|
77
|
+
setTimeout(resolve, ms);
|
|
78
|
+
});
|
|
79
|
+
const canvas = within(canvasElement);
|
|
80
|
+
const switchEl = canvas.getByRole('switch');
|
|
81
|
+
|
|
82
|
+
await step('tab focuses the switch', async () => {
|
|
83
|
+
await userEvent.tab();
|
|
84
|
+
await expect(switchEl).toHaveFocus();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await wait(400);
|
|
88
|
+
|
|
89
|
+
await step('space toggles the switch on', async () => {
|
|
90
|
+
await userEvent.keyboard(' ');
|
|
91
|
+
await expect(switchEl).toHaveAttribute('aria-checked', 'true');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await wait(400);
|
|
95
|
+
|
|
96
|
+
await step('space toggles the switch off', async () => {
|
|
97
|
+
await userEvent.keyboard(' ');
|
|
98
|
+
await expect(switchEl).toHaveAttribute('aria-checked', 'false');
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
};
|