Skip to content

Commit

Permalink
feat: Add Snap UI avatar component
Browse files Browse the repository at this point in the history
  • Loading branch information
FrederikBolding committed Oct 15, 2024
1 parent fd58460 commit 3557e63
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { SnapUICheckbox } from '../snaps/snap-ui-checkbox';
import { SnapUITooltip } from '../snaps/snap-ui-tooltip';
import { SnapUICard } from '../snaps/snap-ui-card';
import { SnapUIAddress } from '../snaps/snap-ui-address';
import { SnapUIAvatar } from '../snaps/snap-ui-avatar';
import { SnapUISelector } from '../snaps/snap-ui-selector';
import { SnapUIFooterButton } from '../snaps/snap-ui-footer-button';
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
Expand Down Expand Up @@ -106,6 +107,7 @@ export const safeComponentList = {
SnapUICard,
SnapUISelector,
SnapUIAddress,
SnapUIAvatar,
SnapUIFooterButton,
FormTextField,
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
Expand Down
36 changes: 13 additions & 23 deletions ui/components/app/snaps/snap-ui-address/snap-ui-address.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,35 @@ import {
Display,
TextColor,
} from '../../../../helpers/constants/design-system';
import BlockieIdenticon from '../../../ui/identicon/blockieIdenticon';
import Jazzicon from '../../../ui/jazzicon';
import { getUseBlockie } from '../../../../selectors';
import { shortenAddress } from '../../../../helpers/utils/util';
import { toChecksumHexAddress } from '../../../../../shared/modules/hexstring-utils';
import { SnapUIAvatar } from '../snap-ui-avatar';

export type SnapUIAddressProps = {
// The address must be a CAIP-10 string.
address: string;
diameter?: number;
// This is not currently exposed to Snaps.
avatarSize?: string;
};

export const SnapUIAddress: React.FunctionComponent<SnapUIAddressProps> = ({
address,
diameter = 32,
avatarSize = 'md',
}) => {
const parsed = useMemo(() => {
const caipIdentifier = useMemo(() => {
if (isHexString(address)) {
// For legacy address inputs we assume them to be Ethereum addresses.
// NOTE: This means the chain ID is not gonna be reliable.
return parseCaipAccountId(`eip155:1:${address}`);
return `eip155:1:${address}`;
}

return parseCaipAccountId(address as CaipAccountId);
return address;
}, [address]);
const useBlockie = useSelector(getUseBlockie);

const parsed = useMemo(
() => parseCaipAccountId(caipIdentifier as CaipAccountId),
[caipIdentifier],
);

// For EVM addresses, we make sure they are checksummed.
const transformedAddress =
Expand All @@ -47,20 +50,7 @@ export const SnapUIAddress: React.FunctionComponent<SnapUIAddressProps> = ({

return (
<Box display={Display.Flex} alignItems={AlignItems.center} gap={2}>
{useBlockie ? (
<BlockieIdenticon
address={parsed.address}
diameter={diameter}
borderRadius="50%"
/>
) : (
<Jazzicon
namespace={parsed.chain.namespace}
address={parsed.address}
diameter={diameter}
style={{ display: 'flex' }}
/>
)}
<SnapUIAvatar address={caipIdentifier} size={avatarSize} />
<Text color={TextColor.inherit}>{shortenedAddress}</Text>
</Box>
);
Expand Down
1 change: 1 addition & 0 deletions ui/components/app/snaps/snap-ui-avatar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './snap-ui-avatar';
44 changes: 44 additions & 0 deletions ui/components/app/snaps/snap-ui-avatar/snap-ui-avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { CaipAccountId, parseCaipAccountId } from '@metamask/utils';
import BlockieIdenticon from '../../../ui/identicon/blockieIdenticon';
import Jazzicon from '../../../ui/jazzicon';
import { getUseBlockie } from '../../../../selectors';

export const DIAMETERS: Record<string, number> = {
'xs': 16,
'sm': 24,
'md': 32,
'lg': 40,
};

export type SnapUIAvatarProps = {
// The address must be a CAIP-10 string.
address: string;
size?: string;
};

export const SnapUIAvatar: React.FunctionComponent<SnapUIAvatarProps> = ({
address,
size = 'md',
}) => {
const parsed = useMemo(() => {
return parseCaipAccountId(address as CaipAccountId);
}, [address]);
const useBlockie = useSelector(getUseBlockie);

return useBlockie ? (
<BlockieIdenticon
address={parsed.address}
diameter={DIAMETERS[size]}
borderRadius="50%"
/>
) : (
<Jazzicon
namespace={parsed.chain.namespace}
address={parsed.address}
diameter={DIAMETERS[size]}
style={{ display: 'flex' }}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ export const address: UIComponentFactory<AddressElement> = ({ element }) => ({
element: 'SnapUIAddress',
props: {
address: element.props.address,
diameter: 16,
avatarSize: 'xs',
},
});
9 changes: 9 additions & 0 deletions ui/components/app/snaps/snap-ui-renderer/components/avatar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AvatarElement } from '@metamask/snaps-sdk/jsx';
import { UIComponentFactory } from './types';

export const avatar: UIComponentFactory<AvatarElement> = ({ element }) => ({
element: 'SnapUIAvatar',
props: {
address: element.props.address,
},
});
2 changes: 2 additions & 0 deletions ui/components/app/snaps/snap-ui-renderer/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { container } from './container';
import { selector } from './selector';
import { icon } from './icon';
import { section } from './section';
import { avatar } from './avatar';

export const COMPONENT_MAPPING = {
Box: box,
Expand All @@ -38,6 +39,7 @@ export const COMPONENT_MAPPING = {
Copyable: copyable,
Row: row,
Address: address,
Avatar: avatar,
Button: button,
FileInput: fileInput,
Form: form,
Expand Down

0 comments on commit 3557e63

Please sign in to comment.