generated from MetaMask/metamask-module-template
-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: adding initial avatar network component
- Loading branch information
1 parent
fe89222
commit d4e6d7d
Showing
8 changed files
with
430 additions
and
0 deletions.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
packages/design-system-react/src/components/avatar-network/AvatarNetwork.constants.ts
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,13 @@ | ||
import { AvatarBaseSize } from '../avatar-base'; | ||
import { TextVariant } from '../text'; | ||
|
||
export const AVATAR_NETWORK_SIZE_TO_TEXT_VARIANT_MAP: Record< | ||
AvatarBaseSize, | ||
TextVariant | ||
> = { | ||
[AvatarBaseSize.Xs]: TextVariant.BodyXs, | ||
[AvatarBaseSize.Sm]: TextVariant.BodyXs, | ||
[AvatarBaseSize.Md]: TextVariant.BodySm, | ||
[AvatarBaseSize.Lg]: TextVariant.BodyMd, | ||
[AvatarBaseSize.Xl]: TextVariant.BodyMd, | ||
}; |
97 changes: 97 additions & 0 deletions
97
packages/design-system-react/src/components/avatar-network/AvatarNetwork.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,97 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import React from 'react'; | ||
|
||
import { FontWeight } from '..'; | ||
import { AvatarNetwork } from './AvatarNetwork'; | ||
import { AvatarNetworkSize } from '.'; | ||
import README from './README.mdx'; | ||
|
||
const meta: Meta<typeof AvatarNetwork> = { | ||
title: 'React Components/AvatarNetwork', | ||
component: AvatarNetwork, | ||
parameters: { | ||
docs: { | ||
page: README, | ||
}, | ||
}, | ||
argTypes: { | ||
src: { | ||
control: 'text', | ||
description: | ||
'Optional URL for the network image. When provided, displays the image instead of fallback text', | ||
}, | ||
size: { | ||
control: 'select', | ||
options: Object.keys(AvatarNetworkSize), | ||
mapping: AvatarNetworkSize, | ||
description: | ||
'Optional prop to control the size of the avatar. Defaults to AvatarNetworkSize.Md', | ||
}, | ||
fallbackText: { | ||
control: 'text', | ||
description: | ||
'Required text to display when no image is provided. Also used as alt text for the image when src is provided', | ||
}, | ||
fallbackTextProps: { | ||
control: 'object', | ||
description: | ||
'Optional props to be passed to the Text component when rendering fallback text. Only used when src is not provided', | ||
}, | ||
className: { | ||
control: 'text', | ||
description: | ||
'Optional additional CSS classes to be applied to the component', | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof AvatarNetwork>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
src: 'https://cryptologos.cc/logos/ethereum-eth-logo.png', | ||
fallbackText: 'Eth', | ||
}, | ||
}; | ||
|
||
export const Src: Story = { | ||
render: () => ( | ||
<div className="flex gap-2"> | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
src="https://cryptologos.cc/logos/ethereum-eth-logo.png" | ||
/> | ||
<AvatarNetwork | ||
fallbackText="Ava" | ||
src="https://cryptologos.cc/logos/avalanche-avax-logo.png" | ||
/> | ||
<AvatarNetwork | ||
fallbackText="Pol" | ||
src="https://cryptologos.cc/logos/polygon-matic-logo.png" | ||
/> | ||
</div> | ||
), | ||
}; | ||
|
||
export const FallbackText: Story = { | ||
render: () => ( | ||
<div className="flex gap-2"> | ||
<AvatarNetwork fallbackText="Eth" /> | ||
<AvatarNetwork fallbackText="Ava" /> | ||
<AvatarNetwork fallbackText="Pol" /> | ||
</div> | ||
), | ||
}; | ||
|
||
export const Size: Story = { | ||
render: () => ( | ||
<div className="flex gap-2 items-center"> | ||
<AvatarNetwork fallbackText="E" size={AvatarNetworkSize.Xs} /> | ||
<AvatarNetwork fallbackText="Eth" size={AvatarNetworkSize.Sm} /> | ||
<AvatarNetwork fallbackText="Eth" size={AvatarNetworkSize.Md} /> | ||
<AvatarNetwork fallbackText="Eth" size={AvatarNetworkSize.Lg} /> | ||
<AvatarNetwork fallbackText="Eth" size={AvatarNetworkSize.Xl} /> | ||
</div> | ||
), | ||
}; |
127 changes: 127 additions & 0 deletions
127
packages/design-system-react/src/components/avatar-network/AvatarNetwork.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,127 @@ | ||
import { render, screen } from '@testing-library/react'; | ||
import React from 'react'; | ||
|
||
import { TextColor } from '..'; | ||
import { AvatarNetwork } from './AvatarNetwork'; | ||
import { AvatarNetworkSize } from '.'; | ||
|
||
describe('AvatarNetwork', () => { | ||
it('renders image when src is provided', () => { | ||
render(<AvatarNetwork src="test-image.jpg" fallbackText="Eth" />); | ||
|
||
const img = screen.getByRole('img'); | ||
expect(img).toBeInTheDocument(); | ||
expect(img).toHaveAttribute('src', 'test-image.jpg'); | ||
expect(img).toHaveAttribute('alt', 'Eth'); | ||
}); | ||
|
||
it('renders fallbackText when src is not provided', () => { | ||
render(<AvatarNetwork fallbackText="Eth" />); | ||
expect(screen.getByText('Eth')).toBeInTheDocument(); | ||
}); | ||
|
||
it('applies fallbackTextProps to Text component', () => { | ||
render( | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
fallbackTextProps={{ | ||
color: TextColor.TextAlternative, | ||
className: 'test-class', | ||
'data-testid': 'fallback-text', | ||
}} | ||
/>, | ||
); | ||
|
||
const text = screen.getByTestId('fallback-text'); | ||
expect(text).toHaveClass('text-alternative', 'test-class'); | ||
}); | ||
|
||
it('applies custom className to root element', () => { | ||
render( | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
className="custom-class" | ||
data-testid="avatar" | ||
/>, | ||
); | ||
|
||
const avatar = screen.getByTestId('avatar'); | ||
expect(avatar).toHaveClass('custom-class'); | ||
}); | ||
|
||
it('passes through additional image props when src is provided', () => { | ||
render( | ||
<AvatarNetwork | ||
src="test-image.jpg" | ||
fallbackText="Eth" | ||
imageProps={{ | ||
loading: 'lazy', | ||
}} | ||
/>, | ||
); | ||
|
||
screen.debug(); | ||
|
||
const img = screen.getByRole('img'); | ||
expect(img).toHaveAttribute('loading', 'lazy'); | ||
}); | ||
|
||
it('applies size classes correctly', () => { | ||
const { rerender } = render( | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
size={AvatarNetworkSize.Xs} | ||
data-testid="avatar" | ||
/>, | ||
); | ||
|
||
let avatar = screen.getByTestId('avatar'); | ||
expect(avatar).toHaveClass('h-4 w-4'); | ||
|
||
rerender( | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
size={AvatarNetworkSize.Sm} | ||
data-testid="avatar" | ||
/>, | ||
); | ||
avatar = screen.getByTestId('avatar'); | ||
expect(avatar).toHaveClass('h-6 w-6'); | ||
|
||
rerender( | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
size={AvatarNetworkSize.Md} | ||
data-testid="avatar" | ||
/>, | ||
); | ||
avatar = screen.getByTestId('avatar'); | ||
expect(avatar).toHaveClass('h-8 w-8'); | ||
|
||
rerender( | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
size={AvatarNetworkSize.Lg} | ||
data-testid="avatar" | ||
/>, | ||
); | ||
avatar = screen.getByTestId('avatar'); | ||
expect(avatar).toHaveClass('h-10 w-10'); | ||
|
||
rerender( | ||
<AvatarNetwork | ||
fallbackText="Eth" | ||
size={AvatarNetworkSize.Xl} | ||
data-testid="avatar" | ||
/>, | ||
); | ||
avatar = screen.getByTestId('avatar'); | ||
expect(avatar).toHaveClass('h-12 w-12'); | ||
}); | ||
|
||
it('uses medium size by default', () => { | ||
render(<AvatarNetwork fallbackText="Eth" data-testid="avatar" />); | ||
const avatar = screen.getByTestId('avatar'); | ||
expect(avatar).toHaveClass('h-8 w-8'); | ||
}); | ||
}); |
53 changes: 53 additions & 0 deletions
53
packages/design-system-react/src/components/avatar-network/AvatarNetwork.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,53 @@ | ||
import React from 'react'; | ||
|
||
import { AvatarBase, AvatarBaseShape, AvatarBaseSize } from '../avatar-base'; | ||
import { Text } from '../text'; | ||
import { AVATAR_NETWORK_SIZE_TO_TEXT_VARIANT_MAP } from './AvatarNetwork.constants'; | ||
import type { AvatarNetworkProps } from './AvatarNetwork.types'; | ||
|
||
export const AvatarNetwork = React.forwardRef< | ||
HTMLDivElement, | ||
AvatarNetworkProps | ||
>( | ||
( | ||
{ | ||
src, | ||
fallbackText, | ||
fallbackTextProps, | ||
className, | ||
size = AvatarBaseSize.Md, | ||
'data-testid': dataTestId, | ||
imageProps, | ||
...props | ||
}, | ||
ref, | ||
) => ( | ||
<AvatarBase | ||
ref={ref} | ||
shape={AvatarBaseShape.Square} | ||
size={size} | ||
className={className} | ||
data-testid={dataTestId} | ||
{...props} | ||
> | ||
{src ? ( | ||
<img | ||
src={src} | ||
alt={fallbackText} | ||
className="w-full h-full object-cover" | ||
{...imageProps} | ||
/> | ||
) : ( | ||
<Text | ||
variant={AVATAR_NETWORK_SIZE_TO_TEXT_VARIANT_MAP[size]} | ||
asChild | ||
{...fallbackTextProps} | ||
> | ||
<span>{fallbackText}</span> | ||
</Text> | ||
)} | ||
</AvatarBase> | ||
), | ||
); | ||
|
||
AvatarNetwork.displayName = 'AvatarNetwork'; |
45 changes: 45 additions & 0 deletions
45
packages/design-system-react/src/components/avatar-network/AvatarNetwork.types.ts
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,45 @@ | ||
import type { ComponentProps } from 'react'; | ||
|
||
import type { TextProps } from '../text'; | ||
import { AvatarNetworkSize } from '.'; | ||
|
||
export type AvatarNetworkProps = Omit< | ||
ComponentProps<'img'>, | ||
'children' | 'size' | ||
> & { | ||
/** | ||
* Optional URL for the network image | ||
* When provided, displays the image instead of fallback text | ||
*/ | ||
src?: string; | ||
/** | ||
* Optional prop to pass to the underlying img element | ||
*/ | ||
imageProps?: ComponentProps<'img'>; | ||
/** | ||
* Optional prop to control the size of the avatar | ||
* @default AvatarNetworkSize.Md | ||
*/ | ||
size?: AvatarNetworkSize; | ||
/** | ||
* Required text to display when no image is provided | ||
* Also used as alt text for the image when src is provided | ||
*/ | ||
fallbackText: string; | ||
/** | ||
* Optional props to be passed to the Text component when rendering fallback text | ||
* Only used when src is not provided | ||
*/ | ||
fallbackTextProps?: Partial< | ||
React.HTMLAttributes<HTMLSpanElement> & TextProps | ||
>; | ||
/** | ||
* Optional additional CSS classes to be applied to the component | ||
*/ | ||
className?: string; | ||
/** | ||
* Optional prop for testing purposes | ||
* Passed to the root element | ||
*/ | ||
'data-testid'?: string; | ||
}; |
Oops, something went wrong.