@transferwise/components 0.0.0-experimental-d7fd1c8 → 0.0.0-experimental-55ad5c7
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/listItem/AvatarLayout/ListItemAvatarLayout.js +2 -0
- package/build/listItem/AvatarLayout/ListItemAvatarLayout.js.map +1 -1
- package/build/listItem/AvatarLayout/ListItemAvatarLayout.mjs +2 -0
- package/build/listItem/AvatarLayout/ListItemAvatarLayout.mjs.map +1 -1
- package/build/listItem/AvatarView/ListItemAvatarView.js +2 -0
- package/build/listItem/AvatarView/ListItemAvatarView.js.map +1 -1
- package/build/listItem/AvatarView/ListItemAvatarView.mjs +2 -0
- package/build/listItem/AvatarView/ListItemAvatarView.mjs.map +1 -1
- package/build/listItem/Image/ListItemImage.js +3 -0
- package/build/listItem/Image/ListItemImage.js.map +1 -1
- package/build/listItem/Image/ListItemImage.mjs +3 -0
- package/build/listItem/Image/ListItemImage.mjs.map +1 -1
- package/build/listItem/ListItem.js +13 -7
- package/build/listItem/ListItem.js.map +1 -1
- package/build/listItem/ListItem.mjs +13 -7
- package/build/listItem/ListItem.mjs.map +1 -1
- package/build/listItem/ListItemContext.js.map +1 -1
- package/build/listItem/ListItemContext.mjs.map +1 -1
- package/build/listItem/Navigation/ListItemNavigation.js +1 -1
- package/build/listItem/Navigation/ListItemNavigation.js.map +1 -1
- package/build/listItem/Navigation/ListItemNavigation.mjs +1 -1
- package/build/listItem/Navigation/ListItemNavigation.mjs.map +1 -1
- 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 +23 -12
- package/build/styles/listItem/ListItem.css +23 -12
- package/build/styles/listItem/ListItem.grid.css +7 -7
- package/build/styles/main.css +23 -12
- package/build/types/listItem/AvatarLayout/ListItemAvatarLayout.d.ts.map +1 -1
- package/build/types/listItem/AvatarView/ListItemAvatarView.d.ts.map +1 -1
- package/build/types/listItem/Image/ListItemImage.d.ts +5 -1
- package/build/types/listItem/Image/ListItemImage.d.ts.map +1 -1
- package/build/types/listItem/ListItem.d.ts +1 -1
- package/build/types/listItem/ListItem.d.ts.map +1 -1
- package/build/types/listItem/ListItemContext.d.ts +3 -0
- package/build/types/listItem/ListItemContext.d.ts.map +1 -1
- package/build/types/listItem/_stories/subcomponents.d.ts.map +1 -1
- 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/useListItemMedia.d.ts +5 -0
- package/build/types/listItem/useListItemMedia.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/listItem/AvatarLayout/ListItemAvatarLayout.tsx +3 -0
- package/src/listItem/AvatarView/ListItemAvatarView.tsx +3 -0
- package/src/listItem/Button/ListItemButton.spec.tsx +10 -35
- package/src/listItem/Image/ListItemImage.spec.tsx +8 -5
- package/src/listItem/Image/ListItemImage.story.tsx +2 -1
- package/src/listItem/Image/ListItemImage.tsx +8 -1
- package/src/listItem/ListItem.css +23 -12
- package/src/listItem/ListItem.grid.css +7 -7
- package/src/listItem/ListItem.grid.less +11 -11
- package/src/listItem/ListItem.less +20 -7
- package/src/listItem/ListItem.tsx +24 -12
- package/src/listItem/ListItemContext.tsx +5 -0
- package/src/listItem/Navigation/ListItemNavigation.tsx +1 -1
- package/src/listItem/_stories/ListItem.story.tsx +2 -39
- package/src/listItem/_stories/ListItem.variants.test.story.tsx +7 -2
- package/src/listItem/_stories/subcomponents.tsx +1 -0
- package/src/listItem/test-utils.tsx +33 -0
- package/src/listItem/useListItemMedia.tsx +12 -0
- package/src/main.css +23 -12
|
@@ -1,49 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { screen, mockMatchMedia } from '../../test-utils';
|
|
2
2
|
import { Button as ItemButton } from './ListItemButton';
|
|
3
3
|
import { ButtonPriority } from '../../button/Button.types';
|
|
4
|
-
import {
|
|
4
|
+
import { renderWithListItemContext, clearListItemMocks, mockSetControlType } from '../test-utils';
|
|
5
5
|
|
|
6
6
|
mockMatchMedia();
|
|
7
7
|
|
|
8
8
|
describe('ItemButton', () => {
|
|
9
|
-
const mockSetControlType = jest.fn();
|
|
10
|
-
const mockSetControlProps = jest.fn();
|
|
11
|
-
|
|
12
|
-
const renderWithItemContext = (ui: React.ReactNode) => {
|
|
13
|
-
return render(
|
|
14
|
-
<ListItemContext.Provider
|
|
15
|
-
value={{
|
|
16
|
-
setControlType: mockSetControlType,
|
|
17
|
-
setControlProps: mockSetControlProps,
|
|
18
|
-
ids: {
|
|
19
|
-
title: 'title',
|
|
20
|
-
additionalInfo: 'additional Info',
|
|
21
|
-
valueTitle: 'value title',
|
|
22
|
-
control: 'control',
|
|
23
|
-
prompt: 'prompt',
|
|
24
|
-
},
|
|
25
|
-
props: {},
|
|
26
|
-
describedByIds: 'described-by-ids',
|
|
27
|
-
}}
|
|
28
|
-
>
|
|
29
|
-
{ui}
|
|
30
|
-
</ListItemContext.Provider>,
|
|
31
|
-
);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
9
|
beforeEach(() => {
|
|
35
|
-
|
|
10
|
+
clearListItemMocks();
|
|
36
11
|
});
|
|
37
12
|
|
|
38
13
|
it('always sets v2 to true', () => {
|
|
39
|
-
|
|
14
|
+
renderWithListItemContext(<ItemButton priority="primary">Test Button</ItemButton>);
|
|
40
15
|
const button = screen.getByRole('button');
|
|
41
16
|
expect(button).toBeInTheDocument();
|
|
42
17
|
expect(mockSetControlType).toHaveBeenCalledWith('button');
|
|
43
18
|
});
|
|
44
19
|
|
|
45
20
|
it('always sets size to "sm"', () => {
|
|
46
|
-
|
|
21
|
+
renderWithListItemContext(<ItemButton priority="primary">Test Button</ItemButton>);
|
|
47
22
|
const button = screen.getByRole('button');
|
|
48
23
|
expect(button).toHaveClass('wds-Button--small');
|
|
49
24
|
});
|
|
@@ -51,21 +26,21 @@ describe('ItemButton', () => {
|
|
|
51
26
|
it('supports all priorities', () => {
|
|
52
27
|
const priorities: ButtonPriority[] = ['primary', 'secondary', 'tertiary'];
|
|
53
28
|
priorities.forEach((priority) => {
|
|
54
|
-
|
|
29
|
+
renderWithListItemContext(<ItemButton priority={priority}>Test {priority}</ItemButton>);
|
|
55
30
|
const button = screen.getByRole('button', { name: `Test ${priority}` });
|
|
56
31
|
expect(button).toBeInTheDocument();
|
|
57
32
|
});
|
|
58
33
|
});
|
|
59
34
|
|
|
60
35
|
it('renders as a button by default', () => {
|
|
61
|
-
|
|
36
|
+
renderWithListItemContext(<ItemButton>Click me</ItemButton>);
|
|
62
37
|
const button = screen.getByRole('button');
|
|
63
38
|
expect(button).toBeInTheDocument();
|
|
64
39
|
expect(button.tagName).toBe('BUTTON');
|
|
65
40
|
});
|
|
66
41
|
|
|
67
42
|
it('renders as an anchor when href is provided', () => {
|
|
68
|
-
|
|
43
|
+
renderWithListItemContext(<ItemButton href="https://example.com">Go to Example</ItemButton>);
|
|
69
44
|
const link = screen.getByRole('link', { name: 'Go to Example' });
|
|
70
45
|
expect(link).toBeInTheDocument();
|
|
71
46
|
expect(link.tagName).toBe('A');
|
|
@@ -73,14 +48,14 @@ describe('ItemButton', () => {
|
|
|
73
48
|
});
|
|
74
49
|
|
|
75
50
|
it('spreads additional props to the button', () => {
|
|
76
|
-
|
|
51
|
+
renderWithListItemContext(<ItemButton aria-label="Custom Button">Custom</ItemButton>);
|
|
77
52
|
const button = screen.getByRole('button', { name: 'Custom Button' });
|
|
78
53
|
expect(button).toBeInTheDocument();
|
|
79
54
|
expect(button).toHaveAttribute('aria-label', 'Custom Button');
|
|
80
55
|
});
|
|
81
56
|
|
|
82
57
|
it('spreads additional props to the anchor', () => {
|
|
83
|
-
|
|
58
|
+
renderWithListItemContext(
|
|
84
59
|
<ItemButton href="https://example.com" target="_blank" aria-label="Custom Link">
|
|
85
60
|
Custom Link
|
|
86
61
|
</ItemButton>,
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { render, screen } from '../../test-utils';
|
|
2
|
-
import { ListItem } from '../ListItem';
|
|
2
|
+
import { ListItem, type Props as ListItemProps } from '../ListItem';
|
|
3
|
+
|
|
4
|
+
const renderWithMedia = (media: ListItemProps['media']) =>
|
|
5
|
+
render(<ListItem title="Test Title" media={media} />);
|
|
3
6
|
|
|
4
7
|
describe('ListItem.Image', () => {
|
|
5
8
|
it('renders image with presentation role when no alt text', () => {
|
|
6
|
-
|
|
9
|
+
renderWithMedia(<ListItem.Image src="test-image.jpg" />);
|
|
7
10
|
expect(screen.getByRole('presentation')).toHaveAttribute('src', 'test-image.jpg');
|
|
8
11
|
});
|
|
9
12
|
|
|
10
13
|
it('renders image with graphics-symbol role when alt text provided', () => {
|
|
11
|
-
|
|
14
|
+
renderWithMedia(<ListItem.Image src="test-image.jpg" alt="Test image description" />);
|
|
12
15
|
|
|
13
16
|
const image = screen.getByRole('graphics-symbol');
|
|
14
17
|
expect(image).toHaveAttribute('alt', 'Test image description');
|
|
@@ -16,12 +19,12 @@ describe('ListItem.Image', () => {
|
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
it('renders image with loading prop', () => {
|
|
19
|
-
|
|
22
|
+
renderWithMedia(<ListItem.Image src="test-image.jpg" loading="lazy" />);
|
|
20
23
|
expect(screen.getByRole('presentation')).toHaveAttribute('loading', 'lazy');
|
|
21
24
|
});
|
|
22
25
|
|
|
23
26
|
it('renders image with className prop', () => {
|
|
24
|
-
|
|
27
|
+
renderWithMedia(<ListItem.Image src="test-image.jpg" className="custom-image-class" />);
|
|
25
28
|
expect(screen.getByRole('presentation')).toHaveClass('custom-image-class');
|
|
26
29
|
});
|
|
27
30
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import ImageComp, { type ImageProps } from '../../image';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
|
+
import { useListItemMedia } from '../useListItemMedia';
|
|
3
4
|
|
|
4
5
|
type SizeProp = {};
|
|
5
6
|
|
|
@@ -8,6 +9,10 @@ export type ListItemImageProps = Omit<ImageProps, 'stretch' | 'shrink' | 'id' |
|
|
|
8
9
|
* The size of square container for the image, matching available avatar sizes.
|
|
9
10
|
*/
|
|
10
11
|
size?: 32 | 40 | 48 | 56 | 72;
|
|
12
|
+
/**
|
|
13
|
+
* If you're using an image that isn't a square or circle, also tell us the height so that we can align the control to it properly.
|
|
14
|
+
*/
|
|
15
|
+
height?: number;
|
|
11
16
|
/**
|
|
12
17
|
* When unset, it will force `role="presentation"` on the image. Otherwise, it will set `role="graphics-symbol"`.
|
|
13
18
|
*/
|
|
@@ -23,7 +28,9 @@ export type ListItemImageProps = Omit<ImageProps, 'stretch' | 'shrink' | 'id' |
|
|
|
23
28
|
*
|
|
24
29
|
* > **NB**: This component is [not intended for use with illustrations](https://wise.design/foundations/illustration#scale).
|
|
25
30
|
*/
|
|
26
|
-
export const Image = ({ alt = '', size = 48, ...props }: ListItemImageProps) => {
|
|
31
|
+
export const Image = ({ alt = '', size = 48, height, ...props }: ListItemImageProps) => {
|
|
32
|
+
useListItemMedia(height ?? size);
|
|
33
|
+
|
|
27
34
|
return (
|
|
28
35
|
<div
|
|
29
36
|
className={clsx('wds-list-item-media-image')}
|
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-hasInfo-hasPrompt {
|
|
10
10
|
grid-template-columns: auto 1fr auto;
|
|
11
11
|
grid-template-rows: auto auto auto;
|
|
12
|
-
grid-template-areas: "media body control" "media info
|
|
12
|
+
grid-template-areas: "media body control" "media info ." ". prompt prompt";
|
|
13
13
|
}
|
|
14
14
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-hasInfo-noPrompt {
|
|
15
15
|
grid-template-columns: auto 1fr auto;
|
|
16
16
|
grid-template-rows: auto auto;
|
|
17
|
-
grid-template-areas: "media body control" "media info
|
|
17
|
+
grid-template-areas: "media body control" "media info .";
|
|
18
18
|
}
|
|
19
19
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-noInfo-hasPrompt {
|
|
20
20
|
grid-template-columns: auto 1fr auto;
|
|
21
21
|
grid-template-rows: auto auto;
|
|
22
|
-
grid-template-areas: "media body control" "
|
|
22
|
+
grid-template-areas: "media body control" ". prompt prompt";
|
|
23
23
|
}
|
|
24
24
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-noInfo-noPrompt {
|
|
25
25
|
grid-template-columns: auto 1fr auto;
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-noControl.wds-list-item-hasInfo-hasPrompt {
|
|
30
30
|
grid-template-columns: auto 1fr;
|
|
31
31
|
grid-template-rows: auto auto;
|
|
32
|
-
grid-template-areas: "media body" "media info" "
|
|
32
|
+
grid-template-areas: "media body" "media info" ". prompt";
|
|
33
33
|
}
|
|
34
34
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-noControl.wds-list-item-hasInfo-noPrompt {
|
|
35
35
|
grid-template-columns: auto 1fr;
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
.wds-list-item-gridWrapper.wds-list-item-noMedia-hasControl.wds-list-item-hasInfo-hasPrompt {
|
|
53
53
|
grid-template-columns: 1fr auto;
|
|
54
54
|
grid-template-rows: auto auto auto;
|
|
55
|
-
grid-template-areas: "body control" "info
|
|
55
|
+
grid-template-areas: "body control" "info ." "prompt prompt";
|
|
56
56
|
}
|
|
57
57
|
.wds-list-item-gridWrapper.wds-list-item-noMedia-hasControl.wds-list-item-hasInfo-noPrompt {
|
|
58
58
|
grid-template-columns: 1fr auto;
|
|
59
59
|
grid-template-rows: auto auto;
|
|
60
|
-
grid-template-areas: "body control" "info
|
|
60
|
+
grid-template-areas: "body control" "info .";
|
|
61
61
|
}
|
|
62
62
|
.wds-list-item-gridWrapper.wds-list-item-noMedia-hasControl.wds-list-item-noInfo-hasPrompt {
|
|
63
63
|
grid-template-columns: 1fr auto;
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
grid-template-areas: "body";
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
-
@container (max-width:
|
|
224
|
+
@container (max-width: 297px) {
|
|
225
225
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-hasInfo-hasPrompt {
|
|
226
226
|
grid-template-columns: auto 1fr;
|
|
227
227
|
grid-template-rows: auto auto auto;
|
|
@@ -450,7 +450,8 @@
|
|
|
450
450
|
}
|
|
451
451
|
.wds-list-item-media-image {
|
|
452
452
|
width: var(--item-media-image-size);
|
|
453
|
-
height:
|
|
453
|
+
height: auto;
|
|
454
|
+
height: var(--wds-list-item-control-wrapper-height, auto);
|
|
454
455
|
}
|
|
455
456
|
.wds-list-item-body {
|
|
456
457
|
grid-area: body;
|
|
@@ -468,6 +469,14 @@
|
|
|
468
469
|
color: #37517e;
|
|
469
470
|
color: var(--color-content-primary);
|
|
470
471
|
}
|
|
472
|
+
.wds-list-item-value {
|
|
473
|
+
text-align: right;
|
|
474
|
+
}
|
|
475
|
+
.wds-list-item-body-center {
|
|
476
|
+
display: flex;
|
|
477
|
+
flex-direction: row;
|
|
478
|
+
align-items: center;
|
|
479
|
+
}
|
|
471
480
|
.wds-list-item-additional-info {
|
|
472
481
|
grid-area: info;
|
|
473
482
|
color: #768e9c;
|
|
@@ -475,12 +484,14 @@
|
|
|
475
484
|
margin-top: calc(4px * -1);
|
|
476
485
|
margin-top: calc(var(--size-4) * -1);
|
|
477
486
|
}
|
|
478
|
-
.wds-list-item-value {
|
|
479
|
-
align-items: end;
|
|
480
|
-
text-align: right;
|
|
481
|
-
}
|
|
482
487
|
.wds-list-item-control-wrapper {
|
|
483
488
|
grid-area: control;
|
|
489
|
+
align-content: center;
|
|
490
|
+
max-height: var(--wds-list-item-control-wrapper-height);
|
|
491
|
+
}
|
|
492
|
+
.wds-list-item-navigation .tw-icon-chevron-right {
|
|
493
|
+
color: #c9cbce;
|
|
494
|
+
color: var(--color-interactive-secondary);
|
|
484
495
|
}
|
|
485
496
|
.wds-list-item-control {
|
|
486
497
|
flex: 0 0 auto;
|
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-hasInfo-hasPrompt {
|
|
10
10
|
grid-template-columns: auto 1fr auto;
|
|
11
11
|
grid-template-rows: auto auto auto;
|
|
12
|
-
grid-template-areas: "media body control" "media info
|
|
12
|
+
grid-template-areas: "media body control" "media info ." ". prompt prompt";
|
|
13
13
|
}
|
|
14
14
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-hasInfo-noPrompt {
|
|
15
15
|
grid-template-columns: auto 1fr auto;
|
|
16
16
|
grid-template-rows: auto auto;
|
|
17
|
-
grid-template-areas: "media body control" "media info
|
|
17
|
+
grid-template-areas: "media body control" "media info .";
|
|
18
18
|
}
|
|
19
19
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-noInfo-hasPrompt {
|
|
20
20
|
grid-template-columns: auto 1fr auto;
|
|
21
21
|
grid-template-rows: auto auto;
|
|
22
|
-
grid-template-areas: "media body control" "
|
|
22
|
+
grid-template-areas: "media body control" ". prompt prompt";
|
|
23
23
|
}
|
|
24
24
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-noInfo-noPrompt {
|
|
25
25
|
grid-template-columns: auto 1fr auto;
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-noControl.wds-list-item-hasInfo-hasPrompt {
|
|
30
30
|
grid-template-columns: auto 1fr;
|
|
31
31
|
grid-template-rows: auto auto;
|
|
32
|
-
grid-template-areas: "media body" "media info" "
|
|
32
|
+
grid-template-areas: "media body" "media info" ". prompt";
|
|
33
33
|
}
|
|
34
34
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-noControl.wds-list-item-hasInfo-noPrompt {
|
|
35
35
|
grid-template-columns: auto 1fr;
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
.wds-list-item-gridWrapper.wds-list-item-noMedia-hasControl.wds-list-item-hasInfo-hasPrompt {
|
|
53
53
|
grid-template-columns: 1fr auto;
|
|
54
54
|
grid-template-rows: auto auto auto;
|
|
55
|
-
grid-template-areas: "body control" "info
|
|
55
|
+
grid-template-areas: "body control" "info ." "prompt prompt";
|
|
56
56
|
}
|
|
57
57
|
.wds-list-item-gridWrapper.wds-list-item-noMedia-hasControl.wds-list-item-hasInfo-noPrompt {
|
|
58
58
|
grid-template-columns: 1fr auto;
|
|
59
59
|
grid-template-rows: auto auto;
|
|
60
|
-
grid-template-areas: "body control" "info
|
|
60
|
+
grid-template-areas: "body control" "info .";
|
|
61
61
|
}
|
|
62
62
|
.wds-list-item-gridWrapper.wds-list-item-noMedia-hasControl.wds-list-item-noInfo-hasPrompt {
|
|
63
63
|
grid-template-columns: 1fr auto;
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
grid-template-areas: "body";
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
-
@container (max-width:
|
|
224
|
+
@container (max-width: 297px) {
|
|
225
225
|
.wds-list-item-gridWrapper.wds-list-item-hasMedia-hasControl.wds-list-item-hasInfo-hasPrompt {
|
|
226
226
|
grid-template-columns: auto 1fr;
|
|
227
227
|
grid-template-rows: auto auto auto;
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
grid-template-rows: auto auto auto;
|
|
11
11
|
grid-template-areas:
|
|
12
12
|
"media body control"
|
|
13
|
-
"media info
|
|
14
|
-
"
|
|
13
|
+
"media info ."
|
|
14
|
+
". prompt prompt";
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
&.wds-list-item-hasInfo-noPrompt {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
grid-template-rows: auto auto;
|
|
20
20
|
grid-template-areas:
|
|
21
21
|
"media body control"
|
|
22
|
-
"media info
|
|
22
|
+
"media info ."
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
&.wds-list-item-noInfo-hasPrompt {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
grid-template-rows: auto auto;
|
|
28
28
|
grid-template-areas:
|
|
29
29
|
"media body control"
|
|
30
|
-
"
|
|
30
|
+
". prompt prompt";
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
&.wds-list-item-noInfo-noPrompt {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
grid-template-areas:
|
|
46
46
|
"media body"
|
|
47
47
|
"media info"
|
|
48
|
-
"
|
|
48
|
+
". prompt";
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
&.wds-list-item-hasInfo-noPrompt {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
grid-template-rows: auto auto auto;
|
|
54
54
|
grid-template-areas:
|
|
55
55
|
"media body"
|
|
56
|
-
"media info"
|
|
56
|
+
"media info"
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
&.wds-list-item-noInfo-hasPrompt {
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
grid-template-rows: auto auto auto;
|
|
83
83
|
grid-template-areas:
|
|
84
84
|
"body control"
|
|
85
|
-
"info
|
|
85
|
+
"info ."
|
|
86
86
|
"prompt prompt";
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
grid-template-rows: auto auto;
|
|
92
92
|
grid-template-areas:
|
|
93
93
|
"body control"
|
|
94
|
-
"info
|
|
94
|
+
"info ."
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
&.wds-list-item-noInfo-hasPrompt {
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
grid-template-rows: auto auto auto;
|
|
247
247
|
grid-template-areas:
|
|
248
248
|
"media media"
|
|
249
|
-
"body body"
|
|
249
|
+
"body body"
|
|
250
250
|
"info info";
|
|
251
251
|
}
|
|
252
252
|
|
|
@@ -378,7 +378,7 @@
|
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
-
@container (max-width:
|
|
381
|
+
@container (max-width: 297px) {
|
|
382
382
|
&.wds-list-item-hasMedia-hasControl {
|
|
383
383
|
&.wds-list-item-hasInfo-hasPrompt {
|
|
384
384
|
grid-template-columns: auto 1fr;
|
|
@@ -461,7 +461,7 @@
|
|
|
461
461
|
grid-template-rows: auto auto auto;
|
|
462
462
|
grid-template-areas:
|
|
463
463
|
"body"
|
|
464
|
-
"info"
|
|
464
|
+
"info"
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
&.wds-list-item-noInfo-hasPrompt {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
|
|
111
111
|
&-image {
|
|
112
112
|
width: var(--item-media-image-size);
|
|
113
|
-
height: var(--item-
|
|
113
|
+
height: var(--wds-list-item-control-wrapper-height, auto);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -124,7 +124,17 @@
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
&-title {
|
|
127
|
-
|
|
127
|
+
color: var(--color-content-primary);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&-value {
|
|
131
|
+
text-align: right;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&-body-center {
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-direction: row;
|
|
137
|
+
align-items: center;
|
|
128
138
|
}
|
|
129
139
|
|
|
130
140
|
&-additional-info {
|
|
@@ -133,13 +143,16 @@
|
|
|
133
143
|
margin-top: calc(var(--size-4) * -1);
|
|
134
144
|
}
|
|
135
145
|
|
|
136
|
-
&-value {
|
|
137
|
-
align-items: end;
|
|
138
|
-
text-align: right;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
146
|
&-control-wrapper {
|
|
142
147
|
grid-area: control;
|
|
148
|
+
align-content: center;
|
|
149
|
+
max-height: var(--wds-list-item-control-wrapper-height);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
&-navigation {
|
|
153
|
+
.tw-icon-chevron-right {
|
|
154
|
+
color: var(--color-interactive-secondary);
|
|
155
|
+
}
|
|
143
156
|
}
|
|
144
157
|
|
|
145
158
|
&-control {
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
useId,
|
|
5
5
|
useMemo,
|
|
6
6
|
useState,
|
|
7
|
+
useEffect,
|
|
7
8
|
type PropsWithChildren,
|
|
8
9
|
type ReactNode,
|
|
9
10
|
} from 'react';
|
|
@@ -22,7 +23,11 @@ import { AvatarView } from './AvatarView';
|
|
|
22
23
|
import { Image } from './Image';
|
|
23
24
|
import { Prompt } from './Prompt';
|
|
24
25
|
import { PrimitiveAnchor } from '../primitives';
|
|
25
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
ListItemContext,
|
|
28
|
+
type ListItemContextData,
|
|
29
|
+
type ListItemMediaSize,
|
|
30
|
+
} from './ListItemContext';
|
|
26
31
|
|
|
27
32
|
export type ListItemTypes =
|
|
28
33
|
| 'non-interactive'
|
|
@@ -119,6 +124,8 @@ export const ListItem = ({
|
|
|
119
124
|
const idPrefix = useId();
|
|
120
125
|
const [controlProps, setControlProps] = useState<ListItemControlProps>({});
|
|
121
126
|
const [controlType, setControlType] = useState<ListItemTypes>('non-interactive');
|
|
127
|
+
const [mediaSize, setMediaSize] = useState<number | undefined>();
|
|
128
|
+
|
|
122
129
|
const ids: ListItemContextData['ids'] = {
|
|
123
130
|
title: `${idPrefix}_title`,
|
|
124
131
|
...(subtitle ? { subtitle: `${idPrefix}_subtitle` } : {}),
|
|
@@ -156,11 +163,13 @@ export const ListItem = ({
|
|
|
156
163
|
() => ({
|
|
157
164
|
setControlType,
|
|
158
165
|
setControlProps,
|
|
166
|
+
setMediaSize,
|
|
159
167
|
ids,
|
|
160
168
|
props: { disabled, inverted },
|
|
169
|
+
mediaSize,
|
|
161
170
|
describedByIds,
|
|
162
171
|
}),
|
|
163
|
-
[describedByIds],
|
|
172
|
+
[describedByIds, mediaSize],
|
|
164
173
|
);
|
|
165
174
|
const gridColumnsStyle = {
|
|
166
175
|
'--wds-list-item-body-left': valueColumnWidth ? `${100 - valueColumnWidth}fr` : '50fr',
|
|
@@ -247,7 +256,11 @@ export const ListItem = ({
|
|
|
247
256
|
style={valueColumnWidth ? gridColumnsStyle : undefined}
|
|
248
257
|
>
|
|
249
258
|
{/* Title + Subtitle + Values - Group */}
|
|
250
|
-
<span
|
|
259
|
+
<span
|
|
260
|
+
className={clsx({
|
|
261
|
+
'wds-list-item-body-center': title && !subtitle,
|
|
262
|
+
})}
|
|
263
|
+
>
|
|
251
264
|
{(() => {
|
|
252
265
|
const titles = [
|
|
253
266
|
<Body
|
|
@@ -274,6 +287,8 @@ export const ListItem = ({
|
|
|
274
287
|
<span
|
|
275
288
|
className={clsx('wds-list-item-value', {
|
|
276
289
|
'flex-column': valueTitle !== undefined || valueSubtitle !== undefined,
|
|
290
|
+
'wds-list-item-body-center':
|
|
291
|
+
(valueTitle && !valueSubtitle) || (!valueTitle && valueSubtitle),
|
|
277
292
|
})}
|
|
278
293
|
>
|
|
279
294
|
{(() => {
|
|
@@ -312,6 +327,11 @@ export const ListItem = ({
|
|
|
312
327
|
className={clsx('wds-list-item-control-wrapper', {
|
|
313
328
|
'wds-list-item-button-control': controlType === 'button',
|
|
314
329
|
})}
|
|
330
|
+
style={
|
|
331
|
+
{
|
|
332
|
+
'--wds-list-item-control-wrapper-height': mediaSize ? `${mediaSize}px` : 'auto',
|
|
333
|
+
} as React.CSSProperties
|
|
334
|
+
}
|
|
315
335
|
>
|
|
316
336
|
{control}
|
|
317
337
|
</Body>
|
|
@@ -364,7 +384,6 @@ function View({
|
|
|
364
384
|
href={(controlProps as ListItemNavigationProps)?.href}
|
|
365
385
|
target={(controlProps as ListItemNavigationProps)?.target}
|
|
366
386
|
className={clsx('wds-list-item-view d-flex flex-row', {
|
|
367
|
-
'align-items-center': !subtitle,
|
|
368
387
|
'wds-list-item-control': controlType === 'navigation',
|
|
369
388
|
})}
|
|
370
389
|
disabled={disabled}
|
|
@@ -380,13 +399,7 @@ function View({
|
|
|
380
399
|
if (isPartiallyInteractive || controlType === 'non-interactive') {
|
|
381
400
|
return (
|
|
382
401
|
<div className={clsx('wds-list-item-gridWrapper', className)}>
|
|
383
|
-
<div
|
|
384
|
-
className={clsx('wds-list-item-view d-flex flex-row', {
|
|
385
|
-
'align-items-center': !subtitle,
|
|
386
|
-
})}
|
|
387
|
-
>
|
|
388
|
-
{children}
|
|
389
|
-
</div>
|
|
402
|
+
<div className={clsx('wds-list-item-view d-flex flex-row')}>{children}</div>
|
|
390
403
|
|
|
391
404
|
{renderExtras()}
|
|
392
405
|
</div>
|
|
@@ -401,7 +414,6 @@ function View({
|
|
|
401
414
|
<label
|
|
402
415
|
htmlFor={ids.control}
|
|
403
416
|
className={clsx('wds-list-item-view', {
|
|
404
|
-
'align-items-center': !subtitle,
|
|
405
417
|
clickable: !disabled,
|
|
406
418
|
fullyInteractive: !isPartiallyInteractive,
|
|
407
419
|
})}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { createContext } from 'react';
|
|
2
2
|
import type { ListItemTypes, ListItemControlProps, Props as ListItemProps } from './ListItem';
|
|
3
|
+
import type { ListItemAvatarViewProps } from './AvatarView';
|
|
4
|
+
|
|
5
|
+
export type ListItemMediaSize = 32 | 40 | 48 | 56 | 72;
|
|
3
6
|
|
|
4
7
|
export type ListItemContextData = {
|
|
5
8
|
setControlType: (type: ListItemTypes) => void;
|
|
6
9
|
setControlProps: (props: ListItemControlProps) => void;
|
|
10
|
+
setMediaSize: (size: number | undefined) => void;
|
|
7
11
|
ids: {
|
|
8
12
|
title: string;
|
|
9
13
|
subtitle?: string;
|
|
@@ -14,6 +18,7 @@ export type ListItemContextData = {
|
|
|
14
18
|
prompt?: string;
|
|
15
19
|
};
|
|
16
20
|
props: Pick<ListItemProps, 'disabled' | 'inverted'>;
|
|
21
|
+
mediaSize?: number;
|
|
17
22
|
describedByIds: string;
|
|
18
23
|
};
|
|
19
24
|
|
|
@@ -19,7 +19,7 @@ export const Navigation = function Navigation({ href = '#', ...props }: ListItem
|
|
|
19
19
|
const { baseItemProps } = useListItemControl('navigation', { href, ...props });
|
|
20
20
|
const { ids, describedByIds } = useContext(ListItemContext);
|
|
21
21
|
const isLink = href !== '#';
|
|
22
|
-
const icon = <ChevronRight size={
|
|
22
|
+
const icon = <ChevronRight size={16} />;
|
|
23
23
|
|
|
24
24
|
if (baseItemProps.disabled) return <BackslashCircle size={24} />;
|
|
25
25
|
|
|
@@ -2,7 +2,6 @@ import { useState } from 'react';
|
|
|
2
2
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
3
3
|
import { MultiCurrency, Plus } from '@transferwise/icons';
|
|
4
4
|
import { lorem5, lorem10 } from '../../test-utils';
|
|
5
|
-
import Emphasis from '../../emphasis';
|
|
6
5
|
import { ListItem, Props as ItemProps } from '../ListItem';
|
|
7
6
|
import {
|
|
8
7
|
SB_LIST_ITEM_CONTROLS as CONTROLS,
|
|
@@ -242,7 +241,7 @@ export const Playground: StoryObj<PreviewStoryArgs> = {
|
|
|
242
241
|
const [props, previewProps] = getPropsForPreview(args);
|
|
243
242
|
|
|
244
243
|
return (
|
|
245
|
-
<ol
|
|
244
|
+
<ol className="list-unstyled">
|
|
246
245
|
<ListItem {...props} {...previewProps} />
|
|
247
246
|
</ol>
|
|
248
247
|
);
|
|
@@ -426,7 +425,7 @@ export const Spotlight: Story = {
|
|
|
426
425
|
* All of these limitations were put in place to ensure that the list item is compliant with
|
|
427
426
|
* accessibility guidance and offers consistent experience across all engineering platforms.
|
|
428
427
|
*
|
|
429
|
-
* Please refer to the [design documentation](https://wise.design/components/list-item
|
|
428
|
+
* Please refer to the [design documentation](https://wise.design/components/list-item#:~:text=specific%20list%20item.-,Interaction,-The%20list%20item) for more details.
|
|
430
429
|
*/
|
|
431
430
|
export const Interactivity: Story = {
|
|
432
431
|
render: function Render() {
|
|
@@ -502,8 +501,6 @@ export const Interactivity: Story = {
|
|
|
502
501
|
* to a new icon for improved user experience and accessibility. <br />
|
|
503
502
|
* For the same reason, only the control part of the List Item is dimmed, while all the content
|
|
504
503
|
* retains high contrast and interactivity.
|
|
505
|
-
*
|
|
506
|
-
* Please refer to the [design documentation](https://wise.design/components/list-item#accessibility:~:text=-,Disabled%20states,-) for more details
|
|
507
504
|
*/
|
|
508
505
|
export const Disabled: Story = {
|
|
509
506
|
parameters: {
|
|
@@ -671,37 +668,3 @@ export const Disabled: Story = {
|
|
|
671
668
|
</div>
|
|
672
669
|
),
|
|
673
670
|
};
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* For backwards compatibility, all of the ListItem's content elements accept `ReactNode`.
|
|
677
|
-
* That said, most of them should be fed with plain text only. The exception is `valueTitle`
|
|
678
|
-
* and `valueSubtitle` which can be augmented with sentiment colours, strikethrough or bold
|
|
679
|
-
* styles. <br />
|
|
680
|
-
*
|
|
681
|
-
* Please refer to the [design documentation](https://wise.design/components/list-item#content) for more details.
|
|
682
|
-
*/
|
|
683
|
-
export const StylingLabels: Story = {
|
|
684
|
-
args: {
|
|
685
|
-
title: lorem5,
|
|
686
|
-
subtitle: lorem10,
|
|
687
|
-
media: MEDIA.image,
|
|
688
|
-
control: CONTROLS.iconButton,
|
|
689
|
-
prompt: PROMPTS.interactive,
|
|
690
|
-
},
|
|
691
|
-
render: function Render(args) {
|
|
692
|
-
return (
|
|
693
|
-
<ol className="list-unstyled">
|
|
694
|
-
<ListItem
|
|
695
|
-
{...args}
|
|
696
|
-
valueTitle={<Emphasis text="<negative>100 GBP</negative>" />}
|
|
697
|
-
valueSubtitle={<s>125 GBP</s>}
|
|
698
|
-
/>
|
|
699
|
-
<ListItem
|
|
700
|
-
{...args}
|
|
701
|
-
valueTitle={<Emphasis text="<positive>100 GBP</positive>" />}
|
|
702
|
-
valueSubtitle={<strong>125 GBP</strong>}
|
|
703
|
-
/>
|
|
704
|
-
</ol>
|
|
705
|
-
);
|
|
706
|
-
},
|
|
707
|
-
};
|