-
Notifications
You must be signed in to change notification settings - Fork 5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UX Multichain: Added avatar group component (#21342)
## **Description** This PR is to add a avatar group component required for the [avatars in account-list-item](MetaMask/MetaMask-planning#1425) ## **Manual testing steps** _1. Step1:_ Go to Storybook build _2. Step2:_ Look for AvatarGroup Component _3. Step3:_ Check if components are in a stacked manner _4. Step4:_ Change the limit and check extra appear in a text like +2 format ## **Screenshots/Recordings** ![Screenshot 2023-10-12 at 4 29 52 PM](https://github.com/MetaMask/metamask-extension/assets/39872794/031c01ea-8665-48bd-991d-61ba40fc2b75) ## **Related issues** _Fixes #21323 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained: - [x] What problem this PR is solving. - [x] How this problem was solved. - [x] How reviewers can test my changes. - [x] I’ve indicated what issue this PR is linked to: Fixes #??? - [x] I’ve included tests if applicable. - [x] I’ve documented any added code. - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). - [x] I’ve properly set the pull request status: - [x] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
- Loading branch information
Showing
7 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
80 changes: 80 additions & 0 deletions
80
ui/components/multichain/avatar-group/__snapshots__/avatar-group.test.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`AvatarGroup should render AvatarGroup component 1`] = ` | ||
<div> | ||
<div | ||
class="mm-box multichain-avatar-group mm-box--display-flex mm-box--align-items-center" | ||
data-testid="avatar-group" | ||
> | ||
<div | ||
class="mm-box mm-box--display-flex" | ||
> | ||
<div | ||
class="mm-box mm-box--rounded-full" | ||
style="margin-left: 0px;" | ||
> | ||
<div | ||
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-xs mm-avatar-token mm-text--body-xs mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1" | ||
> | ||
<img | ||
alt="AVAX logo" | ||
class="mm-avatar-token__token-image" | ||
src="./images/avax-token.png" | ||
/> | ||
</div> | ||
</div> | ||
<div | ||
class="mm-box mm-box--rounded-full" | ||
style="margin-left: -8px;" | ||
> | ||
<div | ||
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-xs mm-avatar-token mm-text--body-xs mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1" | ||
> | ||
<img | ||
alt="OP logo" | ||
class="mm-avatar-token__token-image" | ||
src="./images/optimism.svg" | ||
/> | ||
</div> | ||
</div> | ||
<div | ||
class="mm-box mm-box--rounded-full" | ||
style="margin-left: -8px;" | ||
> | ||
<div | ||
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-xs mm-avatar-token mm-text--body-xs mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1" | ||
> | ||
<img | ||
alt="MATIC logo" | ||
class="mm-avatar-token__token-image" | ||
src="./images/matic-token.png" | ||
/> | ||
</div> | ||
</div> | ||
<div | ||
class="mm-box mm-box--rounded-full" | ||
style="margin-left: -8px;" | ||
> | ||
<div | ||
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-xs mm-avatar-token mm-text--body-xs mm-text--text-transform-uppercase mm-box--display-flex mm-box--justify-content-center mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-full mm-box--border-color-transparent box--border-style-solid box--border-width-1" | ||
> | ||
<img | ||
alt="ETH logo" | ||
class="mm-avatar-token__token-image" | ||
src="./images/eth_logo.png" | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
<div | ||
class="mm-box" | ||
> | ||
<p | ||
class="mm-box mm-text mm-text--body-sm mm-box--color-text-alternative" | ||
> | ||
+1 | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
`; |
57 changes: 57 additions & 0 deletions
57
ui/components/multichain/avatar-group/avatar-group.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import React from 'react'; | ||
import { StoryFn, Meta } from '@storybook/react'; | ||
import { AvatarGroup } from '.'; | ||
|
||
export default { | ||
title: 'Components/Multichain/AvatarGroup', | ||
component: AvatarGroup, | ||
argTypes: { | ||
limit: { | ||
control: 'number', | ||
}, | ||
members: { | ||
control: 'object', | ||
}, | ||
}, | ||
args: { | ||
members: [ | ||
{ symbol: 'ETH', image: './images/eth_logo.png' }, | ||
{ symbol: 'MATIC', image: './images/matic-token.png' }, | ||
{ symbol: 'OP', image: './images/optimism.svg' }, | ||
{ symbol: 'AVAX', image: './images/avax-token.png' }, | ||
], | ||
limit: 4, | ||
}, | ||
} as Meta<typeof AvatarGroup>; | ||
|
||
const Template = (args) => <AvatarGroup {...args} />; | ||
|
||
export const DefaultStory = Template.bind({}); | ||
DefaultStory.storyName = 'Default'; | ||
|
||
export const WithTag: StoryFn<typeof AvatarGroup> = (args) => ( | ||
<AvatarGroup {...args} /> | ||
); | ||
WithTag.args = { | ||
members: [ | ||
{ symbol: 'ETH', image: './images/eth_logo.png' }, | ||
{ symbol: 'MATIC', image: './images/matic-token.png' }, | ||
{ symbol: 'OP', image: './images/optimism.svg' }, | ||
{ symbol: 'AVAX', image: './images/avax-token.png' }, | ||
{ symbol: 'PALM', image: './images/palm.svg' }, | ||
], | ||
limit: 2, | ||
}; | ||
|
||
export const TokenWithOutSrc: StoryFn<typeof AvatarGroup> = (args) => ( | ||
<AvatarGroup {...args} /> | ||
); | ||
TokenWithOutSrc.args = { | ||
members: [ | ||
{ symbol: 'ETH', image: '' }, | ||
{ symbol: 'MATIC', image: '' }, | ||
{ symbol: 'OP', image: '' }, | ||
{ symbol: 'AVAX', image: '' }, | ||
], | ||
limit: 2, | ||
}; |
34 changes: 34 additions & 0 deletions
34
ui/components/multichain/avatar-group/avatar-group.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* eslint-disable jest/require-top-level-describe */ | ||
import { render, screen } from '@testing-library/react'; | ||
import React from 'react'; | ||
|
||
import { AvatarGroup } from './avatar-group'; | ||
|
||
const members = [ | ||
{ symbol: 'ETH', image: './images/eth_logo.png' }, | ||
{ symbol: 'MATIC', image: './images/matic-token.png' }, | ||
{ symbol: 'OP', image: './images/optimism.svg' }, | ||
{ symbol: 'AVAX', image: './images/avax-token.png' }, | ||
{ symbol: 'PALM', image: './images/palm.svg' }, | ||
]; | ||
|
||
describe('AvatarGroup', () => { | ||
it('should render AvatarGroup component', () => { | ||
const { getByTestId, container } = render( | ||
<AvatarGroup members={members} limit={4} />, | ||
); | ||
expect(getByTestId('avatar-group')).toBeDefined(); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('should render the tag +1 if members has a length greater than limit', () => { | ||
render(<AvatarGroup members={members} limit={4} />); | ||
|
||
expect(screen.getByText('+1')).toBeDefined(); | ||
}); | ||
|
||
it('should not render the tag if members has a length less than or equal to limit', () => { | ||
const { queryByText } = render(<AvatarGroup members={members} limit={5} />); | ||
expect(queryByText('+1')).not.toBeInTheDocument(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import * as React from 'react'; | ||
import classnames from 'classnames'; | ||
import { | ||
Text, | ||
Box, | ||
AvatarToken, | ||
AvatarTokenSize, | ||
} from '../../component-library'; | ||
import { | ||
AlignItems, | ||
BorderColor, | ||
BorderRadius, | ||
Display, | ||
TextColor, | ||
TextVariant, | ||
} from '../../../helpers/constants/design-system'; | ||
import { AvatarGroupProps } from './avatar-group.types'; | ||
|
||
export const AvatarGroup: React.FC<AvatarGroupProps> = ({ | ||
className = '', | ||
limit = 4, | ||
members = [], | ||
size = AvatarTokenSize.Xs, | ||
borderColor = BorderColor.transparent, | ||
}): JSX.Element => { | ||
const membersCount = members.length; | ||
const visibleMembers = members.slice(0, limit).reverse(); | ||
const showTag = membersCount > limit; | ||
let marginLeftValue = ''; | ||
if (AvatarTokenSize.Xs) { | ||
marginLeftValue = '-8px'; | ||
} else if (AvatarTokenSize.Sm) { | ||
marginLeftValue = '-12px'; | ||
} else { | ||
marginLeftValue = '-16px'; | ||
} | ||
const tagValue = `+${(membersCount - limit).toLocaleString()}`; | ||
return ( | ||
<Box | ||
alignItems={AlignItems.center} | ||
display={Display.Flex} | ||
className={classnames('multichain-avatar-group', className)} | ||
data-testid="avatar-group" | ||
> | ||
<Box display={Display.Flex}> | ||
{visibleMembers.map((member, i) => ( | ||
<Box | ||
borderRadius={BorderRadius.full} | ||
key={member.symbol} | ||
style={ | ||
i === 0 ? { marginLeft: '0' } : { marginLeft: marginLeftValue } | ||
} | ||
> | ||
<AvatarToken | ||
src={member.image} | ||
name={member.symbol} | ||
size={size} | ||
borderColor={borderColor} | ||
/> | ||
</Box> | ||
))} | ||
</Box> | ||
{showTag ? ( | ||
<Box> | ||
<Text variant={TextVariant.bodySm} color={TextColor.textAlternative}> | ||
{tagValue} | ||
</Text> | ||
</Box> | ||
) : null} | ||
</Box> | ||
); | ||
}; |
21 changes: 21 additions & 0 deletions
21
ui/components/multichain/avatar-group/avatar-group.types.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { BorderColor } from '../../../helpers/constants/design-system'; | ||
import { AvatarTokenSize } from '../../component-library'; | ||
import type { StyleUtilityProps } from '../../component-library/box'; | ||
|
||
export interface AvatarGroupProps extends StyleUtilityProps { | ||
/** * Additional class name for the AvatarGroup component */ | ||
className?: string; | ||
/** * Limit to show only a certain number of tokens and extras in Text */ | ||
limit: number; | ||
/** * List of Avatar Tokens */ | ||
members: { | ||
/** * Image of Avatar Token */ | ||
image: string; | ||
/** * Symbol of Avatar Token */ | ||
symbol?: string; | ||
}[]; | ||
/** * Size of Avatar Tokens. For AvatarGroup we are considering AvatarTokenSize.Xs, AvatarTokenSize.Sm, AvatarTokenSize.Md */ | ||
size?: AvatarTokenSize; | ||
/** * Border Color of Avatar Tokens */ | ||
borderColor?: BorderColor; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { AvatarGroup } from './avatar-group'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters