From d3c9d4a55ad965ff8ba30b4c2bf194eb2b661e86 Mon Sep 17 00:00:00 2001 From: Binij Shrestha <93417120+thebinij@users.noreply.github.com> Date: Wed, 26 Jul 2023 20:35:53 +0545 Subject: [PATCH] Fix/18885 migrate avatar token (#19080) * Migrate AvatarToken --------- Co-authored-by: garrettbear --- .../avatar-network/avatar-network.types.ts | 2 +- .../component-library/avatar-token/README.mdx | 48 +++---- ...est.js.snap => avatar-token.test.tsx.snap} | 0 .../avatar-token/avatar-token.constants.js | 9 -- .../avatar-token/avatar-token.js | 133 ------------------ ...en.stories.js => avatar-token.stories.tsx} | 114 ++++++++------- ...ar-token.test.js => avatar-token.test.tsx} | 57 +++++++- .../avatar-token/avatar-token.tsx | 90 ++++++++++++ .../avatar-token/avatar-token.types.ts | 42 ++++++ .../component-library/avatar-token/index.js | 1 - .../component-library/avatar-token/index.ts | 3 + ui/components/component-library/index.js | 4 +- 12 files changed, 268 insertions(+), 235 deletions(-) rename ui/components/component-library/avatar-token/__snapshots__/{avatar-token.test.js.snap => avatar-token.test.tsx.snap} (100%) delete mode 100644 ui/components/component-library/avatar-token/avatar-token.constants.js delete mode 100644 ui/components/component-library/avatar-token/avatar-token.js rename ui/components/component-library/avatar-token/{avatar-token.stories.js => avatar-token.stories.tsx} (71%) rename ui/components/component-library/avatar-token/{avatar-token.test.js => avatar-token.test.tsx} (72%) create mode 100644 ui/components/component-library/avatar-token/avatar-token.tsx create mode 100644 ui/components/component-library/avatar-token/avatar-token.types.ts delete mode 100644 ui/components/component-library/avatar-token/index.js create mode 100644 ui/components/component-library/avatar-token/index.ts diff --git a/ui/components/component-library/avatar-network/avatar-network.types.ts b/ui/components/component-library/avatar-network/avatar-network.types.ts index d0d049143..c4caea3f6 100644 --- a/ui/components/component-library/avatar-network/avatar-network.types.ts +++ b/ui/components/component-library/avatar-network/avatar-network.types.ts @@ -13,7 +13,7 @@ export enum AvatarNetworkSize { * Props for the AvatarNetwork component */ export interface AvatarNetworkStyleUtilityProps - extends Omit { + extends Omit { /** * The name accepts the string to render the first alphabet of the Avatar Name */ diff --git a/ui/components/component-library/avatar-token/README.mdx b/ui/components/component-library/avatar-token/README.mdx index fb39789bf..435a2fbf1 100644 --- a/ui/components/component-library/avatar-token/README.mdx +++ b/ui/components/component-library/avatar-token/README.mdx @@ -12,23 +12,23 @@ The `AvatarToken` is a component responsible for display of the image of a given ## Props -The `AvatarToken` accepts all props below as well as all [Box](/docs/components-ui-box--default-story#props) component props +The `AvatarToken` accepts all props below as well as all [Box](/docs/components-componentlibrary-box--docs#props) component props ### Size -Use the `size` prop to set the size of the `AvatarToken`. +Use the `size` prop and the `AvatarTokenSize` enum to change the size of `AvatarToken`. Defaults to `IconSize.Sm` Possible sizes include: -- `xs` 16px -- `sm` 24px -- `md` 32px -- `lg` 40px -- `xl` 48px +- `AvatarTokenSize.Xs` 16px +- `AvatarTokenSize.Sm` 24px +- `AvatarTokenSize.Md` 32px +- `AvatarTokenSize.Lg` 40px +- `AvatarTokenSize.Xl` 48px -Defaults to `md` +Defaults to `AvatarTokenSize.Md` The fallback display of the `AvatarToken` is a circle with the initial letter of the network name. The size of the initial letter is calculated based on the size of the `AvatarToken` component. @@ -37,13 +37,13 @@ The fallback display of the `AvatarToken` is a circle with the initial letter of ```jsx -import { AvatarToken } from '../../component-library'; +import { AvatarToken, AvatarTokenSize } from '../../component-library'; - - - - - + + + + + ``` ### Name @@ -104,24 +104,22 @@ Use the `color`, `backgroundColor` and `borderColor` props to set the text color ```jsx -import { TextColor, - BackgroundColor, - BorderColor, } from '../../../helpers/constants/design-system'; +import { TextColor, BackgroundColor, BorderColor, } from '../../../helpers/constants/design-system'; import { AvatarToken } from '../../component-library'; G S diff --git a/ui/components/component-library/avatar-token/__snapshots__/avatar-token.test.js.snap b/ui/components/component-library/avatar-token/__snapshots__/avatar-token.test.tsx.snap similarity index 100% rename from ui/components/component-library/avatar-token/__snapshots__/avatar-token.test.js.snap rename to ui/components/component-library/avatar-token/__snapshots__/avatar-token.test.tsx.snap diff --git a/ui/components/component-library/avatar-token/avatar-token.constants.js b/ui/components/component-library/avatar-token/avatar-token.constants.js deleted file mode 100644 index b9d1e10a4..000000000 --- a/ui/components/component-library/avatar-token/avatar-token.constants.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Size } from '../../../helpers/constants/design-system'; - -export const AVATAR_TOKEN_SIZES = { - XS: Size.XS, - SM: Size.SM, - MD: Size.MD, - LG: Size.LG, - XL: Size.XL, -}; diff --git a/ui/components/component-library/avatar-token/avatar-token.js b/ui/components/component-library/avatar-token/avatar-token.js deleted file mode 100644 index 9cc951011..000000000 --- a/ui/components/component-library/avatar-token/avatar-token.js +++ /dev/null @@ -1,133 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import classnames from 'classnames'; -import PropTypes from 'prop-types'; -import Box from '../../ui/box/box'; -import { AvatarBase } from '../avatar-base'; -import { - Size, - DISPLAY, - AlignItems, - JustifyContent, - TextColor, - BorderColor, - BackgroundColor, -} from '../../../helpers/constants/design-system'; -import { AVATAR_TOKEN_SIZES } from './avatar-token.constants'; - -export const AvatarToken = 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 handleOnError = () => { - setShowFallback(true); - }; - - const fallbackString = name && name[0] ? name[0] : '?'; - - return ( - - {showFallback ? ( - fallbackString - ) : ( - <> - {showHalo && ( - - )} - {`${name} - - )} - - ); - }, -); - -AvatarToken.propTypes = { - /** - * The name accepts the string to render the first letter of the AvatarToken. This will be used as the fallback display if no image url is passed to the src - */ - 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 AvatarToken. - * Possible values could be SIZES.XS(16px), SIZES.SM(24px), SIZES.MD(32px), SIZES.LG(40px), SIZES.XL(48px) - * Defaults to SIZES.MD - */ - size: PropTypes.oneOf(Object.values(AVATAR_TOKEN_SIZES)), - /** - * The background color of the AvatarToken - * Defaults to Color.backgroundAlternative - */ - backgroundColor: PropTypes.oneOf(Object.values(BackgroundColor)), - /** - * The background color of the AvatarToken - * Defaults to Color.borderDefault - */ - borderColor: PropTypes.oneOf(Object.values(BorderColor)), - /** - * The color of the text inside the AvatarToken - * Defaults to Color.textDefault - */ - color: PropTypes.oneOf(Object.values(TextColor)), - /** - * Additional classNames to be added to the AvatarToken - */ - className: PropTypes.string, - /** - * AvatarToken also accepts all Box props including but not limited to - * className, as(change root element of HTML element) and margin props - */ - ...Box.propTypes, -}; - -AvatarToken.displayName = 'AvatarToken'; diff --git a/ui/components/component-library/avatar-token/avatar-token.stories.js b/ui/components/component-library/avatar-token/avatar-token.stories.tsx similarity index 71% rename from ui/components/component-library/avatar-token/avatar-token.stories.js rename to ui/components/component-library/avatar-token/avatar-token.stories.tsx index ed8cfc53b..12d94a170 100644 --- a/ui/components/component-library/avatar-token/avatar-token.stories.js +++ b/ui/components/component-library/avatar-token/avatar-token.stories.tsx @@ -1,32 +1,26 @@ import React from 'react'; +import { StoryFn, Meta } from '@storybook/react'; import { - Size, - DISPLAY, + Display, AlignItems, TextColor, BackgroundColor, BorderColor, } from '../../../helpers/constants/design-system'; - -import Box from '../../ui/box/box'; - import { AvatarNetwork, AvatarNetworkSize, - BUTTON_LINK_SIZES, BadgeWrapper, + Box, ButtonLink, + BUTTON_LINK_SIZES, Text, } from '..'; - import README from './README.mdx'; - -import { AvatarToken } from './avatar-token'; -import { AVATAR_TOKEN_SIZES } from './avatar-token.constants'; +import { AvatarToken, AvatarTokenSize } from '.'; export default { title: 'Components/ComponentLibrary/AvatarToken', - component: AvatarToken, parameters: { docs: { @@ -36,7 +30,7 @@ export default { argTypes: { size: { control: 'select', - options: Object.values(AVATAR_TOKEN_SIZES), + options: Object.values(AvatarTokenSize), }, color: { options: Object.values(TextColor), @@ -63,43 +57,43 @@ export default { args: { name: 'eth', src: './images/eth_logo.png', - size: Size.MD, + size: AvatarTokenSize.Md, showHalo: false, }, -}; +} as Meta; -const Template = (args) => { +const Template: StoryFn = (args) => { return ; }; export const DefaultStory = Template.bind({}); DefaultStory.storyName = 'Default'; -export const SizeStory = (args) => ( +export const SizeStory: StoryFn = (args) => ( <> - - - - - + + + + + - - - - - + + + + + Sizes with{' '} @@ -119,7 +113,7 @@ export const SizeStory = (args) => ( components ( src="./images/eth_logo.png" name="ETH" size={AvatarNetworkSize.Xs} - borderColor={BackgroundColor.backgroundDefault} + borderColor={BorderColor.backgroundDefault} borderWidth={2} /> } > - + ( src="./images/eth_logo.png" name="ETH" size={AvatarNetworkSize.Xs} - borderColor={BackgroundColor.backgroundDefault} + borderColor={BorderColor.backgroundDefault} borderWidth={2} /> } > - + ( src="./images/eth_logo.png" name="ETH" size={AvatarNetworkSize.Xs} - borderColor={BackgroundColor.backgroundDefault} + borderColor={BorderColor.backgroundDefault} borderWidth={2} /> } > - + ( src="./images/eth_logo.png" name="ETH" size={AvatarNetworkSize.Xs} - borderColor={BackgroundColor.backgroundDefault} + borderColor={BorderColor.backgroundDefault} borderWidth={2} /> } > - + ( src="./images/eth_logo.png" name="ETH" size={AvatarNetworkSize.Sm} - borderColor={BackgroundColor.backgroundDefault} + borderColor={BorderColor.backgroundDefault} borderWidth={2} /> } > - + - + } @@ -205,9 +199,9 @@ export const SizeStory = (args) => ( {...args} src="" name="ETH" - size={Size.XS} + size={AvatarTokenSize.Xs} borderColor={BorderColor.borderDefault} - borderSize={2} + borderWidth={2} /> ( } @@ -224,9 +218,9 @@ export const SizeStory = (args) => ( {...args} name="ETH" src="" - size={Size.SM} + size={AvatarTokenSize.Sm} borderColor={BorderColor.borderDefault} - borderSize={2} + borderWidth={2} /> ( } @@ -243,9 +237,9 @@ export const SizeStory = (args) => ( {...args} name="ETH" src="" - size={Size.MD} + size={AvatarTokenSize.Md} borderColor={BorderColor.borderDefault} - borderSize={2} + borderWidth={2} /> ( } @@ -262,9 +256,9 @@ export const SizeStory = (args) => ( {...args} name="ETH" src="" - size={Size.LG} + size={AvatarTokenSize.Lg} borderColor={BorderColor.borderDefault} - borderSize={2} + borderWidth={2} /> ( } @@ -281,9 +275,9 @@ export const SizeStory = (args) => ( {...args} name="ETH" src="" - size={Size.XL} + size={AvatarTokenSize.Xl} borderColor={BorderColor.borderDefault} - borderSize={2} + borderWidth={2} /> @@ -296,8 +290,8 @@ Name.args = { src: '', }; -export const Src = (args) => ( - +export const Src: StoryFn = (args) => ( + @@ -325,8 +319,10 @@ ShowHalo.args = { showHalo: true, }; -export const ColorBackgroundColorAndBorderColor = (args) => ( - +export const ColorBackgroundColorAndBorderColor: StoryFn = ( + args, +) => ( + { const args = { @@ -58,6 +56,53 @@ describe('AvatarToken', () => { ); expect(getByTestId('avatar-token')).toHaveClass('test-class'); }); + // size + it('should render with different AvatarTokenSize', () => { + const { getByTestId } = render( + <> + + + + + + , + ); + expect(getByTestId(AvatarTokenSize.Xs)).toHaveClass( + `mm-avatar-base--size-${AvatarTokenSize.Xs}`, + ); + expect(getByTestId(AvatarTokenSize.Sm)).toHaveClass( + `mm-avatar-base--size-${AvatarTokenSize.Sm}`, + ); + expect(getByTestId(AvatarTokenSize.Md)).toHaveClass( + `mm-avatar-base--size-${AvatarTokenSize.Md}`, + ); + expect(getByTestId(AvatarTokenSize.Lg)).toHaveClass( + `mm-avatar-base--size-${AvatarTokenSize.Lg}`, + ); + expect(getByTestId(AvatarTokenSize.Xl)).toHaveClass( + `mm-avatar-base--size-${AvatarTokenSize.Xl}`, + ); + }); // color it('should render with different colors', () => { const { getByTestId } = render( @@ -122,9 +167,11 @@ describe('AvatarToken', () => { ); }); it('should forward a ref to the root html element', () => { - const ref = React.createRef(); + const ref = React.createRef(); render(); expect(ref.current).not.toBeNull(); - expect(ref.current.nodeName).toBe('DIV'); + if (ref.current) { + expect(ref.current.nodeName).toBe('DIV'); + } }); }); diff --git a/ui/components/component-library/avatar-token/avatar-token.tsx b/ui/components/component-library/avatar-token/avatar-token.tsx new file mode 100644 index 000000000..bece3c2ae --- /dev/null +++ b/ui/components/component-library/avatar-token/avatar-token.tsx @@ -0,0 +1,90 @@ +import React, { useState, useEffect } from 'react'; +import classnames from 'classnames'; +import { AvatarBase, AvatarBaseProps } from '../avatar-base'; +import { + Display, + AlignItems, + JustifyContent, + TextColor, + BorderColor, + BackgroundColor, +} from '../../../helpers/constants/design-system'; +import type { PolymorphicRef } from '../box'; +import type { AvatarTokenComponent } from './avatar-token.types'; +import { AvatarTokenProps, AvatarTokenSize } from './avatar-token.types'; + +export const AvatarToken: AvatarTokenComponent = React.forwardRef( + ( + { + size = AvatarTokenSize.Md, + name, + src, + showHalo, + color = TextColor.textDefault, + backgroundColor = BackgroundColor.backgroundAlternative, + borderColor = BorderColor.transparent, + className = '', + ...props + }: AvatarTokenProps, + ref: PolymorphicRef, + ) => { + const [showFallback, setShowFallback] = useState(false); + + useEffect(() => { + setShowFallback(!src); + }, [src]); + + const handleOnError = () => { + setShowFallback(true); + }; + + const fallbackString = name?.[0] ?? '?'; + + return ( + ), + }} + > + {showFallback ? ( + fallbackString + ) : ( + <> + {showHalo && ( + + )} + {`${name} + + )} + + ); + }, +); diff --git a/ui/components/component-library/avatar-token/avatar-token.types.ts b/ui/components/component-library/avatar-token/avatar-token.types.ts new file mode 100644 index 000000000..c36c15b76 --- /dev/null +++ b/ui/components/component-library/avatar-token/avatar-token.types.ts @@ -0,0 +1,42 @@ +import type { PolymorphicComponentPropWithRef } from '../box'; +import type { AvatarBaseStyleUtilityProps } from '../avatar-base/avatar-base.types'; + +export enum AvatarTokenSize { + Xs = 'xs', + Sm = 'sm', + Md = 'md', + Lg = 'lg', + Xl = 'xl', +} + +/** + * Props for the AvatarToken component + */ +export interface AvatarTokenStyleUtilityProps + extends Omit { + /** + * The name accepts the string to render the first letter of the AvatarToken. This will be used as the fallback display if no image url is passed to the src + */ + 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 AvatarToken. + * Possible values could be 'AvatarTokenSize.Xs' 16px, 'AvatarTokenSize.Sm' 24px, 'AvatarTokenSize.Md' 32px, 'AvatarTokenSize.Lg' 40px, 'AvatarTokenSize.Xl' 48px + * Defaults to AvatarTokenSize.Md + */ + size?: AvatarTokenSize; +} + +export type AvatarTokenProps = + PolymorphicComponentPropWithRef; + +export type AvatarTokenComponent = ( + props: AvatarTokenProps, +) => React.ReactElement | null; diff --git a/ui/components/component-library/avatar-token/index.js b/ui/components/component-library/avatar-token/index.js deleted file mode 100644 index 17c1e649a..000000000 --- a/ui/components/component-library/avatar-token/index.js +++ /dev/null @@ -1 +0,0 @@ -export { AvatarToken } from './avatar-token'; diff --git a/ui/components/component-library/avatar-token/index.ts b/ui/components/component-library/avatar-token/index.ts new file mode 100644 index 000000000..4743bbbe9 --- /dev/null +++ b/ui/components/component-library/avatar-token/index.ts @@ -0,0 +1,3 @@ +export { AvatarToken } from './avatar-token'; +export { AvatarTokenSize } from './avatar-token.types'; +export type { AvatarTokenProps } from './avatar-token.types'; diff --git a/ui/components/component-library/index.js b/ui/components/component-library/index.js index 2a7ff7b85..d37a90c72 100644 --- a/ui/components/component-library/index.js +++ b/ui/components/component-library/index.js @@ -7,8 +7,8 @@ export { export { AvatarFavicon, AVATAR_FAVICON_SIZES } from './avatar-favicon'; export { AvatarIcon, AVATAR_ICON_SIZES } from './avatar-icon'; export { AvatarNetwork, AvatarNetworkSize } from './avatar-network'; -export { AvatarToken } from './avatar-token'; -export { AvatarBase } from './avatar-base'; +export { AvatarToken, AvatarTokenSize } from './avatar-token'; +export { AvatarBase, AvatarBaseSize } from './avatar-base'; export { BadgeWrapper, BadgeWrapperPosition,