Skip to content

Commit ca1626d

Browse files
committed
Add AvatarStack
1 parent 172297d commit ca1626d

File tree

8 files changed

+238
-0
lines changed

8 files changed

+238
-0
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"no-restricted-imports": 0,
5555
"class-methods-use-this": 0,
5656
"no-use-before-define": 0,
57+
"object-curly-newline": 0,
5758
"react/destructuring-assignment": 0,
5859
"react/no-access-state-in-setstate": "error",
5960
"react/jsx-filename-extension": 0,

config/styleguide.config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"description": "React components",
4040
"components": [
4141
"Avatar",
42+
"AvatarStack",
4243
"BannerNotification",
4344
"BannerNotifications",
4445
"Button",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
Defaults:
2+
```js
3+
<AvatarStack
4+
avatars={[{ src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'admin' }, { src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'staff' }, { src: 'https://static.wikia.nocookie.net/fcdbab4c-8838-487e-89fd-5f0782974edf', alt: 'Image', link: 'some://valid.url', badge: 'vstf' }]}
5+
/>
6+
```
7+
8+
With maxStackSize
9+
10+
```js
11+
<AvatarStack
12+
avatars={[{ src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'admin' }, { src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'staff' }, { src: 'https://static.wikia.nocookie.net/fcdbab4c-8838-487e-89fd-5f0782974edf', alt: 'Image', link: 'some://valid.url', badge: 'vstf' }]}
13+
maxStackSize={2}
14+
/>
15+
```
16+
17+
With hidden overflow
18+
19+
```js
20+
<AvatarStack
21+
avatars={[{ src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'admin' }, { src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'staff' }, { src: 'https://static.wikia.nocookie.net/fcdbab4c-8838-487e-89fd-5f0782974edf', alt: 'Image', link: 'some://valid.url', badge: 'vstf' }]}
22+
maxStackSize={2}
23+
hideOverflow={true}
24+
/>
25+
```
26+
27+
With overridden counter
28+
29+
```js
30+
<AvatarStack
31+
avatars={[{ src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'admin' }, { src: 'https://static.wikia.nocookie.net/438f6e23-1a0f-4351-a34d-6f8fa734a246', alt: 'Image', link: 'some://valid.url', badge: 'staff' }, { src: 'https://static.wikia.nocookie.net/fcdbab4c-8838-487e-89fd-5f0782974edf', alt: 'Image', link: 'some://valid.url', badge: 'vstf' }]}
32+
maxStackSize={2}
33+
overrideCount={6}
34+
/>
35+
```
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`AvatarStack renders when there are less avatars than specified by maxStackSize 1`] = `
4+
<div
5+
className="wds-avatar-stack"
6+
>
7+
<Avatar
8+
alt="User"
9+
badge="admin"
10+
href="some.link"
11+
key="0"
12+
src="some.url"
13+
/>
14+
<Avatar
15+
alt="Other user"
16+
badge=""
17+
href="some.other.link"
18+
key="1"
19+
src="some.other.url"
20+
/>
21+
0
22+
</div>
23+
`;
24+
25+
exports[`AvatarStack renders when there are more avatars than specified by maxStackSize 1`] = `
26+
<div
27+
className="wds-avatar-stack"
28+
>
29+
<Avatar
30+
alt="User"
31+
badge="admin"
32+
href="some.link"
33+
key="0"
34+
src="some.url"
35+
/>
36+
<div
37+
className="wds-avatar-stack__overflow"
38+
>
39+
+1
40+
</div>
41+
</div>
42+
`;
43+
44+
exports[`AvatarStack renders with default props 1`] = `
45+
<div
46+
className="wds-avatar-stack"
47+
>
48+
<Avatar
49+
alt="User"
50+
badge="admin"
51+
href="some.link"
52+
key="0"
53+
src="some.url"
54+
/>
55+
<Avatar
56+
alt="Other user"
57+
badge=""
58+
href="some.other.link"
59+
key="1"
60+
src="some.other.url"
61+
/>
62+
0
63+
</div>
64+
`;
65+
66+
exports[`AvatarStack renders with hideOverflow set to true 1`] = `
67+
<div
68+
className="wds-avatar-stack"
69+
>
70+
<Avatar
71+
alt="User"
72+
badge="admin"
73+
href="some.link"
74+
key="0"
75+
src="some.url"
76+
/>
77+
</div>
78+
`;
79+
80+
exports[`AvatarStack renders with overrideCount 1`] = `
81+
<div
82+
className="wds-avatar-stack"
83+
>
84+
<Avatar
85+
alt="User"
86+
badge="admin"
87+
href="some.link"
88+
key="0"
89+
src="some.url"
90+
/>
91+
<Avatar
92+
alt="Other user"
93+
badge=""
94+
href="some.other.link"
95+
key="1"
96+
src="some.other.url"
97+
/>
98+
0
99+
</div>
100+
`;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
5+
import Avatar from '../Avatar';
6+
7+
import './styles.scss';
8+
9+
/* eslint-disable react/no-array-index-key */
10+
const AvatarStack = ({ avatars, overrideCount, maxStackSize, hideOverflow, className }) => {
11+
const count = overrideCount || avatars.length;
12+
const overflow = !hideOverflow && (count > maxStackSize ? count - maxStackSize : 0);
13+
14+
return (
15+
<div className={classNames('wds-avatar-stack', className)}>
16+
{
17+
avatars
18+
.slice(0, maxStackSize)
19+
.map(({ src, alt, link, badge = '' }, index) => (
20+
<Avatar key={index} src={src} alt={alt} badge={badge} href={link} />
21+
))
22+
}
23+
{
24+
overflow && (
25+
<div className="wds-avatar-stack__overflow">
26+
{`+${overflow}`}
27+
</div>
28+
)
29+
}
30+
</div>
31+
);
32+
};
33+
34+
AvatarStack.propTypes = {
35+
avatars: PropTypes.arrayOf(PropTypes.shape()).isRequired,
36+
className: PropTypes.string,
37+
hideOverflow: PropTypes.bool,
38+
maxStackSize: PropTypes.number,
39+
overrideCount: PropTypes.number,
40+
};
41+
42+
AvatarStack.defaultProps = {
43+
className: '',
44+
hideOverflow: false,
45+
maxStackSize: 5,
46+
overrideCount: 0,
47+
};
48+
49+
export default AvatarStack;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { shallow } from 'enzyme';
2+
import React from 'react';
3+
import merge from 'lodash/merge';
4+
5+
import AvatarStack from './index';
6+
7+
const defaultProps = {
8+
avatars: [
9+
{ src: 'some.url', alt: 'User', link: 'some.link', badge: 'admin' },
10+
{ src: 'some.other.url', alt: 'Other user', link: 'some.other.link' },
11+
],
12+
};
13+
14+
function renderComponent(props) {
15+
const computedProps = merge({}, defaultProps, props);
16+
17+
return shallow(<AvatarStack {...computedProps} />);
18+
}
19+
20+
test('AvatarStack renders with default props', () => {
21+
const wrapper = renderComponent();
22+
23+
expect(wrapper).toMatchSnapshot();
24+
});
25+
26+
test('AvatarStack renders with overrideCount', () => {
27+
const wrapper = renderComponent({ overrideCount: 1 });
28+
29+
expect(wrapper).toMatchSnapshot();
30+
});
31+
32+
test('AvatarStack renders when there are less avatars than specified by maxStackSize', () => {
33+
const wrapper = renderComponent({ maxStackSize: 3 });
34+
35+
expect(wrapper).toMatchSnapshot();
36+
});
37+
38+
test('AvatarStack renders when there are more avatars than specified by maxStackSize', () => {
39+
const wrapper = renderComponent({ maxStackSize: 1 });
40+
41+
expect(wrapper).toMatchSnapshot();
42+
});
43+
44+
test('AvatarStack renders with hideOverflow set to true', () => {
45+
const wrapper = renderComponent({ hideOverflow: true, maxStackSize: 1 });
46+
47+
expect(wrapper).toMatchSnapshot();
48+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@import "~design-system/dist/scss/wds-mixins/index.scss";
2+
@import "~design-system/dist/scss/wds-variables/index.scss";
3+
@import "~design-system/dist/scss/wds-components/_avatar-stack.scss";

source/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export { default as FandomContentWell } from './FandomContentWell';
2626
export { default as List } from './List';
2727
// Other UI
2828
export { default as Avatar } from './Avatar';
29+
export { default as AvatarStack } from './AvatarStack';
2930
export { default as ExpandableText } from './ExpandableText';
3031
export { default as Switch } from './Switch';
3132
export { default as Timeago } from './Timeago';

0 commit comments

Comments
 (0)