Skip to content

Commit

Permalink
fix(Avatar): support display names using emoji and multi-byte
Browse files Browse the repository at this point in the history
  • Loading branch information
booc0mtaco committed Jul 31, 2023
1 parent 8e4e462 commit 279452b
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 6 deletions.
2 changes: 2 additions & 0 deletions src/components/Avatar/Avatar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

color: var(--eds-theme-color-text-neutral-strong);
background-color: var(--eds-theme-color-background-neutral-medium);

white-space: nowrap;
}

.avatar:focus-visible {
Expand Down
61 changes: 58 additions & 3 deletions src/components/Avatar/Avatar.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,49 +19,62 @@ export default {

type Args = React.ComponentProps<typeof Avatar>;

export const Default: StoryObj<Args> = {
args: {},
};
export const Default: StoryObj<Args> = {};

export const Small: StoryObj<Args> = {
args: {
size: 'sm',
shape: 'circle',
variant: 'icon',
},
};

export const Medium: StoryObj<Args> = {
args: {
size: 'md',
shape: 'circle',
variant: 'icon',
},
};

export const Large: StoryObj<Args> = {
args: {
size: 'lg',
shape: 'circle',
variant: 'icon',
},
};

export const Square: StoryObj<Args> = {
args: {
shape: 'square',
size: 'md',
variant: 'icon',
},
};

export const UsingImage: StoryObj<Args> = {
args: {
variant: 'image',
src: `data:image/svg+xml,%3csvg width='38' height='37' viewBox='0 0 38 37' fill='none' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M19 17.9417C16.4333 17.9417 14.3333 17.125 12.7 15.4917C11.0667 13.8583 10.25 11.7583 10.25 9.19168C10.25 6.62502 11.0667 4.52501 12.7 2.89168C14.3333 1.25835 16.4333 0.441681 19 0.441681C21.5667 0.441681 23.6667 1.25835 25.3 2.89168C26.9333 4.52501 27.75 6.62502 27.75 9.19168C27.75 11.7583 26.9333 13.8583 25.3 15.4917C23.6667 17.125 21.5667 17.9417 19 17.9417ZM0.333344 36.6667V31.1833C0.333344 29.7056 0.702788 28.4417 1.44168 27.3917C2.18057 26.3417 3.13334 25.5445 4.30001 25C6.90557 23.8333 9.40418 22.9583 11.7958 22.375C14.1875 21.7917 16.5889 21.5 19 21.5C21.4111 21.5 23.8028 21.8014 26.175 22.4042C28.5472 23.007 31.0361 23.8722 33.6417 25C34.8472 25.5445 35.8195 26.3417 36.5583 27.3917C37.2972 28.4417 37.6667 29.7056 37.6667 31.1833V36.6667H0.333344Z' fill='%235D6369'/%3e%3c/svg%3e`,
size: 'md',
shape: 'circle',
},
};

export const WithCustomLabel: StoryObj<Args> = {
args: {
ariaLabel: 'Custom label for avatar',
size: 'md',
shape: 'circle',
variant: 'icon',
},
};

export const UsingInitials: StoryObj<Args> = {
args: {
size: 'md',
shape: 'circle',
variant: 'initials',
user: {
fullName: 'John Smith',
Expand All @@ -70,3 +83,45 @@ export const UsingInitials: StoryObj<Args> = {
},
},
};

export const UsingEmoji: StoryObj<Args> = {
args: {
shape: 'circle',
variant: 'initials',
user: {
fullName: 'Young Yarn Lad',
displayName: '🧶👦🏽',
id: '12345',
hasArbitraryMetadata: true,
},
size: 'lg',
},
};

export const WhenImageVariantMissingSource: StoryObj<Args> = {
args: {
shape: 'circle',
variant: 'image',
user: {
fullName: 'Young Yarn Lad',
id: '12345',
hasArbitraryMetadata: true,
moreMetadata: 123,
},
size: 'lg',
},
};

export const UsingMultibyteUnicode: StoryObj<Args> = {
args: {
shape: 'circle',
variant: 'image',
user: {
fullName: '你好世界',
id: '12345',
hasArbitraryMetadata: true,
moreMetadata: 123,
},
size: 'lg',
},
};
19 changes: 16 additions & 3 deletions src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export type UserData = {
* User ID associated with the attached user
*/
id?: string | number;
/**
* The display shortcut for the user name. Can be initials, emoji, or other text symbols (recommended max: 2)
*/
displayName?: string;
/**
* Additional data for an attached user (email, etc.)
*/
Expand Down Expand Up @@ -56,7 +60,7 @@ function getInitials(fromName: string): string {
* - User's name has a middle name or initial: John C. Smith
* - User's Name has dashes in it
*/
return fromName
const initials = fromName
.split(' ')
.map((part) => part[0])
.reduce(
Expand All @@ -65,6 +69,7 @@ function getInitials(fromName: string): string {
'',
)
.toUpperCase();
return initials;
}

/**
Expand Down Expand Up @@ -94,18 +99,26 @@ export const Avatar = ({
ariaLabel ??
`Avatar for ${user ? '' : 'unknown '}user ${user?.fullName || ''}`;

// use the display name if prop is provided. Otherwise, try to calculate initials
let avatarDisplayName = user ? getInitials(user.fullName) : '??';

if (user?.displayName) {
avatarDisplayName = user.displayName;
}

return (
<div
aria-label={descriptiveLabel}
className={componentClassName}
role="img"
{...other}
>
{variant === 'initials' && (user ? getInitials(user.fullName) : '??')}
{variant === 'initials' && avatarDisplayName}
{variant === 'icon' && <Icon name="person" purpose="decorative" />}
{variant === 'image' && (
{variant === 'image' && src && (
<img alt="user" className={styles['avatar__image']} src={src} />
)}
{variant === 'image' && !src && avatarDisplayName}
</div>
);
};
30 changes: 30 additions & 0 deletions src/components/Avatar/__snapshots__/Avatar.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ exports[`<Avatar /> Square story renders snapshot 1`] = `
</div>
`;

exports[`<Avatar /> UsingEmoji story renders snapshot 1`] = `
<div
aria-label="Avatar for user Young Yarn Lad"
class="avatar avatar--circle avatar--lg avatar--initials"
role="img"
>
🧶👦🏽
</div>
`;

exports[`<Avatar /> UsingImage story renders snapshot 1`] = `
<div
aria-label="Avatar for unknown user "
Expand All @@ -124,6 +134,26 @@ exports[`<Avatar /> UsingInitials story renders snapshot 1`] = `
</div>
`;

exports[`<Avatar /> UsingMultibyteUnicode story renders snapshot 1`] = `
<div
aria-label="Avatar for user 你好世界"
class="avatar avatar--circle avatar--lg avatar--image"
role="img"
>
</div>
`;

exports[`<Avatar /> WhenImageVariantMissingSource story renders snapshot 1`] = `
<div
aria-label="Avatar for user Young Yarn Lad"
class="avatar avatar--circle avatar--lg avatar--image"
role="img"
>
YL
</div>
`;

exports[`<Avatar /> WithCustomLabel story renders snapshot 1`] = `
<div
aria-label="Custom label for avatar"
Expand Down

0 comments on commit 279452b

Please sign in to comment.