@transferwise/components 46.103.1 → 46.105.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/header/Header.js +60 -43
- package/build/header/Header.js.map +1 -1
- package/build/header/Header.mjs +57 -43
- package/build/header/Header.mjs.map +1 -1
- package/build/i18n/cs.json +2 -0
- package/build/i18n/cs.json.js +2 -0
- package/build/i18n/cs.json.js.map +1 -1
- package/build/i18n/cs.json.mjs +2 -0
- package/build/i18n/cs.json.mjs.map +1 -1
- package/build/i18n/es.json +2 -0
- package/build/i18n/es.json.js +2 -0
- package/build/i18n/es.json.js.map +1 -1
- package/build/i18n/es.json.mjs +2 -0
- package/build/i18n/es.json.mjs.map +1 -1
- package/build/i18n/th.json +2 -0
- package/build/i18n/th.json.js +2 -0
- package/build/i18n/th.json.js.map +1 -1
- package/build/i18n/th.json.mjs +2 -0
- package/build/i18n/th.json.mjs.map +1 -1
- package/build/index.js +3 -1
- package/build/index.js.map +1 -1
- package/build/index.mjs +2 -1
- package/build/index.mjs.map +1 -1
- package/build/inputs/SelectInput.js +1 -1
- package/build/inputs/SelectInput.js.map +1 -1
- package/build/inputs/SelectInput.mjs +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 +311 -0
- package/build/listItem/ListItem.js.map +1 -0
- package/build/listItem/ListItem.mjs +306 -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 +794 -14
- package/build/styles/header/Header.css +21 -14
- package/build/styles/listItem/ListItem.css +773 -0
- package/build/styles/listItem/ListItem.grid.css +370 -0
- package/build/styles/listItem/Prompt/ListItemPrompt.css +157 -0
- package/build/styles/main.css +794 -14
- package/build/title/Title.js +10 -4
- package/build/title/Title.js.map +1 -1
- package/build/title/Title.mjs +6 -4
- package/build/title/Title.mjs.map +1 -1
- package/build/types/header/Header.d.ts +27 -11
- package/build/types/header/Header.d.ts.map +1 -1
- package/build/types/header/index.d.ts +1 -0
- package/build/types/header/index.d.ts.map +1 -1
- package/build/types/index.d.ts +3 -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 +111 -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/build/types/title/Title.d.ts +4 -5
- package/build/types/title/Title.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/button/Button.spec.tsx +25 -1
- package/src/button/Button.story.tsx +1 -0
- package/src/header/Header.accessibility.docs.mdx +85 -0
- package/src/header/Header.css +21 -14
- package/src/header/Header.less +17 -10
- package/src/header/Header.spec.tsx +68 -50
- package/src/header/Header.story.tsx +190 -36
- package/src/header/Header.tsx +96 -65
- package/src/header/index.ts +1 -0
- package/src/i18n/cs.json +2 -0
- package/src/i18n/es.json +2 -0
- package/src/i18n/th.json +2 -0
- package/src/iconButton/iconButton.spec.tsx +31 -0
- package/src/index.ts +16 -0
- package/src/legacylistItem/LegacyListItem.story.tsx +1 -1
- package/src/legacylistItem/LegacyListItem.tests.story.tsx +2 -1
- 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 +90 -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 +131 -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 +773 -0
- package/src/listItem/ListItem.grid.css +370 -0
- package/src/listItem/ListItem.grid.less +622 -0
- package/src/listItem/ListItem.less +291 -0
- package/src/listItem/ListItem.spec.tsx +1511 -0
- package/src/listItem/ListItem.tsx +440 -0
- package/src/listItem/ListItemContext.tsx +26 -0
- package/src/listItem/Navigation/ListItemNavigation.spec.tsx +67 -0
- package/src/listItem/Navigation/ListItemNavigation.story.tsx +114 -0
- package/src/listItem/Navigation/ListItemNavigation.tsx +39 -0
- package/src/listItem/Navigation/index.ts +2 -0
- package/src/listItem/Prompt/ListItemPrompt.css +157 -0
- package/src/listItem/Prompt/ListItemPrompt.less +134 -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 +374 -0
- package/src/listItem/_stories/ListItem.scenarios.story.tsx +228 -0
- package/src/listItem/_stories/ListItem.story.tsx +774 -0
- package/src/listItem/_stories/ListItem.variants.test.story.tsx +274 -0
- package/src/listItem/_stories/helpers.tsx +53 -0
- package/src/listItem/_stories/subcomponents.tsx +141 -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 +794 -14
- package/src/main.less +1 -0
- package/src/primitives/PrimitiveAnchor/test/PrimitiveAnchor.spec.tsx +15 -4
- package/src/title/Title.tsx +25 -12
|
@@ -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';
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import Link from '../../link';
|
|
3
|
+
import List from '../../list';
|
|
4
|
+
import { ListItem, type ListItemProps } from '../ListItem';
|
|
5
|
+
import { expect, userEvent, within, waitFor } from 'storybook/test';
|
|
6
|
+
|
|
7
|
+
const waitForFocus = async (assertion: () => Promise<void>, timeout = 3000) => {
|
|
8
|
+
await waitFor(assertion, { timeout });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const waitForListItem = async (canvas: ReturnType<typeof within>, timeout = 3000) => {
|
|
12
|
+
await waitFor(
|
|
13
|
+
async () => {
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
15
|
+
await expect(canvas.getByRole('listitem')).toBeInTheDocument();
|
|
16
|
+
},
|
|
17
|
+
{ timeout },
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
component: ListItem,
|
|
23
|
+
title: 'Content/ListItem/tests/focus',
|
|
24
|
+
tags: ['!autodocs'],
|
|
25
|
+
parameters: {
|
|
26
|
+
controls: { disable: true },
|
|
27
|
+
actions: { disable: true },
|
|
28
|
+
a11y: { disable: true },
|
|
29
|
+
knobs: { disable: true },
|
|
30
|
+
},
|
|
31
|
+
} satisfies Meta<ListItemProps>;
|
|
32
|
+
type Story = StoryObj<ListItemProps>;
|
|
33
|
+
|
|
34
|
+
const title = {
|
|
35
|
+
full: 'Fully interactive',
|
|
36
|
+
partial: 'Partially interactive',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const subtitle = {
|
|
40
|
+
full: 'Whole item should be focusable, control should not.',
|
|
41
|
+
partial: 'Only control should be focusable, not whole item.',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const additionalInfo = {
|
|
45
|
+
static: (
|
|
46
|
+
<ListItem.AdditionalInfo>
|
|
47
|
+
Fully interactive ListItems don't allow any nested interactive elements like links or
|
|
48
|
+
buttons within AdditionalInfo.
|
|
49
|
+
</ListItem.AdditionalInfo>
|
|
50
|
+
),
|
|
51
|
+
interactive: (
|
|
52
|
+
<ListItem.AdditionalInfo
|
|
53
|
+
action={{ label: 'appended to the end.', href: 'https://wise.com', target: '_blank' }}
|
|
54
|
+
>
|
|
55
|
+
This additional info has a focusable link
|
|
56
|
+
</ListItem.AdditionalInfo>
|
|
57
|
+
),
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const prompt = {
|
|
61
|
+
static: <ListItem.Prompt sentiment="positive">Non-interactive prompt.</ListItem.Prompt>,
|
|
62
|
+
interactive: (
|
|
63
|
+
<ListItem.Prompt sentiment="positive">
|
|
64
|
+
This prompt has a{' '}
|
|
65
|
+
<Link href="https://wise.com" target="_blank" rel="noreferrer">
|
|
66
|
+
single interactive element
|
|
67
|
+
</Link>{' '}
|
|
68
|
+
that spreads across the whole prompt area.
|
|
69
|
+
</ListItem.Prompt>
|
|
70
|
+
),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const button = {
|
|
74
|
+
full: (
|
|
75
|
+
<ListItem.Button priority="secondary-neutral" onClick={() => {}}>
|
|
76
|
+
Click me
|
|
77
|
+
</ListItem.Button>
|
|
78
|
+
),
|
|
79
|
+
partial: (
|
|
80
|
+
<ListItem.Button partiallyInteractive priority="secondary-neutral" onClick={() => {}}>
|
|
81
|
+
Click me
|
|
82
|
+
</ListItem.Button>
|
|
83
|
+
),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const FullyInteractive: Story = {
|
|
87
|
+
play: async ({ canvasElement }) => {
|
|
88
|
+
const canvas = within(canvasElement);
|
|
89
|
+
await waitForListItem(canvas);
|
|
90
|
+
await userEvent.tab();
|
|
91
|
+
await waitForFocus(async () => {
|
|
92
|
+
await expect(canvas.getByRole('button')).toHaveFocus();
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
render: () => (
|
|
96
|
+
<List>
|
|
97
|
+
<ListItem
|
|
98
|
+
title={title.full}
|
|
99
|
+
subtitle={subtitle.full}
|
|
100
|
+
additionalInfo={additionalInfo.static}
|
|
101
|
+
control={button.full}
|
|
102
|
+
prompt={prompt.static}
|
|
103
|
+
/>
|
|
104
|
+
</List>
|
|
105
|
+
),
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const FullyInteractiveFocusedOnPrompt: Story = {
|
|
109
|
+
play: async ({ canvasElement }) => {
|
|
110
|
+
const canvas = within(canvasElement);
|
|
111
|
+
await waitForListItem(canvas);
|
|
112
|
+
|
|
113
|
+
await userEvent.tab();
|
|
114
|
+
await waitForFocus(async () => {
|
|
115
|
+
await expect(canvas.getByRole('button')).toHaveFocus();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await userEvent.tab();
|
|
119
|
+
await waitForFocus(async () => {
|
|
120
|
+
await expect(canvas.getByRole('link', { name: /^single interactive element/ })).toHaveFocus();
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
render: () => (
|
|
124
|
+
<List>
|
|
125
|
+
<ListItem
|
|
126
|
+
title={title.full}
|
|
127
|
+
subtitle={subtitle.full}
|
|
128
|
+
additionalInfo={additionalInfo.static}
|
|
129
|
+
control={button.full}
|
|
130
|
+
prompt={prompt.interactive}
|
|
131
|
+
/>
|
|
132
|
+
</List>
|
|
133
|
+
),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const PartiallyInteractiveFocusedOnControl: Story = {
|
|
137
|
+
play: async ({ canvasElement }) => {
|
|
138
|
+
const canvas = within(canvasElement);
|
|
139
|
+
await waitForListItem(canvas);
|
|
140
|
+
await userEvent.tab();
|
|
141
|
+
await waitForFocus(async () => {
|
|
142
|
+
await expect(canvas.getByRole('button')).toHaveFocus();
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
render: () => (
|
|
146
|
+
<List>
|
|
147
|
+
<ListItem
|
|
148
|
+
title={title.partial}
|
|
149
|
+
subtitle={subtitle.partial}
|
|
150
|
+
additionalInfo={additionalInfo.interactive}
|
|
151
|
+
control={button.partial}
|
|
152
|
+
prompt={prompt.interactive}
|
|
153
|
+
/>
|
|
154
|
+
</List>
|
|
155
|
+
),
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export const PartiallyInteractiveFocusedOnAdditionInfo: Story = {
|
|
159
|
+
play: async ({ canvasElement }) => {
|
|
160
|
+
const canvas = within(canvasElement);
|
|
161
|
+
await waitForListItem(canvas);
|
|
162
|
+
|
|
163
|
+
await userEvent.tab();
|
|
164
|
+
await waitForFocus(async () => {
|
|
165
|
+
await expect(canvas.getByRole('button')).toHaveFocus();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await userEvent.tab();
|
|
169
|
+
await waitForFocus(async () => {
|
|
170
|
+
await expect(canvas.getByRole('link', { name: /^appended to the end/ })).toHaveFocus();
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
render: () => (
|
|
174
|
+
<List>
|
|
175
|
+
<ListItem
|
|
176
|
+
title={title.partial}
|
|
177
|
+
subtitle={subtitle.partial}
|
|
178
|
+
additionalInfo={additionalInfo.interactive}
|
|
179
|
+
control={button.partial}
|
|
180
|
+
prompt={prompt.interactive}
|
|
181
|
+
/>
|
|
182
|
+
</List>
|
|
183
|
+
),
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const PartiallyInteractiveFocusedOnPrompt: Story = {
|
|
187
|
+
play: async ({ canvasElement }) => {
|
|
188
|
+
const canvas = within(canvasElement);
|
|
189
|
+
await waitForListItem(canvas);
|
|
190
|
+
|
|
191
|
+
await userEvent.tab();
|
|
192
|
+
await waitForFocus(async () => {
|
|
193
|
+
await expect(canvas.getByRole('button')).toHaveFocus();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
await userEvent.tab();
|
|
197
|
+
await waitForFocus(async () => {
|
|
198
|
+
await expect(canvas.getByRole('link', { name: /^appended to the end/ })).toHaveFocus();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
await userEvent.tab();
|
|
202
|
+
await waitForFocus(async () => {
|
|
203
|
+
await expect(canvas.getByRole('link', { name: /^single interactive element/ })).toHaveFocus();
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
render: () => (
|
|
207
|
+
<List>
|
|
208
|
+
<ListItem
|
|
209
|
+
title={title.partial}
|
|
210
|
+
subtitle={subtitle.partial}
|
|
211
|
+
additionalInfo={additionalInfo.interactive}
|
|
212
|
+
control={button.partial}
|
|
213
|
+
prompt={prompt.interactive}
|
|
214
|
+
/>
|
|
215
|
+
</List>
|
|
216
|
+
),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export const FullyInteractiveDisabled: Story = {
|
|
220
|
+
play: async ({ canvasElement }) => {
|
|
221
|
+
const canvas = within(canvasElement);
|
|
222
|
+
await waitForListItem(canvas);
|
|
223
|
+
|
|
224
|
+
await userEvent.tab();
|
|
225
|
+
await waitForFocus(async () => {
|
|
226
|
+
await expect(canvas.getByRole('button')).not.toHaveFocus();
|
|
227
|
+
});
|
|
228
|
+
},
|
|
229
|
+
render: () => (
|
|
230
|
+
<List>
|
|
231
|
+
<ListItem
|
|
232
|
+
disabled
|
|
233
|
+
title={title.full}
|
|
234
|
+
subtitle={subtitle.full}
|
|
235
|
+
additionalInfo={additionalInfo.static}
|
|
236
|
+
control={button.full}
|
|
237
|
+
prompt={prompt.static}
|
|
238
|
+
/>
|
|
239
|
+
</List>
|
|
240
|
+
),
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export const PartiallyInteractiveDisabled: Story = {
|
|
244
|
+
play: async ({ canvasElement }) => {
|
|
245
|
+
const canvas = within(canvasElement);
|
|
246
|
+
await waitForListItem(canvas);
|
|
247
|
+
|
|
248
|
+
await userEvent.tab();
|
|
249
|
+
await waitForFocus(async () => {
|
|
250
|
+
await expect(canvas.getByRole('button')).not.toHaveFocus();
|
|
251
|
+
});
|
|
252
|
+
},
|
|
253
|
+
render: () => (
|
|
254
|
+
<List>
|
|
255
|
+
<ListItem
|
|
256
|
+
disabled
|
|
257
|
+
title={title.partial}
|
|
258
|
+
subtitle={subtitle.partial}
|
|
259
|
+
additionalInfo={additionalInfo.interactive}
|
|
260
|
+
control={button.partial}
|
|
261
|
+
prompt={prompt.interactive}
|
|
262
|
+
/>
|
|
263
|
+
</List>
|
|
264
|
+
),
|
|
265
|
+
};
|