import Close from '@mui/icons-material/Close' import ContentCopyRounded from '@mui/icons-material/ContentCopyRounded' import OpenInNewRounded from '@mui/icons-material/OpenInNewRounded' import { Box, IconButton, Link, Skeleton, Typography } from '@mui/material' import { forwardRef, type PropsWithChildren, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useAvailableChains } from '../../hooks/useAvailableChains.js' import { useExplorer } from '../../hooks/useExplorer.js' import { useToken } from '../../hooks/useToken.js' import { shortenAddress } from '../../utils/wallet.js' import { TokenAvatar } from '../Avatar/TokenAvatar.js' import { CardIconButton } from '../Card/CardIconButton.js' import { Label, MetricContainer, TokenDetailsSheetContainer, TokenDetailsSheetHeader, } from './TokenDetailsSheetContent.style.js' import type { TokenDetailsSheetBase } from './types.js' interface TokenDetailsSheetContentProps { tokenAddress: string | undefined chainId: number | undefined withoutContractAddress: boolean } const noDataLabel = '-' export const TokenDetailsSheetContent = forwardRef< TokenDetailsSheetBase, TokenDetailsSheetContentProps >(({ tokenAddress, chainId, withoutContractAddress }, ref) => { const { t } = useTranslation() const { getAddressLink } = useExplorer() const { getChainById } = useAvailableChains() const { token, isLoading } = useToken(chainId, tokenAddress, true) const chain = useMemo(() => getChainById(chainId), [chainId, getChainById]) const copyContractAddress = async (e: React.MouseEvent) => { e.stopPropagation() try { // Clipboard API may throw if access is denied (e.g., in insecure contexts or older browsers) await navigator.clipboard.writeText(tokenAddress || '') } catch { // Silently fail to avoid crashing the UI if clipboard write fails } } return ( {isLoading ? ( <> ) : ( <> {token?.symbol || noDataLabel} )} { e.stopPropagation() if (ref && typeof ref !== 'function') { ref.current?.close() } }} sx={{ mt: '-8px', mr: '-8px' }} > {token?.priceUSD ? t('format.currency', { value: token.priceUSD, }) : noDataLabel} {!withoutContractAddress && ( {shortenAddress(tokenAddress)} {tokenAddress && ( )} {tokenAddress && ( e.stopPropagation()} > )} )} {token?.marketCapUSD ? t('format.currency', { value: token.marketCapUSD, notation: 'compact', compactDisplay: 'short', maximumFractionDigits: 2, }) : noDataLabel} {token?.volumeUSD24H ? t('format.currency', { value: token.volumeUSD24H, notation: 'compact', compactDisplay: 'short', maximumFractionDigits: 2, }) : noDataLabel} ) }) interface MetricWithSkeletonProps { label: string isLoading: boolean width: number height: number } const MetricWithSkeleton = ({ label, width, height, isLoading, children, }: PropsWithChildren) => { return ( {isLoading ? ( ) : ( children )} ) }