@transferwise/components 0.0.0-experimental-e06e456 → 0.0.0-experimental-e3978a5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/index.mjs +1 -0
- package/build/index.mjs.map +1 -1
- package/build/listItem/AdditionalInfo/ListItemAdditionalInfo.js +56 -0
- package/build/listItem/AdditionalInfo/ListItemAdditionalInfo.js.map +1 -0
- package/build/listItem/AdditionalInfo/ListItemAdditionalInfo.mjs +54 -0
- package/build/listItem/AdditionalInfo/ListItemAdditionalInfo.mjs.map +1 -0
- package/build/listItem/AvatarLayout/ListItemAvatarLayout.js +23 -0
- package/build/listItem/AvatarLayout/ListItemAvatarLayout.js.map +1 -0
- package/build/listItem/AvatarLayout/ListItemAvatarLayout.mjs +21 -0
- package/build/listItem/AvatarLayout/ListItemAvatarLayout.mjs.map +1 -0
- package/build/listItem/AvatarView/ListItemAvatarView.js +23 -0
- package/build/listItem/AvatarView/ListItemAvatarView.js.map +1 -0
- package/build/listItem/AvatarView/ListItemAvatarView.mjs +21 -0
- package/build/listItem/AvatarView/ListItemAvatarView.mjs.map +1 -0
- package/build/listItem/Button/ListItemButton.js +43 -0
- package/build/listItem/Button/ListItemButton.js.map +1 -0
- package/build/listItem/Button/ListItemButton.mjs +41 -0
- package/build/listItem/Button/ListItemButton.mjs.map +1 -0
- package/build/listItem/Checkbox/ListItemCheckbox.js +30 -0
- package/build/listItem/Checkbox/ListItemCheckbox.js.map +1 -0
- package/build/listItem/Checkbox/ListItemCheckbox.mjs +28 -0
- package/build/listItem/Checkbox/ListItemCheckbox.mjs.map +1 -0
- package/build/listItem/IconButton/ListItemIconButton.js +56 -0
- package/build/listItem/IconButton/ListItemIconButton.js.map +1 -0
- package/build/listItem/IconButton/ListItemIconButton.mjs +54 -0
- package/build/listItem/IconButton/ListItemIconButton.mjs.map +1 -0
- package/build/listItem/Image/ListItemImage.js +31 -0
- package/build/listItem/Image/ListItemImage.js.map +1 -0
- package/build/listItem/Image/ListItemImage.mjs +29 -0
- package/build/listItem/Image/ListItemImage.mjs.map +1 -0
- package/build/listItem/ListItem.js +313 -0
- package/build/listItem/ListItem.js.map +1 -0
- package/build/listItem/ListItem.mjs +308 -0
- package/build/listItem/ListItem.mjs.map +1 -0
- package/build/listItem/ListItemContext.js +8 -0
- package/build/listItem/ListItemContext.js.map +1 -0
- package/build/listItem/ListItemContext.mjs +6 -0
- package/build/listItem/ListItemContext.mjs.map +1 -0
- package/build/listItem/Navigation/ListItemNavigation.js +44 -0
- package/build/listItem/Navigation/ListItemNavigation.js.map +1 -0
- package/build/listItem/Navigation/ListItemNavigation.mjs +42 -0
- package/build/listItem/Navigation/ListItemNavigation.mjs.map +1 -0
- package/build/listItem/Prompt/ListItemPrompt.js +59 -0
- package/build/listItem/Prompt/ListItemPrompt.js.map +1 -0
- package/build/listItem/Prompt/ListItemPrompt.mjs +54 -0
- package/build/listItem/Prompt/ListItemPrompt.mjs.map +1 -0
- package/build/listItem/Radio/ListItemRadio.js +30 -0
- package/build/listItem/Radio/ListItemRadio.js.map +1 -0
- package/build/listItem/Radio/ListItemRadio.mjs +28 -0
- package/build/listItem/Radio/ListItemRadio.mjs.map +1 -0
- package/build/listItem/Switch/ListItemSwitch.js +30 -0
- package/build/listItem/Switch/ListItemSwitch.js.map +1 -0
- package/build/listItem/Switch/ListItemSwitch.mjs +28 -0
- package/build/listItem/Switch/ListItemSwitch.mjs.map +1 -0
- package/build/listItem/useListItemControl.js +22 -0
- package/build/listItem/useListItemControl.js.map +1 -0
- package/build/listItem/useListItemControl.mjs +20 -0
- package/build/listItem/useListItemControl.mjs.map +1 -0
- package/build/listItem/useListItemMedia.js +21 -0
- package/build/listItem/useListItemMedia.js.map +1 -0
- package/build/listItem/useListItemMedia.mjs +19 -0
- package/build/listItem/useListItemMedia.mjs.map +1 -0
- package/build/main.css +771 -1
- package/build/styles/button/Button.css +1 -1
- package/build/styles/listItem/ListItem.css +770 -0
- package/build/styles/listItem/ListItem.grid.css +370 -0
- package/build/styles/main.css +771 -1
- package/build/types/index.d.ts +2 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/listItem/AdditionalInfo/ListItemAdditionalInfo.d.ts +15 -0
- package/build/types/listItem/AdditionalInfo/ListItemAdditionalInfo.d.ts.map +1 -0
- package/build/types/listItem/AdditionalInfo/index.d.ts +3 -0
- package/build/types/listItem/AdditionalInfo/index.d.ts.map +1 -0
- package/build/types/listItem/AvatarLayout/ListItemAvatarLayout.d.ts +18 -0
- package/build/types/listItem/AvatarLayout/ListItemAvatarLayout.d.ts.map +1 -0
- package/build/types/listItem/AvatarLayout/index.d.ts +3 -0
- package/build/types/listItem/AvatarLayout/index.d.ts.map +1 -0
- package/build/types/listItem/AvatarView/ListItemAvatarView.d.ts +16 -0
- package/build/types/listItem/AvatarView/ListItemAvatarView.d.ts.map +1 -0
- package/build/types/listItem/AvatarView/index.d.ts +3 -0
- package/build/types/listItem/AvatarView/index.d.ts.map +1 -0
- package/build/types/listItem/Button/ListItemButton.d.ts +20 -0
- package/build/types/listItem/Button/ListItemButton.d.ts.map +1 -0
- package/build/types/listItem/Button/index.d.ts +3 -0
- package/build/types/listItem/Button/index.d.ts.map +1 -0
- package/build/types/listItem/Checkbox/ListItemCheckbox.d.ts +14 -0
- package/build/types/listItem/Checkbox/ListItemCheckbox.d.ts.map +1 -0
- package/build/types/listItem/Checkbox/index.d.ts +3 -0
- package/build/types/listItem/Checkbox/index.d.ts.map +1 -0
- package/build/types/listItem/IconButton/ListItemIconButton.d.ts +18 -0
- package/build/types/listItem/IconButton/ListItemIconButton.d.ts.map +1 -0
- package/build/types/listItem/IconButton/index.d.ts +3 -0
- package/build/types/listItem/IconButton/index.d.ts.map +1 -0
- package/build/types/listItem/Image/ListItemImage.d.ts +25 -0
- package/build/types/listItem/Image/ListItemImage.d.ts.map +1 -0
- package/build/types/listItem/Image/index.d.ts +3 -0
- package/build/types/listItem/Image/index.d.ts.map +1 -0
- package/build/types/listItem/ListItem.d.ts +113 -0
- package/build/types/listItem/ListItem.d.ts.map +1 -0
- package/build/types/listItem/ListItemContext.d.ts +21 -0
- package/build/types/listItem/ListItemContext.d.ts.map +1 -0
- package/build/types/listItem/Navigation/ListItemNavigation.d.ts +15 -0
- package/build/types/listItem/Navigation/ListItemNavigation.d.ts.map +1 -0
- package/build/types/listItem/Navigation/index.d.ts +3 -0
- package/build/types/listItem/Navigation/index.d.ts.map +1 -0
- package/build/types/listItem/Prompt/ListItemPrompt.d.ts +16 -0
- package/build/types/listItem/Prompt/ListItemPrompt.d.ts.map +1 -0
- package/build/types/listItem/Prompt/index.d.ts +3 -0
- package/build/types/listItem/Prompt/index.d.ts.map +1 -0
- package/build/types/listItem/Radio/ListItemRadio.d.ts +14 -0
- package/build/types/listItem/Radio/ListItemRadio.d.ts.map +1 -0
- package/build/types/listItem/Radio/index.d.ts +3 -0
- package/build/types/listItem/Radio/index.d.ts.map +1 -0
- package/build/types/listItem/Switch/ListItemSwitch.d.ts +14 -0
- package/build/types/listItem/Switch/ListItemSwitch.d.ts.map +1 -0
- package/build/types/listItem/Switch/index.d.ts +3 -0
- package/build/types/listItem/Switch/index.d.ts.map +1 -0
- package/build/types/listItem/_stories/helpers.d.ts +27 -0
- package/build/types/listItem/_stories/helpers.d.ts.map +1 -0
- package/build/types/listItem/_stories/subcomponents.d.ts +18 -0
- package/build/types/listItem/_stories/subcomponents.d.ts.map +1 -0
- package/build/types/listItem/index.d.ts +14 -0
- package/build/types/listItem/index.d.ts.map +1 -0
- package/build/types/listItem/test-utils.d.ts +7 -0
- package/build/types/listItem/test-utils.d.ts.map +1 -0
- package/build/types/listItem/useListItemControl.d.ts +5 -0
- package/build/types/listItem/useListItemControl.d.ts.map +1 -0
- package/build/types/listItem/useListItemMedia.d.ts +6 -0
- package/build/types/listItem/useListItemMedia.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/button/Button.css +1 -1
- package/src/button/Button.less +1 -1
- package/src/button/Button.story.tsx +4 -9
- package/src/index.ts +15 -0
- package/src/list/List.story.tsx +13 -3
- package/src/listItem/AdditionalInfo/ListItemAdditionalInfo.spec.tsx +56 -0
- package/src/listItem/AdditionalInfo/ListItemAdditionalInfo.story.tsx +198 -0
- package/src/listItem/AdditionalInfo/ListItemAdditionalInfo.tsx +36 -0
- package/src/listItem/AdditionalInfo/index.ts +2 -0
- package/src/listItem/AvatarLayout/ListItemAvatarLayout.spec.tsx +59 -0
- package/src/listItem/AvatarLayout/ListItemAvatarLayout.story.tsx +124 -0
- package/src/listItem/AvatarLayout/ListItemAvatarLayout.tsx +27 -0
- package/src/listItem/AvatarLayout/index.ts +2 -0
- package/src/listItem/AvatarView/ListItemAvatarView.spec.tsx +75 -0
- package/src/listItem/AvatarView/ListItemAvatarView.story.tsx +339 -0
- package/src/listItem/AvatarView/ListItemAvatarView.tsx +27 -0
- package/src/listItem/AvatarView/index.ts +2 -0
- package/src/listItem/Button/ListItemButton.spec.tsx +68 -0
- package/src/listItem/Button/ListItemButton.story.tsx +473 -0
- package/src/listItem/Button/ListItemButton.tsx +56 -0
- package/src/listItem/Button/index.ts +2 -0
- package/src/listItem/Checkbox/ListItemCheckbox.spec.tsx +82 -0
- package/src/listItem/Checkbox/ListItemCheckbox.story.tsx +128 -0
- package/src/listItem/Checkbox/ListItemCheckbox.tsx +33 -0
- package/src/listItem/Checkbox/index.ts +2 -0
- package/src/listItem/IconButton/ListItemIconButton.spec.tsx +119 -0
- package/src/listItem/IconButton/ListItemIconButton.story.tsx +284 -0
- package/src/listItem/IconButton/ListItemIconButton.tsx +73 -0
- package/src/listItem/IconButton/index.ts +2 -0
- package/src/listItem/Image/ListItemImage.spec.tsx +30 -0
- package/src/listItem/Image/ListItemImage.story.tsx +80 -0
- package/src/listItem/Image/ListItemImage.tsx +46 -0
- package/src/listItem/Image/index.ts +2 -0
- package/src/listItem/ListItem.css +770 -0
- package/src/listItem/ListItem.grid.css +370 -0
- package/src/listItem/ListItem.grid.less +622 -0
- package/src/listItem/ListItem.less +421 -0
- package/src/listItem/ListItem.spec.tsx +1521 -0
- package/src/listItem/ListItem.tsx +444 -0
- package/src/listItem/ListItemContext.tsx +26 -0
- package/src/listItem/Navigation/ListItemNavigation.spec.tsx +59 -0
- package/src/listItem/Navigation/ListItemNavigation.story.tsx +112 -0
- package/src/listItem/Navigation/ListItemNavigation.tsx +39 -0
- package/src/listItem/Navigation/index.ts +2 -0
- package/src/listItem/Prompt/ListItemPrompt.spec.tsx +36 -0
- package/src/listItem/Prompt/ListItemPrompt.story.tsx +204 -0
- package/src/listItem/Prompt/ListItemPrompt.tsx +32 -0
- package/src/listItem/Prompt/index.ts +2 -0
- package/src/listItem/Radio/ListItemRadio.spec.tsx +66 -0
- package/src/listItem/Radio/ListItemRadio.story.tsx +111 -0
- package/src/listItem/Radio/ListItemRadio.tsx +33 -0
- package/src/listItem/Radio/index.ts +2 -0
- package/src/listItem/Switch/ListItemSwitch.spec.tsx +47 -0
- package/src/listItem/Switch/ListItemSwitch.story.tsx +79 -0
- package/src/listItem/Switch/ListItemSwitch.tsx +33 -0
- package/src/listItem/Switch/index.ts +2 -0
- package/src/listItem/_stories/ListItem.focus.test.story.tsx +265 -0
- package/src/listItem/_stories/ListItem.layout.test.story.tsx +354 -0
- package/src/listItem/_stories/ListItem.scenarios.story.tsx +228 -0
- package/src/listItem/_stories/ListItem.story.tsx +775 -0
- package/src/listItem/_stories/ListItem.variants.test.story.tsx +271 -0
- package/src/listItem/_stories/helpers.tsx +53 -0
- package/src/listItem/_stories/subcomponents.tsx +139 -0
- package/src/listItem/index.ts +14 -0
- package/src/listItem/test-utils.tsx +33 -0
- package/src/listItem/useListItemControl.tsx +18 -0
- package/src/listItem/useListItemMedia.tsx +16 -0
- package/src/main.css +771 -1
- package/src/main.less +1 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { mockMatchMedia, render, screen } from '../../test-utils';
|
|
2
|
+
import { Sentiment } from '../../common';
|
|
3
|
+
import { ListItem } from '../ListItem';
|
|
4
|
+
import type { ListItemPromptProps } from './ListItemPrompt';
|
|
5
|
+
|
|
6
|
+
mockMatchMedia();
|
|
7
|
+
|
|
8
|
+
describe('ListItem.Prompt', () => {
|
|
9
|
+
it('renders children content', () => {
|
|
10
|
+
render(
|
|
11
|
+
<ListItem
|
|
12
|
+
title="Test Title"
|
|
13
|
+
prompt={<ListItem.Prompt>This is a prompt message</ListItem.Prompt>}
|
|
14
|
+
/>,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(screen.getByText('This is a prompt message')).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('render icon', () => {
|
|
21
|
+
it.each([
|
|
22
|
+
[Sentiment.NEUTRAL, 'info-icon'],
|
|
23
|
+
[Sentiment.POSITIVE, 'check-icon'],
|
|
24
|
+
[Sentiment.NEGATIVE, 'cross-icon'],
|
|
25
|
+
[Sentiment.WARNING, 'alert-icon'],
|
|
26
|
+
] as [ListItemPromptProps['sentiment'], string][])('renders %s icon', (sentiment, iconId) => {
|
|
27
|
+
render(
|
|
28
|
+
<ListItem
|
|
29
|
+
title="Test Title"
|
|
30
|
+
prompt={<ListItem.Prompt sentiment={sentiment}>Message</ListItem.Prompt>}
|
|
31
|
+
/>,
|
|
32
|
+
);
|
|
33
|
+
expect(screen.getByTestId(iconId)).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { lorem10, lorem5 } from '../../test-utils';
|
|
4
|
+
import Link from '../../link';
|
|
5
|
+
import List from '../../list';
|
|
6
|
+
import { Sentiment as Sentiments } from '../../common';
|
|
7
|
+
import { ListItem } from '../ListItem';
|
|
8
|
+
import { Prompt, type ListItemPromptProps } from './ListItemPrompt';
|
|
9
|
+
import {
|
|
10
|
+
SB_LIST_ITEM_CONTROLS as CONTROLS,
|
|
11
|
+
SB_LIST_ITEM_MEDIA as MEDIA,
|
|
12
|
+
} from '../_stories/subcomponents';
|
|
13
|
+
|
|
14
|
+
const meta: Meta<ListItemPromptProps> = {
|
|
15
|
+
component: Prompt,
|
|
16
|
+
title: 'Content/ListItem/ListItem.Prompt',
|
|
17
|
+
parameters: {
|
|
18
|
+
docs: {
|
|
19
|
+
toc: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
args: {
|
|
23
|
+
sentiment: undefined,
|
|
24
|
+
children: 'You have done a terrible thing',
|
|
25
|
+
},
|
|
26
|
+
argTypes: {
|
|
27
|
+
sentiment: {
|
|
28
|
+
options: [
|
|
29
|
+
'unset (undefined)',
|
|
30
|
+
Sentiments.POSITIVE,
|
|
31
|
+
Sentiments.NEGATIVE,
|
|
32
|
+
Sentiments.NEUTRAL,
|
|
33
|
+
Sentiments.WARNING,
|
|
34
|
+
],
|
|
35
|
+
mapping: {
|
|
36
|
+
'unset (undefined)': undefined,
|
|
37
|
+
},
|
|
38
|
+
control: { type: 'radio' },
|
|
39
|
+
},
|
|
40
|
+
children: {
|
|
41
|
+
table: {
|
|
42
|
+
type: { summary: 'ReactNode' },
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default meta;
|
|
49
|
+
|
|
50
|
+
type Story = StoryObj<ListItemPromptProps>;
|
|
51
|
+
|
|
52
|
+
export const Playground: Story = {
|
|
53
|
+
tags: ['!autodocs'],
|
|
54
|
+
parameters: {
|
|
55
|
+
docs: {
|
|
56
|
+
source: 'dynamic',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
render: (args) => (
|
|
60
|
+
<List>
|
|
61
|
+
<ListItem
|
|
62
|
+
title={lorem5}
|
|
63
|
+
subtitle={lorem10}
|
|
64
|
+
media={MEDIA.avatarSingle}
|
|
65
|
+
control={CONTROLS.switch}
|
|
66
|
+
prompt={<Prompt {...args} />}
|
|
67
|
+
/>
|
|
68
|
+
</List>
|
|
69
|
+
),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const Sentiment: Story = {
|
|
73
|
+
parameters: {
|
|
74
|
+
controls: { disable: true },
|
|
75
|
+
actions: { disable: true },
|
|
76
|
+
a11y: { disable: true },
|
|
77
|
+
knobs: { disable: true },
|
|
78
|
+
},
|
|
79
|
+
render: (args) => (
|
|
80
|
+
<List>
|
|
81
|
+
<ListItem
|
|
82
|
+
title={lorem5}
|
|
83
|
+
subtitle={lorem10}
|
|
84
|
+
media={MEDIA.avatarSingle}
|
|
85
|
+
control={CONTROLS.switch}
|
|
86
|
+
prompt={<Prompt sentiment={Sentiments.NEUTRAL}>This is a neutral prompt.</Prompt>}
|
|
87
|
+
/>
|
|
88
|
+
<ListItem
|
|
89
|
+
title={lorem5}
|
|
90
|
+
subtitle={lorem10}
|
|
91
|
+
media={MEDIA.avatarSingle}
|
|
92
|
+
control={CONTROLS.switch}
|
|
93
|
+
prompt={<Prompt sentiment={Sentiments.POSITIVE}>This is a positive prompt.</Prompt>}
|
|
94
|
+
/>
|
|
95
|
+
<ListItem
|
|
96
|
+
title={lorem5}
|
|
97
|
+
subtitle={lorem10}
|
|
98
|
+
media={MEDIA.avatarSingle}
|
|
99
|
+
control={CONTROLS.switch}
|
|
100
|
+
prompt={<Prompt sentiment={Sentiments.WARNING}>This is a warning prompt.</Prompt>}
|
|
101
|
+
/>
|
|
102
|
+
<ListItem
|
|
103
|
+
title={lorem5}
|
|
104
|
+
subtitle={lorem10}
|
|
105
|
+
media={MEDIA.avatarSingle}
|
|
106
|
+
control={CONTROLS.switch}
|
|
107
|
+
prompt={<Prompt sentiment={Sentiments.NEGATIVE}>This is a negative prompt.</Prompt>}
|
|
108
|
+
/>
|
|
109
|
+
</List>
|
|
110
|
+
),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* `ListItem.Prompt` is rendered on a separate branch of the Accessibility Tree from the item's
|
|
115
|
+
* control, so it can include a single instance of `Link` component, which can be rendered as
|
|
116
|
+
* either HTML anchor or button. That element will spread across the whole surface of the Prompt
|
|
117
|
+
* so it's easily accessible for all users.
|
|
118
|
+
*/
|
|
119
|
+
export const Interactivity: Story = {
|
|
120
|
+
argTypes: {
|
|
121
|
+
children: {
|
|
122
|
+
table: {
|
|
123
|
+
disable: true,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
render: (args) => (
|
|
128
|
+
<List>
|
|
129
|
+
<ListItem
|
|
130
|
+
title={lorem5}
|
|
131
|
+
subtitle={lorem10}
|
|
132
|
+
media={MEDIA.avatarSingle}
|
|
133
|
+
control={CONTROLS.switch}
|
|
134
|
+
prompt={
|
|
135
|
+
<Prompt sentiment={args.sentiment}>
|
|
136
|
+
This prompt includes a{' '}
|
|
137
|
+
<Link href="https://wise.com" target="_blank" rel="noreferrer">
|
|
138
|
+
link to some resource
|
|
139
|
+
</Link>{' '}
|
|
140
|
+
to help the user in their journey.
|
|
141
|
+
</Prompt>
|
|
142
|
+
}
|
|
143
|
+
/>
|
|
144
|
+
|
|
145
|
+
<ListItem
|
|
146
|
+
title={lorem5}
|
|
147
|
+
subtitle={lorem10}
|
|
148
|
+
media={MEDIA.avatarSingle}
|
|
149
|
+
control={CONTROLS.switch}
|
|
150
|
+
prompt={
|
|
151
|
+
<Prompt sentiment={args.sentiment}>
|
|
152
|
+
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
|
|
153
|
+
This prompt includes an <Link onClick={action('inline button')}>
|
|
154
|
+
inline button
|
|
155
|
+
</Link>{' '}
|
|
156
|
+
than can e.g. trigger a modal.
|
|
157
|
+
</Prompt>
|
|
158
|
+
}
|
|
159
|
+
/>
|
|
160
|
+
</List>
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* By default, the Prompt will try to occupy as little space as possible, but as soon as you make it more than 1 line long, it will stretch to the full available width.
|
|
166
|
+
*
|
|
167
|
+
* **NB:** While Prompt supports multi-line text, its content should be concise and have no more than 2 short sentences so users can quickly understand the message.
|
|
168
|
+
*/
|
|
169
|
+
export const Sizing: Story = {
|
|
170
|
+
parameters: {
|
|
171
|
+
docs: {
|
|
172
|
+
canvas: {
|
|
173
|
+
sourceState: 'hidden',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
render: (args) => (
|
|
178
|
+
<List>
|
|
179
|
+
<ListItem
|
|
180
|
+
title={lorem5}
|
|
181
|
+
subtitle={lorem10}
|
|
182
|
+
media={MEDIA.image}
|
|
183
|
+
control={CONTROLS.switch}
|
|
184
|
+
prompt={
|
|
185
|
+
<ListItem.Prompt sentiment={Sentiments.POSITIVE}>This is a short text</ListItem.Prompt>
|
|
186
|
+
}
|
|
187
|
+
/>
|
|
188
|
+
<ListItem
|
|
189
|
+
title={lorem5}
|
|
190
|
+
subtitle={lorem10}
|
|
191
|
+
media={MEDIA.image}
|
|
192
|
+
control={CONTROLS.switch}
|
|
193
|
+
prompt={
|
|
194
|
+
<ListItem.Prompt sentiment={Sentiments.WARNING}>
|
|
195
|
+
This is a very, very, very, very, very long text that will wrap into more than 1 line
|
|
196
|
+
and will make the prompt stretch to a full available width. Technically it can be as
|
|
197
|
+
long as Vim manual, but we recommend keeping it concise and no more than 2 short
|
|
198
|
+
sentences.
|
|
199
|
+
</ListItem.Prompt>
|
|
200
|
+
}
|
|
201
|
+
/>
|
|
202
|
+
</List>
|
|
203
|
+
),
|
|
204
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { Sentiment } from '../../common';
|
|
4
|
+
import StatusIcon from '../../statusIcon';
|
|
5
|
+
import Body from '../../body';
|
|
6
|
+
import { ListItemContext, type ListItemContextData } from '../ListItemContext';
|
|
7
|
+
|
|
8
|
+
export type ListItemPromptProps = {
|
|
9
|
+
sentiment?: `${Sentiment.POSITIVE | Sentiment.NEGATIVE | Sentiment.NEUTRAL | Sentiment.WARNING}`;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This component allows for rendering an Inline Prompt. <br />In the future it will be a thin wrapper around a standalone component.<br />
|
|
15
|
+
*
|
|
16
|
+
* Please refer to the [Design documentation](https://wise.design/components/list-item#prompt) for details.
|
|
17
|
+
*/
|
|
18
|
+
export const Prompt = ({ sentiment = Sentiment.NEUTRAL, children }: ListItemPromptProps) => {
|
|
19
|
+
const { ids } = useContext<ListItemContextData>(ListItemContext);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div id={ids.prompt} className={clsx('wds-list-item-prompt', sentiment)}>
|
|
23
|
+
<div className="np-prompt-icon">
|
|
24
|
+
<StatusIcon size={16} sentiment={sentiment} />
|
|
25
|
+
</div>
|
|
26
|
+
<Body>{children}</Body>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
Prompt.displayName = 'ListItem.Prompt';
|
|
32
|
+
export default Prompt;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { render, screen } from '../../test-utils';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { ListItem, type ListItemProps } from '../ListItem';
|
|
4
|
+
|
|
5
|
+
describe('ListItem.Radio', () => {
|
|
6
|
+
const renderWith = (overrides: Partial<ListItemProps> = {}) =>
|
|
7
|
+
render(<ListItem title="Test Title" {...overrides} />);
|
|
8
|
+
|
|
9
|
+
it('renders radio button', () => {
|
|
10
|
+
renderWith({
|
|
11
|
+
control: <ListItem.Radio name="test-radio" value="option1" onChange={() => {}} />,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
expect(screen.getByRole('radio')).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('checked state', () => {
|
|
18
|
+
it('reflects checked state', () => {
|
|
19
|
+
renderWith({
|
|
20
|
+
control: <ListItem.Radio name="test-radio" value="option1" checked />,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(screen.getByRole('radio')).toBeChecked();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('reflects unchecked state', () => {
|
|
27
|
+
renderWith({
|
|
28
|
+
control: <ListItem.Radio name="test-radio" value="option1" checked={false} />,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(screen.getByRole('radio')).not.toBeChecked();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('handles onChange events', async () => {
|
|
36
|
+
const handleChange = jest.fn();
|
|
37
|
+
renderWith({
|
|
38
|
+
control: <ListItem.Radio name="test-radio" value="option1" onChange={handleChange} />,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await userEvent.click(screen.getByRole('radio'));
|
|
42
|
+
expect(handleChange).toHaveBeenCalledTimes(1);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('is disabled when ListItem is disabled', async () => {
|
|
46
|
+
const handleChange = jest.fn();
|
|
47
|
+
renderWith({
|
|
48
|
+
disabled: true,
|
|
49
|
+
control: <ListItem.Radio name="test-radio" value="option1" onChange={handleChange} />,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const radio = screen.getByRole('radio');
|
|
53
|
+
expect(radio).toBeDisabled();
|
|
54
|
+
await userEvent.click(radio);
|
|
55
|
+
expect(handleChange).not.toHaveBeenCalled();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('supports name and value attributes', () => {
|
|
59
|
+
renderWith({ control: <ListItem.Radio name="test-radio" value="option1" /> });
|
|
60
|
+
|
|
61
|
+
const radio = screen.getByRole('radio');
|
|
62
|
+
expect(radio).toHaveAttribute('name', 'test-radio');
|
|
63
|
+
// eslint-disable-next-line jest-dom/prefer-to-have-value
|
|
64
|
+
expect(radio).toHaveAttribute('value', 'option1');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import List from '../../list';
|
|
4
|
+
import { ListItem } from '../ListItem';
|
|
5
|
+
import {
|
|
6
|
+
SB_LIST_ITEM_ADDITIONAL_INFO as INFO,
|
|
7
|
+
SB_LIST_ITEM_MEDIA as MEDIA,
|
|
8
|
+
} from '../_stories/subcomponents';
|
|
9
|
+
import type { ListItemRadioProps } from './ListItemRadio';
|
|
10
|
+
import { fn } from 'storybook/test';
|
|
11
|
+
import { ProfileType } from '../../common';
|
|
12
|
+
|
|
13
|
+
const meta: Meta<ListItemRadioProps> = {
|
|
14
|
+
component: ListItem.Radio,
|
|
15
|
+
title: 'Content/ListItem/ListItem.Radio',
|
|
16
|
+
parameters: {
|
|
17
|
+
docs: {
|
|
18
|
+
toc: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
args: {
|
|
22
|
+
name: 'radio-group',
|
|
23
|
+
value: 'option1',
|
|
24
|
+
checked: false,
|
|
25
|
+
onChange: fn(),
|
|
26
|
+
},
|
|
27
|
+
argTypes: {
|
|
28
|
+
onChange: {
|
|
29
|
+
table: {
|
|
30
|
+
type: { summary: '(value: string | number) => void' },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
} satisfies Meta<ListItemRadioProps>;
|
|
35
|
+
|
|
36
|
+
export default meta;
|
|
37
|
+
|
|
38
|
+
type Story = StoryObj<ListItemRadioProps>;
|
|
39
|
+
|
|
40
|
+
export const Playground: Story = {
|
|
41
|
+
tags: ['!autodocs'],
|
|
42
|
+
render: (args: ListItemRadioProps) => {
|
|
43
|
+
return (
|
|
44
|
+
<List>
|
|
45
|
+
<ListItem
|
|
46
|
+
title="List item with radio"
|
|
47
|
+
subtitle="Select this option"
|
|
48
|
+
media={MEDIA.avatarSingle}
|
|
49
|
+
control={<ListItem.Radio {...args} />}
|
|
50
|
+
additionalInfo={INFO.nonInteractive}
|
|
51
|
+
/>
|
|
52
|
+
</List>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Radio controls follow the native HTML behaviour and can be grouped using the `name` prop.
|
|
59
|
+
*/
|
|
60
|
+
export const RadioGroup: Story = {
|
|
61
|
+
parameters: {
|
|
62
|
+
controls: { disable: true },
|
|
63
|
+
},
|
|
64
|
+
render: function Render() {
|
|
65
|
+
const [selectedValue, setSelectedValue] = useState('2');
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<List>
|
|
69
|
+
<ListItem
|
|
70
|
+
control={
|
|
71
|
+
<ListItem.Radio
|
|
72
|
+
name="group"
|
|
73
|
+
value="1"
|
|
74
|
+
checked={selectedValue === '1'}
|
|
75
|
+
onChange={setSelectedValue}
|
|
76
|
+
/>
|
|
77
|
+
}
|
|
78
|
+
title="First option"
|
|
79
|
+
subtitle="This is the first choice"
|
|
80
|
+
media={<ListItem.AvatarView profileType={ProfileType.BUSINESS} />}
|
|
81
|
+
/>
|
|
82
|
+
<ListItem
|
|
83
|
+
control={
|
|
84
|
+
<ListItem.Radio
|
|
85
|
+
name="group"
|
|
86
|
+
value="2"
|
|
87
|
+
checked={selectedValue === '2'}
|
|
88
|
+
onChange={setSelectedValue}
|
|
89
|
+
/>
|
|
90
|
+
}
|
|
91
|
+
title="Second option"
|
|
92
|
+
subtitle="This is the second choice"
|
|
93
|
+
media={<ListItem.AvatarView profileType={ProfileType.BUSINESS} />}
|
|
94
|
+
/>
|
|
95
|
+
<ListItem
|
|
96
|
+
control={
|
|
97
|
+
<ListItem.Radio
|
|
98
|
+
name="group"
|
|
99
|
+
value="3"
|
|
100
|
+
checked={selectedValue === '3'}
|
|
101
|
+
onChange={setSelectedValue}
|
|
102
|
+
/>
|
|
103
|
+
}
|
|
104
|
+
title="Third option"
|
|
105
|
+
subtitle="This is the third choice"
|
|
106
|
+
media={<ListItem.AvatarView profileType={ProfileType.BUSINESS} />}
|
|
107
|
+
/>
|
|
108
|
+
</List>
|
|
109
|
+
);
|
|
110
|
+
},
|
|
111
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import RadioButton, { type RadioButtonProps } from '../../common/RadioButton/RadioButton';
|
|
3
|
+
import { useListItemControl } from '../useListItemControl';
|
|
4
|
+
import { ListItemContext } from '../ListItemContext';
|
|
5
|
+
|
|
6
|
+
export type ListItemRadioProps = Omit<
|
|
7
|
+
RadioButtonProps,
|
|
8
|
+
'disabled' | 'readOnly' | 'className' | 'id'
|
|
9
|
+
>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* This component allows for rendering a Button control. It's a thin wrapper around the
|
|
13
|
+
* [Button component](https://storybook.wise.design/?path=/docs/content-button--docs), but offers only
|
|
14
|
+
* a subset of its features in line with the ListItem's constraints. <br />
|
|
15
|
+
* <br />
|
|
16
|
+
* Please refer to the [Design documentation](https://wise.design/components/list-item---button) for details.
|
|
17
|
+
*/
|
|
18
|
+
export const Radio = function (props: ListItemRadioProps) {
|
|
19
|
+
const { baseItemProps } = useListItemControl('radio', { ...props });
|
|
20
|
+
const { ids, describedByIds } = useContext(ListItemContext);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<RadioButton
|
|
24
|
+
{...props}
|
|
25
|
+
aria-describedby={describedByIds}
|
|
26
|
+
className="wds-list-item-control"
|
|
27
|
+
disabled={baseItemProps.disabled}
|
|
28
|
+
id={ids.control}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
Radio.displayName = 'ListItem.Radio';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { render, screen } from '../../test-utils';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { ListItem, type ListItemProps } from '../ListItem';
|
|
4
|
+
|
|
5
|
+
describe('ListItem.Switch', () => {
|
|
6
|
+
const renderWith = (overrides: Partial<ListItemProps> = {}) =>
|
|
7
|
+
render(<ListItem title="Test title" {...overrides} />);
|
|
8
|
+
|
|
9
|
+
it('renders switch with correct role', () => {
|
|
10
|
+
renderWith({ control: <ListItem.Switch checked={false} onClick={() => {}} /> });
|
|
11
|
+
expect(screen.getByRole('switch')).toBeInTheDocument();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('checked state', () => {
|
|
15
|
+
it('reflects checked state', () => {
|
|
16
|
+
renderWith({ control: <ListItem.Switch checked onClick={() => {}} /> });
|
|
17
|
+
expect(screen.getByRole('switch')).toBeChecked();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('reflects unchecked state', () => {
|
|
21
|
+
renderWith({ control: <ListItem.Switch checked={false} onClick={() => {}} /> });
|
|
22
|
+
expect(screen.getByRole('switch')).not.toBeChecked();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('handles onClick events', async () => {
|
|
27
|
+
const handleClick = jest.fn();
|
|
28
|
+
renderWith({ control: <ListItem.Switch checked={false} onClick={handleClick} /> });
|
|
29
|
+
|
|
30
|
+
await userEvent.click(screen.getByRole('switch'));
|
|
31
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('is disabled when ListItem is disabled', async () => {
|
|
35
|
+
const handleClick = jest.fn();
|
|
36
|
+
renderWith({
|
|
37
|
+
disabled: true,
|
|
38
|
+
control: <ListItem.Switch checked={false} onClick={handleClick} />,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const switchElement = screen.getByRole('switch');
|
|
42
|
+
expect(switchElement).toBeDisabled();
|
|
43
|
+
|
|
44
|
+
await userEvent.click(screen.getByRole('switch'));
|
|
45
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { fn } from 'storybook/test';
|
|
3
|
+
import { lorem10, lorem5 } from '../../test-utils';
|
|
4
|
+
import List from '../../list';
|
|
5
|
+
import { ListItem } from '../ListItem';
|
|
6
|
+
import {
|
|
7
|
+
SB_LIST_ITEM_ADDITIONAL_INFO as INFO,
|
|
8
|
+
SB_LIST_ITEM_MEDIA as MEDIA,
|
|
9
|
+
} from '../_stories/subcomponents';
|
|
10
|
+
import type { ListItemSwitchProps } from './ListItemSwitch';
|
|
11
|
+
|
|
12
|
+
const meta: Meta<ListItemSwitchProps> = {
|
|
13
|
+
component: ListItem.Switch,
|
|
14
|
+
title: 'Content/ListItem/ListItem.Switch',
|
|
15
|
+
parameters: {
|
|
16
|
+
docs: {
|
|
17
|
+
toc: true,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
args: {
|
|
21
|
+
checked: false,
|
|
22
|
+
onClick: fn(),
|
|
23
|
+
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
checked: {
|
|
26
|
+
control: 'boolean',
|
|
27
|
+
},
|
|
28
|
+
onClick: {
|
|
29
|
+
table: {
|
|
30
|
+
type: { summary: '(event?: MouseEvent<HTMLButtonElement>) => void' },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
} satisfies Meta<ListItemSwitchProps>;
|
|
35
|
+
|
|
36
|
+
export default meta;
|
|
37
|
+
|
|
38
|
+
type Story = StoryObj<ListItemSwitchProps>;
|
|
39
|
+
|
|
40
|
+
export const Playground: Story = {
|
|
41
|
+
tags: ['!autodocs'],
|
|
42
|
+
render: (args: ListItemSwitchProps) => {
|
|
43
|
+
return (
|
|
44
|
+
<List>
|
|
45
|
+
<ListItem
|
|
46
|
+
title="List item with switch"
|
|
47
|
+
subtitle="Toggle this setting"
|
|
48
|
+
media={MEDIA.avatarSingle}
|
|
49
|
+
control={<ListItem.Switch {...args} />}
|
|
50
|
+
additionalInfo={INFO.nonInteractive}
|
|
51
|
+
/>
|
|
52
|
+
</List>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const States: Story = {
|
|
58
|
+
parameters: {
|
|
59
|
+
controls: { disable: true },
|
|
60
|
+
},
|
|
61
|
+
render: (args) => {
|
|
62
|
+
return (
|
|
63
|
+
<List>
|
|
64
|
+
<ListItem
|
|
65
|
+
title={lorem5}
|
|
66
|
+
subtitle={lorem10}
|
|
67
|
+
media={MEDIA.avatarSingle}
|
|
68
|
+
control={<ListItem.Switch {...args} checked />}
|
|
69
|
+
/>
|
|
70
|
+
<ListItem
|
|
71
|
+
key={lorem5}
|
|
72
|
+
title={lorem10}
|
|
73
|
+
media={MEDIA.avatarSingle}
|
|
74
|
+
control={<ListItem.Switch {...args} />}
|
|
75
|
+
/>
|
|
76
|
+
</List>
|
|
77
|
+
);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useContext } from 'react';
|
|
2
|
+
import SwitchComp, { type SwitchProps } from '../../switch';
|
|
3
|
+
import { useListItemControl } from '../useListItemControl';
|
|
4
|
+
import { ListItemContext } from '../ListItemContext';
|
|
5
|
+
|
|
6
|
+
export type ListItemSwitchProps = Omit<
|
|
7
|
+
SwitchProps,
|
|
8
|
+
'disabled' | 'id' | 'aria-labelledby' | 'aria-label'
|
|
9
|
+
>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* This component allows for rendering a switch control within a fully interactive ListItem. <br />It's a thin wrapper around the
|
|
13
|
+
* [CheckboxButton component](https://storybook.wise.design/?path=/docs/actions-switch--docs),
|
|
14
|
+
* but offers only a subset of its features in line with the ListItem's constraints. <br />
|
|
15
|
+
*
|
|
16
|
+
* Please refer to the [Design documentation](https://wise.design/components/list-item---switch) for details.
|
|
17
|
+
*/
|
|
18
|
+
export const Switch = function (props: ListItemSwitchProps) {
|
|
19
|
+
const { baseItemProps } = useListItemControl('switch', { ...props });
|
|
20
|
+
const { ids, describedByIds } = useContext(ListItemContext);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<SwitchComp
|
|
24
|
+
{...props}
|
|
25
|
+
aria-describedby={describedByIds}
|
|
26
|
+
className="wds-list-item-control"
|
|
27
|
+
disabled={baseItemProps.disabled}
|
|
28
|
+
id={ids.control}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
Switch.displayName = 'ListItem.Switch';
|