1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

Fix/18884 migrate avatar network (#19079)

* Migrate AvatarNetwokr

fixing error

fix textAlign

added AvatarNetworkSize

NetworkProps extends BaseProps instead of Boxprops

omitted children from base, made name required

replace deprecated and fix lint

* update AvatarNetwork TS

* add AvatarNetworkSize test

* remove unused size import

* Update ui/components/component-library/avatar-network/avatar-network.types.ts

Co-authored-by: George Marshall <georgewrmarshall@gmail.com>

* fix readme

* update to latest box component

---------

Co-authored-by: garrettbear <gwhisten@gmail.com>
Co-authored-by: George Marshall <georgewrmarshall@gmail.com>
This commit is contained in:
Binij Shrestha 2023-07-25 00:00:33 +05:45 committed by GitHub
parent 74a645e957
commit ceadfacb21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 303 additions and 239 deletions

View File

@ -14,7 +14,6 @@ import {
BackgroundColor, BackgroundColor,
TextColor, TextColor,
IconColor, IconColor,
Size,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import Button from '../../ui/button'; import Button from '../../ui/button';
import Tooltip from '../../ui/tooltip'; import Tooltip from '../../ui/tooltip';
@ -40,6 +39,7 @@ import {
IconName, IconName,
IconSize, IconSize,
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
Text, Text,
} from '../../component-library'; } from '../../component-library';
import { MetaMetricsNetworkEventSource } from '../../../../shared/constants/metametrics'; import { MetaMetricsNetworkEventSource } from '../../../../shared/constants/metametrics';
@ -199,7 +199,7 @@ const AddNetwork = () => {
> >
<Box display={Display.Flex} alignItems={AlignItems.center}> <Box display={Display.Flex} alignItems={AlignItems.center}>
<AvatarNetwork <AvatarNetwork
size={Size.SM} size={AvatarNetworkSize.Sm}
src={item.rpcPrefs?.imageUrl} src={item.rpcPrefs?.imageUrl}
name={item.nickname} name={item.nickname}
/> />

View File

@ -18,6 +18,7 @@ import TransactionListItemDetails from '../transaction-list-item-details';
import { ActivityListItem } from '../../multichain'; import { ActivityListItem } from '../../multichain';
import { import {
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BadgeWrapper, BadgeWrapper,
BadgeWrapperAnchorElementShape, BadgeWrapperAnchorElementShape,
Box, Box,
@ -25,7 +26,6 @@ import {
import { import {
BackgroundColor, BackgroundColor,
Display, Display,
Size,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { getCurrentNetwork } from '../../../selectors'; import { getCurrentNetwork } from '../../../selectors';
@ -77,7 +77,7 @@ export default function SmartTransactionListItem({
<AvatarNetwork <AvatarNetwork
className="activity-tx__network-badge" className="activity-tx__network-badge"
data-testid="activity-tx-network-badge" data-testid="activity-tx-network-badge"
size={Size.XS} size={AvatarNetworkSize.Xs}
name={currentChain?.nickname} name={currentChain?.nickname}
src={currentChain?.rpcPrefs?.imageUrl} src={currentChain?.rpcPrefs?.imageUrl}
borderWidth={1} borderWidth={1}

View File

@ -18,12 +18,12 @@ import {
Color, Color,
Display, Display,
FontWeight, FontWeight,
Size,
TextAlign, TextAlign,
TextVariant, TextVariant,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { import {
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BadgeWrapper, BadgeWrapper,
BadgeWrapperAnchorElementShape, BadgeWrapperAnchorElementShape,
Box, Box,
@ -273,7 +273,7 @@ function TransactionListItemInner({
<AvatarNetwork <AvatarNetwork
className="activity-tx__network-badge" className="activity-tx__network-badge"
data-testid="activity-tx-network-badge" data-testid="activity-tx-network-badge"
size={Size.XS} size={AvatarNetworkSize.Xs}
name={currentChain?.nickname} name={currentChain?.nickname}
src={currentChain?.rpcPrefs?.imageUrl} src={currentChain?.rpcPrefs?.imageUrl}
borderWidth={1} borderWidth={1}

View File

@ -15,7 +15,7 @@ import {
import type { PolymorphicRef } from '../box'; import type { PolymorphicRef } from '../box';
import { Text } from '../text'; import { Text } from '../text';
import type { TextProps } from '../text';
import { import {
AvatarBaseComponent, AvatarBaseComponent,
AvatarBaseProps, AvatarBaseProps,
@ -60,7 +60,7 @@ export const AvatarBase: AvatarBaseComponent = React.forwardRef(
variant={fallbackTextVariant} variant={fallbackTextVariant}
textTransform={TextTransform.Uppercase} textTransform={TextTransform.Uppercase}
{...{ backgroundColor, borderColor, color }} {...{ backgroundColor, borderColor, color }}
{...props} // TODO: There is a typing issue with spreading props to the Box component. It still works but TypeScript complains. {...(props as TextProps<C>)}
> >
{children} {children}
</Text> </Text>

View File

@ -14,7 +14,7 @@ export enum AvatarBaseSize {
Xl = 'xl', Xl = 'xl',
} }
export interface Props extends TextStyleUtilityProps { export interface AvatarBaseStyleUtilityProps extends TextStyleUtilityProps {
/** /**
* The size of the AvatarBase. * The size of the AvatarBase.
* Possible values could be 'AvatarBaseSize.Xs'(16px), 'AvatarBaseSize.Sm'(24px), * Possible values could be 'AvatarBaseSize.Xs'(16px), 'AvatarBaseSize.Sm'(24px),
@ -48,7 +48,7 @@ export interface Props extends TextStyleUtilityProps {
} }
export type AvatarBaseProps<C extends React.ElementType> = export type AvatarBaseProps<C extends React.ElementType> =
PolymorphicComponentPropWithRef<C, Props>; PolymorphicComponentPropWithRef<C, AvatarBaseStyleUtilityProps>;
export type AvatarBaseComponent = <C extends React.ElementType = 'span'>( export type AvatarBaseComponent = <C extends React.ElementType = 'span'>(
props: AvatarBaseProps<C>, props: AvatarBaseProps<C>,

View File

@ -12,7 +12,7 @@ The `AvatarNetwork` is a component responsible for display of the image of a giv
## Props ## Props
The `AvatarNetwork` accepts all props below as well as all [Box](/docs/components-ui-box--default-story#props) component props The `AvatarNetwork` accepts all props below as well as all [Box](/docs/components-componentlibrary-box--docs#props) component props
<ArgsTable of={AvatarNetwork} /> <ArgsTable of={AvatarNetwork} />
@ -37,13 +37,13 @@ The fallback display of the `AvatarNetwork` is a circle with the initial letter
</Canvas> </Canvas>
```jsx ```jsx
import { Size } from '../../../helpers/constants/design-system'; import { AvatarNetwork, AvatarNetworkSize } from '../../component-library';
import { AvatarNetwork } from '../../component-library';
<AvatarNetwork size={Size.XS} /> <AvatarNetwork size={AvatarNetworkSize.Xs} />
<AvatarNetwork size={Size.SM} /> <AvatarNetwork size={AvatarNetworkSize.Sm} />
<AvatarNetwork size={Size.MD} /> <AvatarNetwork size={AvatarNetworkSize.Md} />
<AvatarNetwork size={Size.LG} /> <AvatarNetwork size={AvatarNetworkSize.Lg} />
<AvatarNetwork size={Size.XL} /> <AvatarNetwork size={AvatarNetworkSize.Xl} />
``` ```
### Name ### Name

View File

@ -6,7 +6,11 @@ exports[`AvatarNetwork should render correctly 1`] = `
class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-network mm-text--body-sm 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" class="mm-box mm-text mm-avatar-base mm-avatar-base--size-md mm-avatar-network mm-text--body-sm 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"
data-testid="avatar-network" data-testid="avatar-network"
> >
? <img
alt="ethereum logo"
class="mm-avatar-network__network-image"
src="./images/eth_logo.png"
/>
</div> </div>
</div> </div>
`; `;

View File

@ -1,9 +0,0 @@
import { Size } from '../../../helpers/constants/design-system';
export const AVATAR_NETWORK_SIZES = {
XS: Size.XS,
SM: Size.SM,
MD: Size.MD,
LG: Size.LG,
XL: Size.XL,
};

View File

@ -1,133 +0,0 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { AvatarBase } from '../avatar-base';
import Box from '../../ui/box/box';
import {
Size,
DISPLAY,
AlignItems,
JustifyContent,
TextColor,
BackgroundColor,
BorderColor,
} from '../../../helpers/constants/design-system';
import { AVATAR_NETWORK_SIZES } from './avatar-network.constants';
export const AvatarNetwork = React.forwardRef(
(
{
size = Size.MD,
name,
src,
showHalo,
color = TextColor.textDefault,
backgroundColor = BackgroundColor.backgroundAlternative,
borderColor = BorderColor.transparent,
className,
...props
},
ref,
) => {
const [showFallback, setShowFallback] = useState(false);
useEffect(() => {
setShowFallback(!src);
}, [src]);
const fallbackString = name && name[0] ? name[0] : '?';
const handleOnError = () => {
setShowFallback(true);
};
return (
<AvatarBase
ref={ref}
size={size}
display={DISPLAY.FLEX}
alignItems={AlignItems.center}
justifyContent={JustifyContent.center}
className={classnames(
'mm-avatar-network',
showHalo && 'mm-avatar-network--with-halo',
className,
)}
{...{ backgroundColor, borderColor, color, ...props }}
>
{showFallback ? (
fallbackString
) : (
<>
{showHalo && (
<img
src={src}
className={
showHalo ? 'mm-avatar-network__network-image--blurred' : ''
}
aria-hidden="true"
/>
)}
<img
className={
showHalo
? 'mm-avatar-network__network-image--size-reduced'
: 'mm-avatar-network__network-image'
}
onError={handleOnError}
src={src}
alt={`${name} logo` || 'network logo'}
/>
</>
)}
</AvatarBase>
);
},
);
AvatarNetwork.propTypes = {
/**
* The name accepts the string to render the first alphabet of the Avatar Name
*/
name: PropTypes.string,
/**
* The src accepts the string of the image to be rendered
*/
src: PropTypes.string,
/**
* The showHalo accepts a boolean prop to render the image with halo effect
*/
showHalo: PropTypes.bool,
/**
* The size of the AvatarNetwork
* Possible values could be Size.XS(16px), Size.SM(24px), Size.MD(32px), Size.LG(40px), Size.XL(48px)
* Defaults to Size.MD
*/
size: PropTypes.oneOf(Object.values(AVATAR_NETWORK_SIZES)),
/**
* The background color of the AvatarNetwork
* Defaults to BackgroundColor.backgroundAlternative
*/
backgroundColor: PropTypes.oneOf(Object.values(BackgroundColor)),
/**
* The background color of the AvatarNetwork
* Defaults to BorderColor.borderDefault
*/
borderColor: PropTypes.oneOf(Object.values(BorderColor)),
/**
* The color of the text inside the AvatarNetwork
* Defaults to TextColor.textDefault
*/
color: PropTypes.oneOf(Object.values(TextColor)),
/**
* Additional classNames to be added to the AvatarNetwork
*/
className: PropTypes.string,
/**
* AvatarNetwork also accepts all Box props including but not limited to
* className, as(change root element of HTML element) and margin props
*/
...Box.propTypes,
};
AvatarNetwork.displayName = 'AvatarNetwork';

View File

@ -1,20 +1,17 @@
import React from 'react'; import React from 'react';
import { StoryFn, Meta } from '@storybook/react';
import { import {
Size, Display,
DISPLAY,
TextColor, TextColor,
BackgroundColor, BackgroundColor,
BorderColor, BorderColor,
Color,
AlignItems, AlignItems,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { Box } from '..';
import Box from '../../ui/box/box'; import { AvatarNetworkSize } from './avatar-network.types';
import README from './README.mdx'; import README from './README.mdx';
import { AvatarNetwork } from './avatar-network'; import { AvatarNetwork } from './avatar-network';
import { AVATAR_NETWORK_SIZES } from './avatar-network.constants';
export default { export default {
title: 'Components/ComponentLibrary/AvatarNetwork', title: 'Components/ComponentLibrary/AvatarNetwork',
@ -27,7 +24,7 @@ export default {
argTypes: { argTypes: {
size: { size: {
control: 'select', control: 'select',
options: Object.values(AVATAR_NETWORK_SIZES), options: Object.values(AvatarNetworkSize),
}, },
color: { color: {
options: Object.values(TextColor), options: Object.values(TextColor),
@ -54,38 +51,38 @@ export default {
args: { args: {
name: 'Arbitrum One', name: 'Arbitrum One',
src: './images/arbitrum.svg', src: './images/arbitrum.svg',
size: Size.MD, size: AvatarNetworkSize.Md,
showHalo: false, showHalo: false,
}, },
}; } as Meta<typeof AvatarNetwork>;
const Template = (args) => { const Template: StoryFn<typeof AvatarNetwork> = (args) => {
return <AvatarNetwork {...args} />; return <AvatarNetwork {...args} />;
}; };
export const DefaultStory = Template.bind({}); export const DefaultStory = Template.bind({});
DefaultStory.storyName = 'Default'; DefaultStory.storyName = 'Default';
export const SizeStory = (args) => ( export const SizeStory: StoryFn<typeof AvatarNetwork> = (args) => (
<> <>
<Box <Box
display={DISPLAY.FLEX} display={Display.Flex}
alignItems={AlignItems.flexEnd} alignItems={AlignItems.flexEnd}
gap={1} gap={1}
marginBottom={4} marginBottom={4}
> >
<AvatarNetwork {...args} size={Size.XS} /> <AvatarNetwork {...args} size={AvatarNetworkSize.Xs} />
<AvatarNetwork {...args} size={Size.SM} /> <AvatarNetwork {...args} size={AvatarNetworkSize.Sm} />
<AvatarNetwork {...args} size={Size.MD} /> <AvatarNetwork {...args} size={AvatarNetworkSize.Md} />
<AvatarNetwork {...args} size={Size.LG} /> <AvatarNetwork {...args} size={AvatarNetworkSize.Lg} />
<AvatarNetwork {...args} size={Size.XL} /> <AvatarNetwork {...args} size={AvatarNetworkSize.Xl} />
</Box> </Box>
<Box display={DISPLAY.FLEX} alignItems={AlignItems.flexEnd} gap={1}> <Box display={Display.Flex} alignItems={AlignItems.flexEnd} gap={1}>
<AvatarNetwork {...args} src="" size={Size.XS} /> <AvatarNetwork {...args} src="" size={AvatarNetworkSize.Xs} />
<AvatarNetwork {...args} src="" size={Size.SM} /> <AvatarNetwork {...args} src="" size={AvatarNetworkSize.Sm} />
<AvatarNetwork {...args} src="" size={Size.MD} /> <AvatarNetwork {...args} src="" size={AvatarNetworkSize.Md} />
<AvatarNetwork {...args} src="" size={Size.LG} /> <AvatarNetwork {...args} src="" size={AvatarNetworkSize.Lg} />
<AvatarNetwork {...args} src="" size={Size.XL} /> <AvatarNetwork {...args} src="" size={AvatarNetworkSize.Xl} />
</Box> </Box>
</> </>
); );
@ -96,8 +93,8 @@ Name.args = {
src: '', src: '',
}; };
export const Src = (args) => ( export const Src: StoryFn<typeof AvatarNetwork> = (args) => (
<Box display={DISPLAY.FLEX} gap={1}> <Box display={Display.Flex} gap={1}>
<AvatarNetwork {...args} src="./images/matic-token.png" /> <AvatarNetwork {...args} src="./images/matic-token.png" />
<AvatarNetwork {...args} src="./images/arbitrum.svg" /> <AvatarNetwork {...args} src="./images/arbitrum.svg" />
<AvatarNetwork {...args} src="./images/optimism.svg" /> <AvatarNetwork {...args} src="./images/optimism.svg" />
@ -115,21 +112,23 @@ ShowHalo.args = {
showHalo: true, showHalo: true,
}; };
export const ColorBackgroundColorAndBorderColor = (args) => ( export const ColorBackgroundColorAndBorderColor: StoryFn<
<Box display={DISPLAY.FLEX} gap={1}> typeof AvatarNetwork
> = (args) => (
<Box display={Display.Flex} gap={1}>
<AvatarNetwork <AvatarNetwork
{...args} {...args}
backgroundColor={BackgroundColor.goerli} backgroundColor={BackgroundColor.goerli}
borderColor={BorderColor.goerli} borderColor={BorderColor.goerli}
name="G" name="G"
color={Color.goerliInverse} color={TextColor.goerliInverse}
/> />
<AvatarNetwork <AvatarNetwork
{...args} {...args}
backgroundColor={BackgroundColor.sepolia} backgroundColor={BackgroundColor.sepolia}
borderColor={BorderColor.sepolia} borderColor={BorderColor.sepolia}
name="S" name="S"
color={Color.goerliInverse} color={TextColor.goerliInverse}
/> />
</Box> </Box>
); );

View File

@ -8,7 +8,7 @@ import {
TextColor, TextColor,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { AvatarNetwork } from './avatar-network'; import { AvatarNetwork, AvatarNetworkSize } from '.';
describe('AvatarNetwork', () => { describe('AvatarNetwork', () => {
const args = { const args = {
@ -19,7 +19,7 @@ describe('AvatarNetwork', () => {
it('should render correctly', () => { it('should render correctly', () => {
const { getByTestId, container } = render( const { getByTestId, container } = render(
<AvatarNetwork data-testid="avatar-network" />, <AvatarNetwork {...args} data-testid="avatar-network" />,
); );
expect(getByTestId('avatar-network')).toBeDefined(); expect(getByTestId('avatar-network')).toBeDefined();
expect(container).toMatchSnapshot(); expect(container).toMatchSnapshot();
@ -56,7 +56,11 @@ describe('AvatarNetwork', () => {
// className // className
it('should render with custom className', () => { it('should render with custom className', () => {
const { getByTestId } = render( const { getByTestId } = render(
<AvatarNetwork data-testid="avatar-network" className="test-class" />, <AvatarNetwork
{...args}
data-testid="avatar-network"
className="test-class"
/>,
); );
expect(getByTestId('avatar-network')).toHaveClass('test-class'); expect(getByTestId('avatar-network')).toHaveClass('test-class');
}); });
@ -65,10 +69,12 @@ describe('AvatarNetwork', () => {
const { getByTestId } = render( const { getByTestId } = render(
<> <>
<AvatarNetwork <AvatarNetwork
{...args}
color={TextColor.successDefault} color={TextColor.successDefault}
data-testid={TextColor.successDefault} data-testid={TextColor.successDefault}
/> />
<AvatarNetwork <AvatarNetwork
{...args}
color={TextColor.errorDefault} color={TextColor.errorDefault}
data-testid={TextColor.errorDefault} data-testid={TextColor.errorDefault}
/> />
@ -86,10 +92,12 @@ describe('AvatarNetwork', () => {
const { getByTestId } = render( const { getByTestId } = render(
<> <>
<AvatarNetwork <AvatarNetwork
{...args}
backgroundColor={BackgroundColor.successDefault} backgroundColor={BackgroundColor.successDefault}
data-testid={BackgroundColor.successDefault} data-testid={BackgroundColor.successDefault}
/> />
<AvatarNetwork <AvatarNetwork
{...args}
backgroundColor={BackgroundColor.errorDefault} backgroundColor={BackgroundColor.errorDefault}
data-testid={BackgroundColor.errorDefault} data-testid={BackgroundColor.errorDefault}
/> />
@ -107,10 +115,12 @@ describe('AvatarNetwork', () => {
const { getByTestId } = render( const { getByTestId } = render(
<> <>
<AvatarNetwork <AvatarNetwork
{...args}
borderColor={BorderColor.successDefault} borderColor={BorderColor.successDefault}
data-testid={BorderColor.successDefault} data-testid={BorderColor.successDefault}
/> />
<AvatarNetwork <AvatarNetwork
{...args}
borderColor={BorderColor.errorDefault} borderColor={BorderColor.errorDefault}
data-testid={BorderColor.errorDefault} data-testid={BorderColor.errorDefault}
/> />
@ -123,10 +133,59 @@ describe('AvatarNetwork', () => {
`mm-box--border-color-${BorderColor.errorDefault}`, `mm-box--border-color-${BorderColor.errorDefault}`,
); );
}); });
// AvatarNetworkSize
it('should render with different AvatarNetworkSize', () => {
const { getByTestId } = render(
<>
<AvatarNetwork
{...args}
size={AvatarNetworkSize.Xs}
data-testid={AvatarNetworkSize.Xs}
/>
<AvatarNetwork
{...args}
size={AvatarNetworkSize.Sm}
data-testid={AvatarNetworkSize.Sm}
/>
<AvatarNetwork
{...args}
size={AvatarNetworkSize.Md}
data-testid={AvatarNetworkSize.Md}
/>
<AvatarNetwork
{...args}
size={AvatarNetworkSize.Lg}
data-testid={AvatarNetworkSize.Lg}
/>
<AvatarNetwork
{...args}
size={AvatarNetworkSize.Xl}
data-testid={AvatarNetworkSize.Xl}
/>
</>,
);
expect(getByTestId(AvatarNetworkSize.Xs)).toHaveClass(
`mm-avatar-base--size-${AvatarNetworkSize.Xs}`,
);
expect(getByTestId(AvatarNetworkSize.Sm)).toHaveClass(
`mm-avatar-base--size-${AvatarNetworkSize.Sm}`,
);
expect(getByTestId(AvatarNetworkSize.Md)).toHaveClass(
`mm-avatar-base--size-${AvatarNetworkSize.Md}`,
);
expect(getByTestId(AvatarNetworkSize.Lg)).toHaveClass(
`mm-avatar-base--size-${AvatarNetworkSize.Lg}`,
);
expect(getByTestId(AvatarNetworkSize.Xl)).toHaveClass(
`mm-avatar-base--size-${AvatarNetworkSize.Xl}`,
);
});
it('should forward a ref to the root html element', () => { it('should forward a ref to the root html element', () => {
const ref = React.createRef(); const ref = React.createRef<HTMLDivElement>();
render(<AvatarNetwork ref={ref} />); render(<AvatarNetwork {...args} ref={ref} />);
expect(ref.current).not.toBeNull(); expect(ref.current).not.toBeNull();
expect(ref.current.nodeName).toBe('DIV'); if (ref.current) {
expect(ref.current.nodeName).toBe('DIV');
}
}); });
}); });

View File

@ -0,0 +1,90 @@
import React, { useState, useEffect } from 'react';
import classnames from 'classnames';
import {
Display,
AlignItems,
JustifyContent,
TextColor,
BackgroundColor,
BorderColor,
} from '../../../helpers/constants/design-system';
import type { PolymorphicRef } from '../box';
import { AvatarBase, AvatarBaseProps } from '../avatar-base';
import type { AvatarNetworkComponent } from './avatar-network.types';
import { AvatarNetworkProps, AvatarNetworkSize } from './avatar-network.types';
export const AvatarNetwork: AvatarNetworkComponent = React.forwardRef(
<C extends React.ElementType = 'div'>(
{
size = AvatarNetworkSize.Md,
name,
src,
showHalo,
color = TextColor.textDefault,
backgroundColor = BackgroundColor.backgroundAlternative,
borderColor = BorderColor.transparent,
className = '',
...props
}: AvatarNetworkProps<C>,
ref?: PolymorphicRef<C>,
) => {
const [showFallback, setShowFallback] = useState(false);
useEffect(() => {
setShowFallback(!src);
}, [src]);
const fallbackString = name?.[0] ?? '?';
const handleOnError = () => {
setShowFallback(true);
};
return (
<AvatarBase
ref={ref}
size={size}
display={Display.Flex}
alignItems={AlignItems.center}
justifyContent={JustifyContent.center}
className={classnames(
'mm-avatar-network',
showHalo ? 'mm-avatar-network--with-halo' : '',
className,
)}
{...{
backgroundColor,
borderColor,
color,
...(props as AvatarBaseProps<C>),
}}
>
{showFallback ? (
fallbackString
) : (
<>
{showHalo && (
<img
src={src}
className={
showHalo ? 'mm-avatar-network__network-image--blurred' : ''
}
aria-hidden="true"
/>
)}
<img
className={
showHalo
? 'mm-avatar-network__network-image--size-reduced'
: 'mm-avatar-network__network-image'
}
onError={handleOnError}
src={src}
alt={`${name} logo` || 'network logo'}
/>
</>
)}
</AvatarBase>
);
},
);

View File

@ -0,0 +1,42 @@
import type { PolymorphicComponentPropWithRef } from '../box';
import type { AvatarBaseStyleUtilityProps } from '../avatar-base/avatar-base.types';
export enum AvatarNetworkSize {
Xs = 'xs',
Sm = 'sm',
Md = 'md',
Lg = 'lg',
Xl = 'xl',
}
/**
* Props for the AvatarNetwork component
*/
export interface AvatarNetworkStyleUtilityProps
extends Omit<AvatarBaseStyleUtilityProps, 'size'> {
/**
* The name accepts the string to render the first alphabet of the Avatar Name
*/
name: string;
/**
* The src accepts the string of the image to be rendered
*/
src?: string;
/**
* The showHalo accepts a boolean prop to render the image with halo effect
*/
showHalo?: boolean;
/**
* The size of the AvatarNetwork
* Possible values could be AvatarNetworkSize.Xs(16px), AvatarNetworkSize.Sm(24px), AvatarNetworkSize.Md(32px), AvatarNetworkSize.Lg(40px), AvatarNetworkSize.Xl(48px)
* Defaults to AvatarNetworkSize.Md
*/
size?: AvatarNetworkSize;
}
export type AvatarNetworkProps<C extends React.ElementType> =
PolymorphicComponentPropWithRef<C, AvatarNetworkStyleUtilityProps>;
export type AvatarNetworkComponent = <C extends React.ElementType = 'span'>(
props: AvatarNetworkProps<C>,
) => React.ReactElement | null;

View File

@ -1,2 +0,0 @@
export { AvatarNetwork } from './avatar-network';
export { AVATAR_NETWORK_SIZES } from './avatar-network.constants';

View File

@ -0,0 +1,3 @@
export { AvatarNetwork } from './avatar-network';
export type { AvatarNetworkProps } from './avatar-network.types';
export { AvatarNetworkSize } from './avatar-network.types';

View File

@ -12,6 +12,7 @@ import Box from '../../ui/box/box';
import { import {
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BUTTON_LINK_SIZES, BUTTON_LINK_SIZES,
BadgeWrapper, BadgeWrapper,
ButtonLink, ButtonLink,
@ -128,7 +129,7 @@ export const SizeStory = (args) => (
<AvatarNetwork <AvatarNetwork
src="./images/eth_logo.png" src="./images/eth_logo.png"
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -141,7 +142,7 @@ export const SizeStory = (args) => (
<AvatarNetwork <AvatarNetwork
src="./images/eth_logo.png" src="./images/eth_logo.png"
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -154,7 +155,7 @@ export const SizeStory = (args) => (
<AvatarNetwork <AvatarNetwork
src="./images/eth_logo.png" src="./images/eth_logo.png"
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -167,7 +168,7 @@ export const SizeStory = (args) => (
<AvatarNetwork <AvatarNetwork
src="./images/eth_logo.png" src="./images/eth_logo.png"
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -180,7 +181,7 @@ export const SizeStory = (args) => (
<AvatarNetwork <AvatarNetwork
src="./images/eth_logo.png" src="./images/eth_logo.png"
name="ETH" name="ETH"
size={Size.SM} size={AvatarNetworkSize.Sm}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -194,7 +195,7 @@ export const SizeStory = (args) => (
badge={ badge={
<AvatarNetwork <AvatarNetwork
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -213,7 +214,7 @@ export const SizeStory = (args) => (
badge={ badge={
<AvatarNetwork <AvatarNetwork
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -232,7 +233,7 @@ export const SizeStory = (args) => (
badge={ badge={
<AvatarNetwork <AvatarNetwork
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -251,7 +252,7 @@ export const SizeStory = (args) => (
badge={ badge={
<AvatarNetwork <AvatarNetwork
name="ETH" name="ETH"
size={Size.XS} size={AvatarNetworkSize.Xs}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />
@ -270,7 +271,7 @@ export const SizeStory = (args) => (
badge={ badge={
<AvatarNetwork <AvatarNetwork
name="ETH" name="ETH"
size={Size.SM} size={AvatarNetworkSize.Sm}
borderColor={BackgroundColor.backgroundDefault} borderColor={BackgroundColor.backgroundDefault}
borderWidth={2} borderWidth={2}
/> />

View File

@ -30,6 +30,7 @@ import { Color, Size } from '../../../helpers/constants/design-system';
import { import {
AvatarAccount, AvatarAccount,
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
AvatarToken, AvatarToken,
BadgeWrapper, BadgeWrapper,
BadgeWrapperAnchorElementShape, BadgeWrapperAnchorElementShape,
@ -39,7 +40,7 @@ import {
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -53,7 +54,7 @@ import {
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -69,7 +70,7 @@ import {
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.SM} size={AvatarNetworkSize.Sm}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -110,6 +111,7 @@ import {
import { import {
AvatarAccount, AvatarAccount,
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BadgeWrapper, BadgeWrapper,
BadgeWrapperAnchorElementShape, BadgeWrapperAnchorElementShape,
Icon, Icon,
@ -121,7 +123,7 @@ import {
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -203,6 +205,7 @@ import { BorderColor Size } from '../../../helpers/constants/design-system';
import { import {
AvatarAccount, AvatarAccount,
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BadgeWrapper, BadgeWrapper,
BadgeWrapperPosition BadgeWrapperPosition
} from '../../component-library'; } from '../../component-library';
@ -211,7 +214,7 @@ import {
position={BadgeWrapperPosition.topLeft} position={BadgeWrapperPosition.topLeft}
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -223,7 +226,7 @@ import {
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -236,7 +239,7 @@ import {
position={BadgeWrapperPosition.bottomLeft} position={BadgeWrapperPosition.bottomLeft}
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -249,7 +252,7 @@ import {
position={BadgeWrapperPosition.bottomRight} position={BadgeWrapperPosition.bottomRight}
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -279,6 +282,7 @@ import { BorderColor Size } from '../../../helpers/constants/design-system';
import { import {
AvatarAccount, AvatarAccount,
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BadgeWrapper, BadgeWrapper,
} from '../../component-library'; } from '../../component-library';
@ -286,7 +290,7 @@ import {
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}

View File

@ -9,7 +9,6 @@ import {
BackgroundColor, BackgroundColor,
DISPLAY, DISPLAY,
IconColor, IconColor,
Size,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import Box from '../../ui/box/box'; import Box from '../../ui/box/box';
@ -17,6 +16,7 @@ import Box from '../../ui/box/box';
import { import {
AvatarAccount, AvatarAccount,
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
AvatarToken, AvatarToken,
Icon, Icon,
IconName, IconName,
@ -68,7 +68,7 @@ const Template: ComponentStory<typeof BadgeWrapper> = (args) => (
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -93,7 +93,7 @@ export const Children: ComponentStory<typeof BadgeWrapper> = () => (
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -105,7 +105,7 @@ export const Children: ComponentStory<typeof BadgeWrapper> = () => (
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -121,7 +121,7 @@ export const Children: ComponentStory<typeof BadgeWrapper> = () => (
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.SM} size={AvatarNetworkSize.Sm}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -145,7 +145,7 @@ export const Badge: ComponentStory<typeof BadgeWrapper> = () => (
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -213,7 +213,7 @@ export const Position: ComponentStory<typeof BadgeWrapper> = () => (
position={BadgeWrapperPosition.topLeft} position={BadgeWrapperPosition.topLeft}
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -225,7 +225,7 @@ export const Position: ComponentStory<typeof BadgeWrapper> = () => (
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -238,7 +238,7 @@ export const Position: ComponentStory<typeof BadgeWrapper> = () => (
position={BadgeWrapperPosition.bottomLeft} position={BadgeWrapperPosition.bottomLeft}
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -251,7 +251,7 @@ export const Position: ComponentStory<typeof BadgeWrapper> = () => (
position={BadgeWrapperPosition.bottomRight} position={BadgeWrapperPosition.bottomRight}
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}
@ -268,7 +268,7 @@ export const PositionObj: ComponentStory<typeof BadgeWrapper> = () => (
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Avalanche" name="Avalanche"
src="./images/avax-token.png" src="./images/avax-token.png"
borderColor={BorderColor.borderMuted} borderColor={BorderColor.borderMuted}

View File

@ -6,7 +6,7 @@ export {
} from './avatar-account'; } from './avatar-account';
export { AvatarFavicon, AVATAR_FAVICON_SIZES } from './avatar-favicon'; export { AvatarFavicon, AVATAR_FAVICON_SIZES } from './avatar-favicon';
export { AvatarIcon, AVATAR_ICON_SIZES } from './avatar-icon'; export { AvatarIcon, AVATAR_ICON_SIZES } from './avatar-icon';
export { AvatarNetwork, AVATAR_NETWORK_SIZES } from './avatar-network'; export { AvatarNetwork, AvatarNetworkSize } from './avatar-network';
export { AvatarToken } from './avatar-token'; export { AvatarToken } from './avatar-token';
export { AvatarBase } from './avatar-base'; export { AvatarBase } from './avatar-base';
export { export {

View File

@ -4,14 +4,20 @@ import classnames from 'classnames';
import { import {
AlignItems, AlignItems,
DISPLAY, DISPLAY,
Size,
BorderRadius, BorderRadius,
TextVariant, TextVariant,
IconColor, IconColor,
BackgroundColor, BackgroundColor,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import Box from '../../ui/box'; import Box from '../../ui/box';
import { AvatarNetwork, IconName, Icon, IconSize, Text } from '..'; import {
AvatarNetwork,
AvatarNetworkSize,
IconName,
Icon,
IconSize,
Text,
} from '..';
export const PickerNetwork = ({ export const PickerNetwork = ({
className, className,
@ -38,7 +44,7 @@ export const PickerNetwork = ({
className="mm-picker-network__avatar-network" className="mm-picker-network__avatar-network"
src={src} src={src}
name={label} name={label}
size={Size.XS} size={AvatarNetworkSize.Xs}
{...avatarNetworkProps} {...avatarNetworkProps}
/> />
<Text ellipsis variant={TextVariant.bodySm}> <Text ellipsis variant={TextVariant.bodySm}>

View File

@ -7,12 +7,12 @@ import {
Color, Color,
Display, Display,
FontWeight, FontWeight,
Size,
TextAlign, TextAlign,
TextVariant, TextVariant,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { import {
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BadgeWrapper, BadgeWrapper,
BadgeWrapperAnchorElementShape, BadgeWrapperAnchorElementShape,
Box, Box,
@ -44,7 +44,7 @@ DefaultStory.args = {
<AvatarNetwork <AvatarNetwork
className="activity-tx__network-badge" className="activity-tx__network-badge"
data-testid="activity-tx-network-badge" data-testid="activity-tx-network-badge"
size={Size.XS} size={AvatarNetworkSize.Xs}
name="Network Name" name="Network Name"
src="./images/eth_logo.png" src="./images/eth_logo.png"
borderWidth={1} borderWidth={1}

View File

@ -5,6 +5,7 @@ import { useSelector } from 'react-redux';
import NftDefaultImage from '../../app/nft-default-image/nft-default-image'; import NftDefaultImage from '../../app/nft-default-image/nft-default-image';
import { import {
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
BadgeWrapper, BadgeWrapper,
BadgeWrapperAnchorElementShape, BadgeWrapperAnchorElementShape,
Box, Box,
@ -13,7 +14,6 @@ import {
BackgroundColor, BackgroundColor,
Display, Display,
JustifyContent, JustifyContent,
Size,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { getTestNetworkBackgroundColor } from '../../../selectors'; import { getTestNetworkBackgroundColor } from '../../../selectors';
@ -47,7 +47,7 @@ export const NftItem = ({
className="nft-item__network-badge" className="nft-item__network-badge"
backgroundColor={testNetworkBackgroundColor} backgroundColor={testNetworkBackgroundColor}
data-testid="nft-network-badge" data-testid="nft-network-badge"
size={Size.SM} size={AvatarNetworkSize.Sm}
name={networkName} name={networkName}
src={networkSrc} src={networkSrc}
borderWidth={2} borderWidth={2}

View File

@ -9,13 +9,13 @@ import {
FlexDirection, FlexDirection,
FontWeight, FontWeight,
JustifyContent, JustifyContent,
Size,
TextColor, TextColor,
TextVariant, TextVariant,
TextAlign, TextAlign,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { import {
AvatarNetwork, AvatarNetwork,
AvatarNetworkSize,
AvatarToken, AvatarToken,
BadgeWrapper, BadgeWrapper,
Box, Box,
@ -86,7 +86,7 @@ export const TokenListItem = ({
<BadgeWrapper <BadgeWrapper
badge={ badge={
<AvatarNetwork <AvatarNetwork
size={Size.XS} size={AvatarNetworkSize.Xs}
name={currentNetwork?.nickname} name={currentNetwork?.nickname}
src={currentNetwork?.rpcPrefs?.imageUrl} src={currentNetwork?.rpcPrefs?.imageUrl}
backgroundColor={testNetworkBackgroundColor} backgroundColor={testNetworkBackgroundColor}