Skip to content

Commit

Permalink
feat(avatars): Add Avatar and AvatarGroup components
Browse files Browse the repository at this point in the history
  • Loading branch information
kendrick committed Sep 8, 2021
1 parent 00f81a2 commit d798deb
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 0 deletions.
12 changes: 12 additions & 0 deletions packages/components/react-web/src/Avatars/Avatar/Avatar.docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
// import { Avatar } from './Avatar';

# Avatar

<Canvas>
<Story id="layouts-avatars-avatar--basic" />
</Canvas>

<Canvas>
<Story id="layouts-avatars-avatar--with-image" />
</Canvas>
49 changes: 49 additions & 0 deletions packages/components/react-web/src/Avatars/Avatar/Avatar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import PropTypes from 'prop-types';

/** @jsxRuntime classic */
/** @jsx jsx */
import { jsx } from '@emotion/core';
import { cx } from 'emotion';
import avatarStyles from './Avatar.styles';
import { useTheme } from '../../hooks';

/**
* Primary UI component for user interaction
*/
export const Avatar = ({ size, shape, image, initials, color, ...props }) => {
const theme = useTheme();

const withImage = !!image;

return (
<div
css={avatarStyles(theme.component.avatar, color, withImage)}
className={cx('avatar', {
[`avatar--${size}`]: size !== Avatar.defaultProps.size,
[`avatar--${shape}`]: shape !== Avatar.defaultProps.shape,
[`avatar--image`]: image,
[`avatar--initials`]: initials && !image,
})}
{...props}
>
{image || (initials && initials.toUpperCase())}
{/* Image || Initials || Auto */}
</div>
);
};

Avatar.propTypes = {
size: PropTypes.oneOf(['small', 'medium', 'large']),
shape: PropTypes.oneOf(['circle', 'square', 'rounded']),
initials: PropTypes.string,
color: PropTypes.string,
image: PropTypes.elementType,
};

Avatar.defaultProps = {
size: 'small',
shape: 'circle',
initials: null,
color: '#efefef',
image: null,
};
35 changes: 35 additions & 0 deletions packages/components/react-web/src/Avatars/Avatar/Avatar.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { Avatar } from './Avatar';
import { AvatarGroup } from '../AvatarGroup';

import AvatarDocs from './Avatar.docs.mdx';

import { Image } from '../../Image';

export default {
title: 'Layouts/Avatars/Avatar',
component: Avatar,
argTypes: {
color: { control: { type: 'color' } },
},
parameters: {
docs: {
page: AvatarDocs,
},
},
};

const imageComponent = (
<Image
alt="Arkansas is great."
objectFit="cover"
src="https://images.unsplash.com/photo-1605027628030-9bb6f83535e6?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=64&q=100"
srcPreview="https://images.unsplash.com/photo-1605027628030-9bb6f83535e6?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=10&q=100"
/>
);

export const Basic = (args) => (
<Avatar initials="KA" color="#cc00ff" {...args} />
);

export const WithImage = (args) => <Avatar image={imageComponent} {...args} />;
56 changes: 56 additions & 0 deletions packages/components/react-web/src/Avatars/Avatar/Avatar.styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { css } from '@emotion/core';
import { helpers } from '@compassion-gds/elements';

export default (theme, color, withImage) => {
let textColor;

if (!withImage) {
textColor =
helpers.color.calculateContrastRatio(color, '#000') > 4.5
? '#000'
: '#fff';
}
return css`
--gds-avatar-size: 44px;
--gds-avatar-background-color: ${color};
--gds-avatar-text-color: ${textColor || `inherit`};
display: inline-flex;
overflow: hidden;
width: var(--gds-avatar-size);
height: var(--gds-avatar-size);
border-radius: 50%;
background-color: var(--gds-avatar-background-color);
color: var(--gds-avatar-text-color);
font-weight: 300;
font-size: calc(var(--gds-avatar-size) / 2);
line-height: 1;
justify-content: center;
align-items: center;
&.avatar--medium {
--gds-avatar-size: 64px;
}
&.avatar--large {
--gds-avatar-size: 88px;
}
&.avatar--square {
border-radius: 0;
}
&.avatar--rounded {
border-radius: 8px;
}
&.avatar--image {
img {
height: var(--gds-avatar-size);
}
}
`;
};
1 change: 1 addition & 0 deletions packages/components/react-web/src/Avatars/Avatar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Avatar';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';

