Skip to content
Merged
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@make-software/cspr-design",
"version": "2.0.1",
"version": "2.0.2",
"description": "React-based UI component library powering Casper Blockchain applications",
"homepage": "https://cspr.design",
"repository": "git://github.com/make-software/cspr-design",
Expand Down Expand Up @@ -37,7 +37,6 @@
"downshift": "^9.0.4",
"facepaint": "^1.2.1",
"i18next": "^25.3.2",
"prettier": "^3.6.2",
"react-inlinesvg": "^4.2.0",
"react-loading-skeleton": "^3.5.0",
"react-modal": "^3.16.1",
Expand Down Expand Up @@ -95,6 +94,7 @@
"@types/react-modal": "^3.16.3",
"@types/styled-components": "^5.1.34",
"@vitejs/plugin-react": "^4.7.0",
"prettier": "^3.6.2",
"babel-plugin-named-exports-order": "^0.0.2",
"eslint-plugin-storybook": "^9.0.18",
"remark-gfm": "^4.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default {
component: AccountInfoRow,
excludeStories: ['Primary'],
// tags: ['autodocs', '!dev'],
title: 'Components/Display/AccountInfoRow',
title: 'Components/Form/AccountInfoRow',
parameters: {
controls: {
sort: 'requiredFirst',
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/account-info-row/account-info-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function AccountInfoRow(props: AccountInfoRowProps) {
{publicKey && (
<>
<FlexRow align="center">
<Tooltip title={publicKey}>
<Tooltip tooltipContent={publicKey}>
<BodyText size={3} variation={'black'} monotype>
{formatHash(publicKey, responsiveHashSize)}
</BodyText>
Expand Down
49 changes: 49 additions & 0 deletions src/lib/components/address/address.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Meta } from '@storybook/react';
import { StoryObj } from '@storybook/react-vite';
import { Address } from './address.tsx';

const meta = {
component: Address,
title: 'Components/Display/Address',
// tags: ['autodocs', '!dev'],
args: {
hash: '01f5f1fa995ab7e966428e5a1aed797526ad5b2454c50a63a7aaa2dfeae6a996c2',
minifiedCopyNotification: true,
tooltipCaption: 'public key',
avatarSize: 'default',
},
argTypes: {
avatarSize: {
control: { type: 'select' },
options: ['default', 'big', 'average', 'medium', 'small'],
description: 'The size of the avatar',
},
hash: { control: 'text' },
csprName: { control: 'text' },
logo: { control: 'text' },
name: { control: 'text' },
tooltipCaption: { control: 'text' },
minifiedCopyNotification: { control: 'boolean' },
},
} as Meta<typeof Address>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Primary: Story = {};

export const withName: Story = {
args: {
name: 'Faucet',
csprName: 'faucet.cspr',
logo: 'https://cspr-image-proxy-cdn.dev.make.services/64,fit,ttl86400/https://casper-assets.s3.amazonaws.com/accounts/faucet.svg',
},
};

export const withLogo: Story = {
args: {
name: 'Casper Space DJ',
logo: 'https://image-proxy-cdn.make.services/64,fit,ttl86400/https://makegroup.io/wp-content/uploads/2024/04/logo.svg',
},
};
184 changes: 184 additions & 0 deletions src/lib/components/address/address.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import React from 'react';
import { Avatar, AvatarProps } from '../avatar/avatar';

import styled from 'styled-components';
import BodyText from '../body-text/body-text.tsx';
import Tooltip from '../tooltip/tooltip.tsx';
import { HashLink } from '../hash-link/hash-link.tsx';
import FlexRow from '../flex-row/flex-row.tsx';
import FlexColumn from '../flex-column/flex-column.tsx';
import { HashLength, shortenCsprName } from '../../utils/formatters.ts';
import { Size } from '../../types.ts';
import TruncateBox from '../truncate-box/truncate-box.tsx';

/**
* Address component can be used to display a public key or hash associated with an account.
* It supports various configurations, including loading state, logo, name, csprName, and tooltip.
*
* Properties:
* @property {boolean} loading - Specifies whether the address component is in a loading state.
* @property {string | null} logo - The logo associated with the address, if available.
* @property {string | undefined} name - The display name of the address.
* @property {string | undefined} [csprName] - The CSPR.name associated with the address, if applicable.
* @property {string | null | undefined} hash - The public key or hash associated with the address.
* @property {string} [tooltipCaption] - Text to be displayed in a tooltip for additional context.
* @property {string} [navigateToPath] - The path to navigate to when interacting with the address.
* @property {HashLength} [hashLength] - Specifies the length of the hash representation.
* @property {Size} [nameTruncateSize] - Defines the size of the name text.
* @property {AvatarProps['size']} [avatarSize] - The size of the avatar related to the address.
* @property {HashFontSize} [hashFontSize] - Specifies the font size to display the hash.
* @property {boolean} [minifiedCopyNotification] - Determines if the address component should be rendered in a minimized style.
* @property {keyof any} [navigationPath] - **@deprecated** Use `navigateToPath` instead.
* @property {'full' | 'tiny'} [copyNotifyingStyle] - **@deprecated** Use `minifiedCopyNotification` instead.
*/
interface AddressProps {
loading: boolean;
logo: string | null;
name: string | undefined;
hash: string | null | undefined;
csprName?: string | undefined;
tooltipCaption?: string;
additionalTooltipBlock?: React.ReactElement;
navigateToPath?: string;
hashLength?: HashLength;
nameTruncateSize?: Size;
avatarSize?: AvatarProps['size'];
hashFontSize?: HashFontSize;
minifiedCopyNotification?: boolean;
/** @deprecated use *navigateToPath* instead */
navigationPath?: keyof any;
/** @deprecated use *minifiedCopyNotification* instead */
copyNotifyingStyle?: 'full' | 'tiny';
}

const StyledTruncateBox = styled(TruncateBox)(() => ({
height: '20px',
}));

const StyledBodyText = styled(BodyText)(({ theme }) => ({
color: theme.styleguideColors.contentBlue,
'& > *': {
color: theme.styleguideColors.contentBlue,
},
'&:hover > *': {
color: theme.styleguideColors.fillPrimaryRed,
},
'&:active > *': {
color: theme.styleguideColors.fillPrimaryRedClick,
},
}));

export enum HashFontSize {
'default' = 'default',
'big' = 'big',
}

export const Address = ({
hash,
csprName,
logo,
name,
loading,
hashLength,
minifiedCopyNotification,
navigateToPath,
tooltipCaption,
additionalTooltipBlock,
nameTruncateSize = 5,
avatarSize = 'default',
hashFontSize = HashFontSize.default,
}: AddressProps) => {
if (loading || !hash) {
return (
<FlexRow align="center" itemsSpacing={12}>
<Avatar hash={hash} loading={loading} size={avatarSize} />
</FlexRow>
);
}

if (hash === '00') {
// hash == '00' means that it is a Immediate Switch Block
// NOTE: as part of Casper network node v1.5, the node software now creates an "immediate switch block" on upgrades;
// there are no rewards for this block. it simply captures the information after application of the upgrade,
// which allows this to be deterministically detected
return (
<FlexRow align="center" itemsSpacing={12}>
<Avatar hash={hash} loading={loading} size={avatarSize} />
<FlexColumn>
<BodyText size={2} monotype>
{hash}
</BodyText>
<BodyText size={3} variation="darkGray" noWrap>
System
</BodyText>
</FlexColumn>
</FlexRow>
);
}

return (
<FlexRow align="center" itemsSpacing={12}>
{logo ? (
<Avatar
src={logo}
loading={loading}
size={avatarSize}
alt={'Account logo'}
/>
) : (
<Avatar hash={hash} loading={loading} size={avatarSize} />
)}

<Tooltip
caption={tooltipCaption}
tooltipContent={hash}
additionalBlock={additionalTooltipBlock}
>
<FlexColumn>
{name ? (
<>
<StyledBodyText
size={3}
scale={hashFontSize === HashFontSize.big ? 'sm' : undefined}
monotype={!csprName}
>
<HashLink
minified={minifiedCopyNotification}
href={navigateToPath}
hash={hash}
csprName={
csprName && shortenCsprName(csprName, HashLength.TINY)
}
hashLength={hashLength}
/>
</StyledBodyText>
<FlexRow itemsSpacing={6} align={'center'}>
<StyledTruncateBox size={nameTruncateSize}>
<BodyText size={3} variation="darkGray" noWrap>
{name}
</BodyText>
</StyledTruncateBox>
</FlexRow>
</>
) : (
<StyledBodyText
size={3}
scale={hashFontSize === HashFontSize.big ? 'sm' : undefined}
monotype={!csprName}
>
<HashLink
href={navigateToPath}
hash={hash}
csprName={
csprName && shortenCsprName(csprName, HashLength.TINY)
}
hashLength={hashLength}
minified={minifiedCopyNotification}
/>
</StyledBodyText>
)}
</FlexColumn>
</Tooltip>
</FlexRow>
);
};
Loading