mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Updating AvatarWithBage to BadgeWrapper (#17851)
This commit is contained in:
parent
de83546d6d
commit
ed519d8b60
@ -1,75 +0,0 @@
|
|||||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
|
|
||||||
|
|
||||||
import { AvatarWithBadge } from './avatar-with-badge';
|
|
||||||
|
|
||||||
# AvatarWithBadge
|
|
||||||
|
|
||||||
The `AvatarWithBadge` is a wrapper component that adds badge display options to avatars.
|
|
||||||
|
|
||||||
<Canvas>
|
|
||||||
<Story id="components-componentlibrary-avatarwithbadge--default-story" />
|
|
||||||
</Canvas>
|
|
||||||
|
|
||||||
## Props
|
|
||||||
|
|
||||||
The `AvatarWithBadge` accepts all props below as well as all [Box](/docs/components-ui-box--default-story#props) component props.
|
|
||||||
|
|
||||||
<ArgsTable of={AvatarWithBadge} />
|
|
||||||
|
|
||||||
### Badge Position
|
|
||||||
|
|
||||||
Use the `badgePosition` prop to set the position of the badge, it can have two values `Top` and `Bottom`
|
|
||||||
|
|
||||||
<Canvas>
|
|
||||||
<Story id="components-componentlibrary-avatarwithbadge--badge-position" />
|
|
||||||
</Canvas>
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
import { AvatarWithBadge } from '../ui/component-library';
|
|
||||||
|
|
||||||
<AvatarWithBadge
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.BOTTOM}
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
size={Size.XS}
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<AvatarAccount
|
|
||||||
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
|
|
||||||
size={Size.MD}
|
|
||||||
type={TYPES.JAZZICON}
|
|
||||||
/>
|
|
||||||
</AvatarWithBadge>
|
|
||||||
|
|
||||||
<AvatarWithBadge
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.TOP}
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
size={Size.XS}
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<AvatarAccount
|
|
||||||
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
|
|
||||||
size={Size.MD}
|
|
||||||
type={TYPES.JAZZICON}
|
|
||||||
/>
|
|
||||||
</AvatarWithBadge>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Badge
|
|
||||||
|
|
||||||
Used to define the badge component to be rendered inside the `AvatarWithBadge`.
|
|
||||||
|
|
||||||
### Badge Props
|
|
||||||
|
|
||||||
The required props to be passed to the badge.
|
|
||||||
|
|
||||||
### Children
|
|
||||||
|
|
||||||
The children to be rendered inside the AvatarWithBadge. Generally used with the `AvatarAccount`
|
|
@ -1,25 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`AvatarWithBadge should render correctly 1`] = `
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="box mm-avatar-with-badge box--flex-direction-row"
|
|
||||||
data-testid="avatar-with-badge"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="box mm-avatar-with-badge__badge-wrapper--position-bottom box--flex-direction-row"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="box mm-avatar-base mm-avatar-base--size-md mm-avatar-network box--display-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-text-default box--background-color-background-alternative box--border-color-transparent box--border-style-solid box--border-width-1"
|
|
||||||
data-testid="badge"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt="Arbitrum One logo"
|
|
||||||
class="mm-avatar-network__network-image"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
@ -1,4 +0,0 @@
|
|||||||
export const AVATAR_WITH_BADGE_POSTIONS = {
|
|
||||||
TOP: 'top',
|
|
||||||
BOTTOM: 'bottom',
|
|
||||||
};
|
|
@ -1,60 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Box from '../../ui/box/box';
|
|
||||||
import { AVATAR_WITH_BADGE_POSTIONS } from './avatar-with-badge.constants';
|
|
||||||
|
|
||||||
export const AvatarWithBadge = ({
|
|
||||||
children,
|
|
||||||
badgePosition,
|
|
||||||
className,
|
|
||||||
badge,
|
|
||||||
badgeWrapperProps,
|
|
||||||
...props
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Box className={classnames('mm-avatar-with-badge', className)} {...props}>
|
|
||||||
{/* Generally the AvatarAccount */}
|
|
||||||
{children}
|
|
||||||
<Box
|
|
||||||
className={
|
|
||||||
badgePosition === 'top'
|
|
||||||
? 'mm-avatar-with-badge__badge-wrapper--position-top'
|
|
||||||
: 'mm-avatar-with-badge__badge-wrapper--position-bottom'
|
|
||||||
}
|
|
||||||
{...badgeWrapperProps}
|
|
||||||
>
|
|
||||||
{/* Generally the AvatarNetwork at SIZES.XS */}
|
|
||||||
{badge}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
AvatarWithBadge.propTypes = {
|
|
||||||
/**
|
|
||||||
* The position of the Badge
|
|
||||||
* Possible values could be 'top', 'bottom',
|
|
||||||
*/
|
|
||||||
badgePosition: PropTypes.oneOf(Object.values(AVATAR_WITH_BADGE_POSTIONS)),
|
|
||||||
/**
|
|
||||||
* The Badge Wrapper props of the component. All Box props can be used
|
|
||||||
*/
|
|
||||||
badgeWrapperProps: PropTypes.shape(Box.PropTypes),
|
|
||||||
/**
|
|
||||||
* The children to be rendered inside the AvatarWithBadge
|
|
||||||
*/
|
|
||||||
children: PropTypes.node,
|
|
||||||
/**
|
|
||||||
* The badge to be rendered inside the AvatarWithBadge
|
|
||||||
*/
|
|
||||||
badge: PropTypes.object,
|
|
||||||
/**
|
|
||||||
* Add custom css class
|
|
||||||
*/
|
|
||||||
className: PropTypes.string,
|
|
||||||
/**
|
|
||||||
* AvatarWithBadge accepts all the props from Box
|
|
||||||
*/
|
|
||||||
...Box.propTypes,
|
|
||||||
};
|
|
@ -1,16 +0,0 @@
|
|||||||
.mm-avatar-with-badge {
|
|
||||||
position: relative;
|
|
||||||
width: fit-content;
|
|
||||||
|
|
||||||
&__badge-wrapper--position-top {
|
|
||||||
position: absolute;
|
|
||||||
top: -4px;
|
|
||||||
right: -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__badge-wrapper--position-bottom {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -4px;
|
|
||||||
right: -4px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { AvatarAccount } from '../avatar-account';
|
|
||||||
import { AVATAR_ACCOUNT_TYPES } from '../avatar-account/avatar-account.constants';
|
|
||||||
import { AvatarNetwork } from '../avatar-network';
|
|
||||||
import Box from '../../ui/box/box';
|
|
||||||
import {
|
|
||||||
AlignItems,
|
|
||||||
DISPLAY,
|
|
||||||
Size,
|
|
||||||
} from '../../../helpers/constants/design-system';
|
|
||||||
import { AVATAR_WITH_BADGE_POSTIONS } from './avatar-with-badge.constants';
|
|
||||||
import README from './README.mdx';
|
|
||||||
import { AvatarWithBadge } from './avatar-with-badge';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Components/ComponentLibrary/AvatarWithBadge',
|
|
||||||
|
|
||||||
component: AvatarWithBadge,
|
|
||||||
parameters: {
|
|
||||||
docs: {
|
|
||||||
page: README,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
argTypes: {
|
|
||||||
badgePosition: {
|
|
||||||
options: Object.values(AVATAR_WITH_BADGE_POSTIONS),
|
|
||||||
control: 'select',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
args: {
|
|
||||||
badgePosition: AVATAR_WITH_BADGE_POSTIONS.top,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DefaultStory = (args) => (
|
|
||||||
<AvatarWithBadge
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
size={Size.XS}
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{...args}
|
|
||||||
>
|
|
||||||
<AvatarAccount
|
|
||||||
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
|
|
||||||
size={Size.MD}
|
|
||||||
type={AVATAR_ACCOUNT_TYPES.JAZZICON}
|
|
||||||
/>
|
|
||||||
</AvatarWithBadge>
|
|
||||||
);
|
|
||||||
DefaultStory.storyName = 'Default';
|
|
||||||
|
|
||||||
export const BadgePosition = () => (
|
|
||||||
<Box display={DISPLAY.FLEX} alignItems={AlignItems.baseline} gap={1}>
|
|
||||||
<AvatarWithBadge
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.BOTTOM}
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
size={Size.XS}
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<AvatarAccount
|
|
||||||
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
|
|
||||||
size={Size.MD}
|
|
||||||
type={AVATAR_ACCOUNT_TYPES.JAZZICON}
|
|
||||||
/>
|
|
||||||
</AvatarWithBadge>
|
|
||||||
|
|
||||||
<AvatarWithBadge
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.TOP}
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
size={Size.XS}
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<AvatarAccount
|
|
||||||
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
|
|
||||||
size={Size.MD}
|
|
||||||
type={AVATAR_ACCOUNT_TYPES.JAZZICON}
|
|
||||||
/>
|
|
||||||
</AvatarWithBadge>
|
|
||||||
</Box>
|
|
||||||
);
|
|
@ -1,102 +0,0 @@
|
|||||||
/* eslint-disable jest/require-top-level-describe */
|
|
||||||
import { render } from '@testing-library/react';
|
|
||||||
import React from 'react';
|
|
||||||
import { AvatarNetwork } from '../avatar-network/avatar-network';
|
|
||||||
import { BorderColor } from '../../../helpers/constants/design-system';
|
|
||||||
import { AvatarWithBadge } from './avatar-with-badge';
|
|
||||||
import { AVATAR_WITH_BADGE_POSTIONS } from './avatar-with-badge.constants';
|
|
||||||
|
|
||||||
describe('AvatarWithBadge', () => {
|
|
||||||
it('should render correctly', () => {
|
|
||||||
const { getByTestId, container } = render(
|
|
||||||
<AvatarWithBadge
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.BOTTOM}
|
|
||||||
data-testid="avatar-with-badge"
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
data-testid="badge"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
expect(getByTestId('avatar-with-badge')).toBeDefined();
|
|
||||||
expect(getByTestId('badge')).toBeDefined();
|
|
||||||
expect(container).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render badge network with bottom right position correctly', () => {
|
|
||||||
const { container } = render(
|
|
||||||
<AvatarWithBadge
|
|
||||||
data-testid="avatar-with-badge"
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.BOTTOM}
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
data-testid="badge"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
container.getElementsByClassName(
|
|
||||||
'mm-avatar-with-badge__badge-wrapper--position-bottom',
|
|
||||||
),
|
|
||||||
).toHaveLength(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render badge network with top right position correctly', () => {
|
|
||||||
const { container } = render(
|
|
||||||
<AvatarWithBadge
|
|
||||||
data-testid="avatar-with-badge"
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.TOP}
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
data-testid="badge"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
container.getElementsByClassName(
|
|
||||||
'mm-avatar-with-badge__badge-wrapper--position-top',
|
|
||||||
),
|
|
||||||
).toHaveLength(1);
|
|
||||||
});
|
|
||||||
it('should render badge network with badgeWrapperProps', () => {
|
|
||||||
const container = (
|
|
||||||
<AvatarWithBadge
|
|
||||||
data-testid="avatar-with-badge"
|
|
||||||
badgePosition={AVATAR_WITH_BADGE_POSTIONS.TOP}
|
|
||||||
badgeWrapperProps={{ borderColor: BorderColor.errorDefault }}
|
|
||||||
badge={
|
|
||||||
<AvatarNetwork
|
|
||||||
name="Arbitrum One"
|
|
||||||
src="./images/arbitrum.svg"
|
|
||||||
data-testid="badge"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
expect(container.props.badgeWrapperProps.borderColor).toStrictEqual(
|
|
||||||
'error-default',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// className
|
|
||||||
it('should render with custom className', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<AvatarWithBadge
|
|
||||||
data-testid="avatar-with-badge"
|
|
||||||
className="test-class"
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
expect(getByTestId('avatar-with-badge')).toHaveClass('test-class');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,2 +0,0 @@
|
|||||||
export { AvatarWithBadge } from './avatar-with-badge';
|
|
||||||
export { AVATAR_WITH_BADGE_POSTIONS } from './avatar-with-badge.constants';
|
|
378
ui/components/component-library/badge-wrapper/README.mdx
Normal file
378
ui/components/component-library/badge-wrapper/README.mdx
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
|
||||||
|
|
||||||
|
import { BadgeWrapper } from './badge-wrapper';
|
||||||
|
|
||||||
|
# BadgeWrapper
|
||||||
|
|
||||||
|
The `BadgeWrapper` positions a badge on top of another component
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story id="components-componentlibrary-badgewrapper--default-story" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
## Props
|
||||||
|
|
||||||
|
The `BadgeWrapper` accepts all props below as well as all [Box](/docs/components-ui-box--default-story#props) component props.
|
||||||
|
|
||||||
|
<ArgsTable of={BadgeWrapper} />
|
||||||
|
|
||||||
|
### Children
|
||||||
|
|
||||||
|
Use the `children` prop to define the element to be wrapped by the `BadgeWrapper`. This element will be what the badge is positioned on top of.
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story id="components-componentlibrary-badgewrapper--children" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { Color, Size } from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import {
|
||||||
|
AvatarAccount,
|
||||||
|
AvatarNetwork,
|
||||||
|
AvatarToken,
|
||||||
|
BadgeWrapper,
|
||||||
|
BadgeWrapperAnchorElementShape,
|
||||||
|
BadgeWrapperPosition,
|
||||||
|
} from '../../component-library';
|
||||||
|
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount
|
||||||
|
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarToken
|
||||||
|
name="Eth"
|
||||||
|
src="./images/eth_logo.svg"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.SM}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
as="img"
|
||||||
|
src="./catnip-spicywright.png"
|
||||||
|
borderRadius={BorderRadius.SM}
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
style={{ width: 100, height: 100 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Badge
|
||||||
|
|
||||||
|
Use the `badge` prop to define the badge component to be rendered on top of the `children` component.
|
||||||
|
|
||||||
|
To access the component containing the badge, use the `badgeContainerProps` prop. The wrapping component is a `Box` and accepts all box props.
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story id="components-componentlibrary-badgewrapper--badge" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
|
||||||
|
import {
|
||||||
|
BorderColor,
|
||||||
|
BorderRadius,
|
||||||
|
Color,
|
||||||
|
IconColor,
|
||||||
|
Size,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import {
|
||||||
|
AvatarAccount,
|
||||||
|
AvatarNetwork,
|
||||||
|
BadgeWrapper,
|
||||||
|
BadgeWrapperAnchorElementShape,
|
||||||
|
Icon,
|
||||||
|
ICON_NAMES,
|
||||||
|
Tag,
|
||||||
|
} from '../../component-library';
|
||||||
|
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.successDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
borderWidth={2}
|
||||||
|
style={{ width: 12, height: 12 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name={ICON_NAMES.GLOBAL}
|
||||||
|
size={Size.XL}
|
||||||
|
color={IconColor.iconAlternative}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<Box
|
||||||
|
paddingTop={1}
|
||||||
|
paddingBottom={1}
|
||||||
|
paddingRight={1}
|
||||||
|
paddingLeft={1}
|
||||||
|
backgroundColor={Color.backgroundAlternative}
|
||||||
|
borderRadius={BorderRadius.SM}
|
||||||
|
style={{ alignSelf: 'flex-start' }}
|
||||||
|
>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Tag
|
||||||
|
label="9999"
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
labelProps={{ color: Color.errorInverse }}
|
||||||
|
borderColor={BorderColor.errorDefault}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
paddingTop={1}
|
||||||
|
paddingBottom={1}
|
||||||
|
paddingRight={8}
|
||||||
|
paddingLeft={8}
|
||||||
|
borderRadius={BorderRadius.SM}
|
||||||
|
borderColor={BorderColor.borderDefault}
|
||||||
|
backgroundColor={Color.backgroundDefault}
|
||||||
|
>
|
||||||
|
NFTs
|
||||||
|
</Box>
|
||||||
|
</BadgeWrapper>
|
||||||
|
</Box>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Position
|
||||||
|
|
||||||
|
Use the `position` prop and the `BadgeWrapperPosition` enum to set the position of the badge. Possible positions are:
|
||||||
|
|
||||||
|
- top left `BadgeWrapperPosition.topLeft`
|
||||||
|
- top right `BadgeWrapperPosition.topRight`
|
||||||
|
- bottom left `BadgeWrapperPosition.bottomLeft`
|
||||||
|
- bottom right `BadgeWrapperPosition.bottomRight`
|
||||||
|
|
||||||
|
If you require a custom position, you can use the `positionObj` prop see [Position Obj](/docs/components-componentlibrary-badgewrapper--position-obj#position-obj) for more details.
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story id="components-componentlibrary-badgewrapper--position" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { BorderColor Size } from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import {
|
||||||
|
AvatarAccount,
|
||||||
|
AvatarNetwork,
|
||||||
|
BadgeWrapper,
|
||||||
|
BadgeWrapperPosition
|
||||||
|
} from '../../component-library';
|
||||||
|
|
||||||
|
<BadgeWrapper
|
||||||
|
position={BadgeWrapperPosition.topLeft}
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
position={BadgeWrapperPosition.bottomLeft}
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
position={BadgeWrapperPosition.bottomRight}
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Position Obj
|
||||||
|
|
||||||
|
Use the `positionObj` prop to set a custom position for the badge. The `positionObj` prop takes an object with the following properties:
|
||||||
|
|
||||||
|
- `top` - the top position of the badge
|
||||||
|
- `right` - the right position of the badge
|
||||||
|
- `bottom` - the bottom position of the badge
|
||||||
|
- `left` - the left position of the badge
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story id="components-componentlibrary-badgewrapper--position-obj" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { BorderColor Size } from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import {
|
||||||
|
AvatarAccount,
|
||||||
|
AvatarNetwork,
|
||||||
|
BadgeWrapper,
|
||||||
|
} from '../../component-library';
|
||||||
|
|
||||||
|
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
positionObj={{ top: 4, right: -8 }}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Anchor Element Shape
|
||||||
|
|
||||||
|
Use the `anchorElementShape` prop and the `BadgeWrapperAnchorElementShape` enum to set the badge position relative to the shape of the anchor element. Possible shapes are:
|
||||||
|
|
||||||
|
- circular `BadgeWrapperAnchorElementShape.circular`
|
||||||
|
- rectangular `BadgeWrapperAnchorElementShape.rectangular`
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story id="components-componentlibrary-badgewrapper--anchor-element-shape" />
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import Box from '../../ui/box/box';
|
||||||
|
|
||||||
|
import { BorderRadius, Color } from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import { BadgeWrapper, BadgeWrapperAnchorElementShape } from '../../component-library';
|
||||||
|
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 16, height: 16 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 8, height: 8 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 16, height: 16 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 8, height: 8 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
```
|
@ -0,0 +1,20 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`BadgeWrapper should render correctly 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="box mm-badge-wrapper box--display-inline-block box--flex-direction-row"
|
||||||
|
>
|
||||||
|
content
|
||||||
|
<div
|
||||||
|
class="box mm-badge-wrapper__badge-container mm-badge-wrapper__badge-container--circular-top-right box--flex-direction-row"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-testid="badge"
|
||||||
|
>
|
||||||
|
badge
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* Mixin that renders the CSS values for badge positions and value
|
||||||
|
*/
|
||||||
|
@mixin badgePosition($position, $value) {
|
||||||
|
@if $position == top-right {
|
||||||
|
top: $value;
|
||||||
|
right: $value;
|
||||||
|
transform: scale(1) translate(50%, -50%);
|
||||||
|
transform-origin: 100% 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@else if $position == bottom-right {
|
||||||
|
bottom: $value;
|
||||||
|
right: $value;
|
||||||
|
transform: scale(1) translate(50%, 50%);
|
||||||
|
transform-origin: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@else if $position == top-left {
|
||||||
|
top: $value;
|
||||||
|
left: $value;
|
||||||
|
transform: scale(1) translate(-50%, -50%);
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@else if $position == bottom-left {
|
||||||
|
bottom: $value;
|
||||||
|
left: $value;
|
||||||
|
transform: scale(1) translate(-50%, 50%);
|
||||||
|
transform-origin: 0% 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-badge-wrapper {
|
||||||
|
--badge-wrapper-position-circular: 14%;
|
||||||
|
--badge-wrapper-position-rectangular: 0;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
align-self: start; // prevents stretching of badge-wrapper when in flexbox container to maintain badge positioning
|
||||||
|
|
||||||
|
&__badge-container {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
&--circular {
|
||||||
|
&-top-right {
|
||||||
|
@include badgePosition('top-right', var(--badge-wrapper-position-circular));
|
||||||
|
}
|
||||||
|
|
||||||
|
&-bottom-right {
|
||||||
|
@include badgePosition('bottom-right', var(--badge-wrapper-position-circular));
|
||||||
|
}
|
||||||
|
|
||||||
|
&-top-left {
|
||||||
|
@include badgePosition('top-left', var(--badge-wrapper-position-circular));
|
||||||
|
}
|
||||||
|
|
||||||
|
&-bottom-left {
|
||||||
|
@include badgePosition('bottom-left', var(--badge-wrapper-position-circular));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--rectangular {
|
||||||
|
&-top-right {
|
||||||
|
@include badgePosition('top-right', var(--badge-wrapper-position-rectangular));
|
||||||
|
}
|
||||||
|
|
||||||
|
&-bottom-right {
|
||||||
|
@include badgePosition('bottom-right', var(--badge-wrapper-position-rectangular));
|
||||||
|
}
|
||||||
|
|
||||||
|
&-top-left {
|
||||||
|
@include badgePosition('top-left', var(--badge-wrapper-position-rectangular));
|
||||||
|
}
|
||||||
|
|
||||||
|
&-bottom-left {
|
||||||
|
@include badgePosition('bottom-left', var(--badge-wrapper-position-rectangular));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,360 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
AlignItems,
|
||||||
|
BorderColor,
|
||||||
|
BorderRadius,
|
||||||
|
Color,
|
||||||
|
DISPLAY,
|
||||||
|
IconColor,
|
||||||
|
Size,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import Box from '../../ui/box/box';
|
||||||
|
|
||||||
|
import {
|
||||||
|
AvatarAccount,
|
||||||
|
AvatarNetwork,
|
||||||
|
AvatarToken,
|
||||||
|
Icon,
|
||||||
|
ICON_NAMES,
|
||||||
|
Tag,
|
||||||
|
} from '..';
|
||||||
|
import {
|
||||||
|
BadgeWrapperAnchorElementShape,
|
||||||
|
BadgeWrapperPosition,
|
||||||
|
} from './badge-wrapper.types';
|
||||||
|
|
||||||
|
import README from './README.mdx';
|
||||||
|
|
||||||
|
import { BadgeWrapper } from './badge-wrapper';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/ComponentLibrary/BadgeWrapper',
|
||||||
|
component: BadgeWrapper,
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
page: README,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
children: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
badge: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
options: Object.values(BadgeWrapperPosition),
|
||||||
|
control: 'select',
|
||||||
|
},
|
||||||
|
positionObj: {
|
||||||
|
control: 'object',
|
||||||
|
},
|
||||||
|
anchorElementShape: {
|
||||||
|
options: Object.values(BadgeWrapperAnchorElementShape),
|
||||||
|
control: 'select',
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ComponentMeta<typeof BadgeWrapper>;
|
||||||
|
|
||||||
|
const Template: ComponentStory<typeof BadgeWrapper> = (args) => (
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{...args}
|
||||||
|
>
|
||||||
|
{args.children ? (
|
||||||
|
args.children
|
||||||
|
) : (
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
)}
|
||||||
|
</BadgeWrapper>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const DefaultStory = Template.bind({});
|
||||||
|
|
||||||
|
DefaultStory.storyName = 'Default';
|
||||||
|
|
||||||
|
export const Children = () => (
|
||||||
|
<Box display={DISPLAY.FLEX} gap={4}>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarToken
|
||||||
|
name="Eth"
|
||||||
|
src="./images/eth_logo.svg"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.SM}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
as="img"
|
||||||
|
src="./catnip-spicywright.png"
|
||||||
|
borderRadius={BorderRadius.SM}
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
style={{ width: 100, height: 100 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Badge = () => (
|
||||||
|
<Box display={DISPLAY.FLEX} gap={4}>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.successDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
borderWidth={2}
|
||||||
|
style={{ width: 12, height: 12 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name={ICON_NAMES.GLOBAL}
|
||||||
|
size={Size.XL}
|
||||||
|
color={IconColor.iconAlternative}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<Box
|
||||||
|
paddingTop={1}
|
||||||
|
paddingBottom={1}
|
||||||
|
paddingRight={1}
|
||||||
|
paddingLeft={1}
|
||||||
|
backgroundColor={Color.backgroundAlternative}
|
||||||
|
borderRadius={BorderRadius.SM}
|
||||||
|
style={{ alignSelf: 'flex-start' }}
|
||||||
|
>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Tag
|
||||||
|
label="9999"
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
labelProps={{ color: Color.errorInverse }}
|
||||||
|
borderColor={BorderColor.errorDefault}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
paddingTop={1}
|
||||||
|
paddingBottom={1}
|
||||||
|
paddingRight={8}
|
||||||
|
paddingLeft={8}
|
||||||
|
borderRadius={BorderRadius.SM}
|
||||||
|
borderColor={BorderColor.borderDefault}
|
||||||
|
backgroundColor={Color.backgroundDefault}
|
||||||
|
>
|
||||||
|
NFTs
|
||||||
|
</Box>
|
||||||
|
</BadgeWrapper>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Position = () => (
|
||||||
|
<Box display={DISPLAY.FLEX} gap={4}>
|
||||||
|
<BadgeWrapper
|
||||||
|
position={BadgeWrapperPosition.topLeft}
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
position={BadgeWrapperPosition.bottomLeft}
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
position={BadgeWrapperPosition.bottomRight}
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const PositionObj = () => (
|
||||||
|
<Box display={DISPLAY.FLEX} alignItems={AlignItems.baseline} gap={4}>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<AvatarNetwork
|
||||||
|
size={Size.XS}
|
||||||
|
name="Avalanche"
|
||||||
|
src="./images/avax-token.png"
|
||||||
|
borderColor={BorderColor.borderMuted}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
positionObj={{ top: 4, right: -8 }}
|
||||||
|
>
|
||||||
|
<AvatarAccount address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1" />
|
||||||
|
</BadgeWrapper>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AnchorElementShape = () => (
|
||||||
|
<Box display={DISPLAY.FLEX} gap={4}>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 16, height: 16 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 8, height: 8 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 16, height: 16 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 8, height: 8 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
style={{ width: 40, height: 40 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
badge={
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.errorDefault}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
style={{ width: 16, height: 16 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
backgroundColor={Color.infoDefault}
|
||||||
|
style={{ width: 40, height: 80 }}
|
||||||
|
/>
|
||||||
|
</BadgeWrapper>
|
||||||
|
</Box>
|
||||||
|
);
|
@ -0,0 +1,143 @@
|
|||||||
|
/* eslint-disable jest/require-top-level-describe */
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { BadgeWrapper } from './badge-wrapper';
|
||||||
|
import {
|
||||||
|
BadgeWrapperPosition,
|
||||||
|
BadgeWrapperAnchorElementShape,
|
||||||
|
} from './badge-wrapper.types';
|
||||||
|
|
||||||
|
describe('BadgeWrapper', () => {
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const { getByText, container } = render(
|
||||||
|
<BadgeWrapper badge={<div data-testid="badge">badge</div>}>
|
||||||
|
content
|
||||||
|
</BadgeWrapper>,
|
||||||
|
);
|
||||||
|
expect(getByText('content')).toBeDefined();
|
||||||
|
expect(getByText('badge')).toBeDefined();
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with additional className', () => {
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<BadgeWrapper data-testid="badge-wrapper" className="test-class">
|
||||||
|
content
|
||||||
|
</BadgeWrapper>,
|
||||||
|
);
|
||||||
|
expect(getByTestId('badge-wrapper')).toHaveClass('test-class');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render badge positions correctly', () => {
|
||||||
|
const { getByTestId, getByText } = render(
|
||||||
|
<>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-default' }}
|
||||||
|
>
|
||||||
|
content default
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-top-right' }}
|
||||||
|
position={BadgeWrapperPosition.topRight}
|
||||||
|
>
|
||||||
|
content top-right
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-top-left' }}
|
||||||
|
position={BadgeWrapperPosition.topLeft}
|
||||||
|
>
|
||||||
|
content top-left
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-bottom-right' }}
|
||||||
|
position={BadgeWrapperPosition.bottomRight}
|
||||||
|
>
|
||||||
|
content bottom-right
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-bottom-left' }}
|
||||||
|
position={BadgeWrapperPosition.bottomLeft}
|
||||||
|
>
|
||||||
|
content bottom-left
|
||||||
|
</BadgeWrapper>
|
||||||
|
</>,
|
||||||
|
);
|
||||||
|
expect(getByText('content default')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-default')).toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--circular-top-right',
|
||||||
|
);
|
||||||
|
expect(getByText('content top-right')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-top-right')).toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--circular-top-right',
|
||||||
|
);
|
||||||
|
expect(getByText('content top-left')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-top-left')).toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--circular-top-left',
|
||||||
|
);
|
||||||
|
expect(getByText('content bottom-right')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-bottom-right')).toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--circular-bottom-right',
|
||||||
|
);
|
||||||
|
expect(getByText('content bottom-left')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-bottom-left')).toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--circular-bottom-left',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the badge with custom position', () => {
|
||||||
|
const { getByTestId, getByText } = render(
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-custom' }}
|
||||||
|
position={{
|
||||||
|
top: -10,
|
||||||
|
right: -10,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
content custom
|
||||||
|
</BadgeWrapper>,
|
||||||
|
);
|
||||||
|
expect(getByText('content custom')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-custom')).not.toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--circular-top-right',
|
||||||
|
);
|
||||||
|
expect(getByTestId('badge-custom')).toHaveStyle({
|
||||||
|
top: -10,
|
||||||
|
right: -10,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render badge anchor element shape correctly', () => {
|
||||||
|
const { getByTestId, getByText } = render(
|
||||||
|
<>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-circular' }}
|
||||||
|
>
|
||||||
|
content circular
|
||||||
|
</BadgeWrapper>
|
||||||
|
<BadgeWrapper
|
||||||
|
badge={<div>badge</div>}
|
||||||
|
badgeContainerProps={{ 'data-testid': 'badge-rectangular' }}
|
||||||
|
anchorElementShape={BadgeWrapperAnchorElementShape.rectangular}
|
||||||
|
>
|
||||||
|
content rectangular
|
||||||
|
</BadgeWrapper>
|
||||||
|
</>,
|
||||||
|
);
|
||||||
|
expect(getByText('content circular')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-circular')).toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--circular-top-right',
|
||||||
|
);
|
||||||
|
expect(getByText('content rectangular')).toBeDefined();
|
||||||
|
expect(getByTestId('badge-rectangular')).toHaveClass(
|
||||||
|
'mm-badge-wrapper__badge-container--rectangular-top-right',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import { DISPLAY } from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import Box from '../../ui/box';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BadgeWrapperPosition,
|
||||||
|
BadgeWrapperAnchorElementShape,
|
||||||
|
BadgeWrapperProps,
|
||||||
|
} from './badge-wrapper.types';
|
||||||
|
|
||||||
|
export const BadgeWrapper = ({
|
||||||
|
children,
|
||||||
|
badge,
|
||||||
|
badgeContainerProps,
|
||||||
|
position = BadgeWrapperPosition.topRight,
|
||||||
|
positionObj,
|
||||||
|
anchorElementShape = BadgeWrapperAnchorElementShape.circular,
|
||||||
|
className = '',
|
||||||
|
color,
|
||||||
|
...props
|
||||||
|
}: BadgeWrapperProps) => (
|
||||||
|
<Box
|
||||||
|
className={classnames('mm-badge-wrapper', className)}
|
||||||
|
display={DISPLAY.INLINE_BLOCK}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{/* Generally the AvatarAccount or AvatarToken */}
|
||||||
|
{children}
|
||||||
|
<Box
|
||||||
|
className={classnames('mm-badge-wrapper__badge-container', {
|
||||||
|
[`mm-badge-wrapper__badge-container--${anchorElementShape}-${position}`]:
|
||||||
|
!positionObj,
|
||||||
|
})}
|
||||||
|
style={{ ...positionObj }}
|
||||||
|
{...badgeContainerProps}
|
||||||
|
>
|
||||||
|
{/* Generally the AvatarNetwork at SIZES.XS */}
|
||||||
|
{badge}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
@ -0,0 +1,55 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Box from '../../ui/box';
|
||||||
|
import type { BoxProps } from '../../ui/box/box.d';
|
||||||
|
|
||||||
|
export enum BadgeWrapperPosition {
|
||||||
|
topRight = 'top-right',
|
||||||
|
bottomRight = 'bottom-right',
|
||||||
|
topLeft = 'top-left',
|
||||||
|
bottomLeft = 'bottom-left',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum BadgeWrapperAnchorElementShape {
|
||||||
|
rectangular = 'rectangular',
|
||||||
|
circular = 'circular',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BadgeWrapperProps
|
||||||
|
extends PropTypes.InferProps<typeof Box.propTypes>,
|
||||||
|
React.HTMLAttributes<HTMLDivElement> {
|
||||||
|
/**
|
||||||
|
* The element to be wrapped by the BadgeWrapper and for the badge to be positioned on top of
|
||||||
|
*/
|
||||||
|
children: React.ReactNode;
|
||||||
|
/**
|
||||||
|
* Use the `badge` prop to define the badge component to be rendered on top of the `children` component
|
||||||
|
*/
|
||||||
|
badge?: React.ReactNode;
|
||||||
|
/**
|
||||||
|
* The BadgeWrapper props of the component. All Box props can be used
|
||||||
|
*/
|
||||||
|
badgeContainerProps?: BoxProps;
|
||||||
|
/**
|
||||||
|
* The position of the Badge. Possible values could be 'BadgeWrapperPosition.topRight', 'BadgeWrapperPosition.bottomRight','BadgeWrapperPosition.topLeft', 'BadgeWrapperPosition.bottomLeft'
|
||||||
|
* Defaults to 'BadgeWrapperPosition.topRight'
|
||||||
|
*/
|
||||||
|
position?: BadgeWrapperPosition;
|
||||||
|
/**
|
||||||
|
* The positionObj can be used to override the default positioning of the badge it accepts an object with the following keys { top, right, bottom, left }
|
||||||
|
*/
|
||||||
|
positionObj?: {
|
||||||
|
top?: number;
|
||||||
|
right?: number;
|
||||||
|
bottom?: number;
|
||||||
|
left?: number;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The shape of the anchor element. Possible values could be 'BadgeWrapperAnchorElementShape.circular', 'BadgeWrapperAnchorElementShape.square'
|
||||||
|
* Defaults to
|
||||||
|
*/
|
||||||
|
anchorElementShape?: BadgeWrapperAnchorElementShape;
|
||||||
|
/**
|
||||||
|
* Additional classNames to be added to the BadgeWrapper component
|
||||||
|
*/
|
||||||
|
className?: string;
|
||||||
|
}
|
7
ui/components/component-library/badge-wrapper/index.ts
Normal file
7
ui/components/component-library/badge-wrapper/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export { BadgeWrapper } from './badge-wrapper';
|
||||||
|
export {
|
||||||
|
BadgeWrapperPosition,
|
||||||
|
BadgeWrapperAnchorElementShape,
|
||||||
|
} from './badge-wrapper.types';
|
||||||
|
|
||||||
|
export type { BadgeWrapperProps } from './badge-wrapper.types';
|
@ -14,7 +14,7 @@
|
|||||||
@import 'avatar-favicon/avatar-favicon';
|
@import 'avatar-favicon/avatar-favicon';
|
||||||
@import 'avatar-network/avatar-network';
|
@import 'avatar-network/avatar-network';
|
||||||
@import 'avatar-token/avatar-token';
|
@import 'avatar-token/avatar-token';
|
||||||
@import 'avatar-with-badge/avatar-with-badge';
|
@import 'badge-wrapper/badge-wrapper';
|
||||||
@import 'button-base/button-base';
|
@import 'button-base/button-base';
|
||||||
@import 'button-icon/button-icon';
|
@import 'button-icon/button-icon';
|
||||||
@import 'button-link/button-link';
|
@import 'button-link/button-link';
|
||||||
|
@ -9,9 +9,10 @@ export { AvatarIcon, AVATAR_ICON_SIZES } from './avatar-icon';
|
|||||||
export { AvatarNetwork, AVATAR_NETWORK_SIZES } from './avatar-network';
|
export { AvatarNetwork, AVATAR_NETWORK_SIZES } from './avatar-network';
|
||||||
export { AvatarToken } from './avatar-token';
|
export { AvatarToken } from './avatar-token';
|
||||||
export {
|
export {
|
||||||
AvatarWithBadge,
|
BadgeWrapper,
|
||||||
AVATAR_WITH_BADGE_POSTIONS,
|
BadgeWrapperPosition,
|
||||||
} from './avatar-with-badge';
|
BadgeWrapperAnchorElementShape,
|
||||||
|
} from './badge-wrapper';
|
||||||
export { AvatarBase } from './avatar-base';
|
export { AvatarBase } from './avatar-base';
|
||||||
export { Button, BUTTON_TYPES, BUTTON_SIZES } from './button';
|
export { Button, BUTTON_TYPES, BUTTON_SIZES } from './button';
|
||||||
export { ButtonBase, BUTTON_BASE_SIZES } from './button-base';
|
export { ButtonBase, BUTTON_BASE_SIZES } from './button-base';
|
||||||
|
Loading…
Reference in New Issue
Block a user