# AvatarGroup

<Canvas>
<Story id="layouts-avatars-avatargroup--default" />
</Canvas>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import PropTypes from 'prop-types';

/** @jsxRuntime classic */
/** @jsx jsx */
import { jsx } from '@emotion/core';
import { cx } from 'emotion';
import avatarGroupStyles from './AvatarGroup.styles';
import { useTheme } from '../../hooks';

export const AvatarGroup = ({ size, overlap, gapColor, shape, ...props }) => {
const theme = useTheme();

return (
<div
css={avatarGroupStyles(theme.component.avatarGroup, gapColor)}
className={cx('avatar-group', {
[`avatar-group--${size}`]: size !== AvatarGroup.defaultProps.size,
[`avatar-group--${shape}`]: shape !== AvatarGroup.defaultProps.shape,
[`avatar-group--overlap-${overlap}`]:
overlap !== AvatarGroup.defaultProps.overlap,
})}
{...props}
>
{props.children}
{/* Image || Initials || Auto */}
</div>
);
};

AvatarGroup.propTypes = {
size: PropTypes.oneOf(['small', 'medium', 'large']),
overlap: PropTypes.oneOf(['none', 'small', 'medium', 'large']),
gapColor: PropTypes.string,
shape: PropTypes.oneOf(['circle', 'square', 'rounded']),
};

AvatarGroup.defaultProps = {
size: 'small',
overlap: 'small',
gapColor: '#fff',
shape: 'circle',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { Avatar } from '../Avatar';
import { AvatarGroup } from './AvatarGroup';

import AvatarGroupDocs from './AvatarGroup.docs.mdx';

export default {
title: 'Layouts/Avatars/AvatarGroup',
component: AvatarGroup,
argTypes: {
gapColor: { control: { type: 'color' } },
},
parameters: {
docs: {
page: AvatarGroupDocs,
},
},
};

export const Default = (args) => (
<AvatarGroup {...args}>
<Avatar initials="AB" />
<Avatar initials="BC" />
<Avatar initials="CD" />
<Avatar initials="DE" />
<Avatar initials="EF" />
<Avatar initials="FG" />
</AvatarGroup>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { css } from '@emotion/core';

export default (theme, gapColor) => {
return css`
display: flex;
.avatar {
--gds-avatar-size: 44px;
--gds-avatar-group-overlap: calc(var(--gds-avatar-size) / -3);
box-sizing: content-box;
border: 4px ${gapColor} solid;
&:not(:first-of-type) {
margin-left: var(--gds-avatar-group-overlap);
}
}
&.avatar-group--medium {
.avatar {
--gds-avatar-size: 64px;
}
}
&.avatar-group--large {
.avatar {
--gds-avatar-size: 88px;
}
}
&.avatar-group--square {
.avatar {
border-radius: 0;
}
}
&.avatar-group--rounded {
.avatar {
border-radius: 8px;
}
}
&.avatar-group--overlap {
&-none .avatar {
--gds-avatar-group-overlap: calc(var(--gds-avatar-size) / 8);
box-sizing: border-box;
border: none;
}
&-medium .avatar {
--gds-avatar-group-overlap: calc(var(--gds-avatar-size) / -2);
}
&-large .avatar {
--gds-avatar-group-overlap: calc(var(--gds-avatar-size) / -1.5);
border-width: 3px;
}
}
`;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './AvatarGroup';
2 changes: 2 additions & 0 deletions packages/components/react-web/src/Avatars/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Avatar';
export * from './AvatarGroup';
1 change: 1 addition & 0 deletions packages/components/react-web/src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './Avatars';
export * from './Button';
export * from './FileSelect';
export * from './Icon';
Expand Down

0 comments on commit d798deb

Please sign in to comment.