@lifi/widget
Version:
LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.
129 lines • 8.62 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { ChainType } from '@lifi/sdk';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import WarningRounded from '@mui/icons-material/WarningRounded';
import { Avatar, Box, ListItemAvatar, ListItemText, listItemSecondaryActionClasses, Skeleton, Slide, Tooltip, Typography, } from '@mui/material';
import { memo, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLongPress } from '../../hooks/useLongPress.js';
import { formatTokenAmount, formatTokenPrice } from '../../utils/format.js';
import { shortenAddress } from '../../utils/wallet.js';
import { TokenAvatar } from '../Avatar/TokenAvatar.js';
import { ListItemButton } from '../ListItem/ListItemButton.js';
import { IconButton, ListItem } from './TokenList.style.js';
export const TokenListItem = memo(({ onClick, size, start, token, chain, isBalanceLoading, startAdornment, endAdornment, selected, onShowTokenDetails, }) => {
return (_jsxs(ListItem, { style: {
height: `${size}px`,
transform: `translateY(${start}px)`,
padding: 0,
}, children: [startAdornment, _jsx(TokenListItemButton, { token: token, isBalanceLoading: isBalanceLoading, onClick: onClick, chain: chain, selected: selected, onShowTokenDetails: onShowTokenDetails }), endAdornment] }));
});
const TokenListItemAvatar = memo(({ token }) => {
const [isImageLoading, setIsImageLoading] = useState(true);
return (_jsx(Avatar, { src: token.logoURI, alt: token.symbol, sx: (theme) => isImageLoading ? { bgcolor: theme.vars.palette.grey[300] } : null, onLoad: () => setIsImageLoading(false), children: token.symbol?.[0] }));
});
const OpenTokenDetailsButton = ({ tokenAddress, withoutContractAddress, chainId, onClick, }) => {
if (!tokenAddress) {
return null;
}
return (_jsx(IconButton, { size: "small", onClick: (e) => {
e.stopPropagation();
e.currentTarget.blur(); // Remove focus to prevent accessibility issues when opening drawer
onClick(tokenAddress, withoutContractAddress, chainId);
}, children: _jsx(InfoOutlinedIcon, {}) }));
};
const TokenListItemButton = memo(({ onClick, token, chain, isBalanceLoading, selected, onShowTokenDetails, }) => {
const { t } = useTranslation();
const container = useRef(null);
const timeoutId = useRef(undefined);
const [showAddress, setShowAddress] = useState(false);
const withoutContractAddress = chain?.chainType === ChainType.UTXO;
const onMouseEnter = () => {
timeoutId.current = setTimeout(() => {
if (token.address) {
setShowAddress(true);
}
}, 350);
};
const onMouseLeave = () => {
clearTimeout(timeoutId.current);
if (showAddress) {
setShowAddress(false);
}
};
const handleClick = (e) => {
e.stopPropagation();
onClick?.(token.address, token.chainId);
};
const tokenAmount = useMemo(() => formatTokenAmount(token.amount, token.decimals), [token.amount, token.decimals]);
const tokenPrice = useMemo(() => formatTokenPrice(token.amount, token.priceUSD, token.decimals), [token.amount, token.priceUSD, token.decimals]);
const longPressEvents = useLongPress(() => onShowTokenDetails(token.address, withoutContractAddress, token.chainId));
return (_jsxs(ListItemButton, { onClick: handleClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, ...longPressEvents, dense: true, selected: selected, sx: {
height: 60,
marginBottom: '4px',
}, children: [_jsx(ListItemAvatar, { children: chain ? (_jsx(TokenAvatar, { token: token, chain: chain, tokenAvatarSize: 40, chainAvatarSize: 16 })) : (_jsx(TokenListItemAvatar, { token: token })) }), _jsx(ListItemText, { primary: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [token.symbol, !token.verified && (_jsx(Tooltip, { title: t('warning.message.unverifiedToken'), placement: "top", arrow: true, children: _jsx(WarningRounded, { sx: {
display: 'flex',
fontSize: 16,
color: 'warning.main',
cursor: 'help',
} }) }))] }), slotProps: {
secondary: {
component: 'div',
},
}, secondary: withoutContractAddress ? (_jsxs(Box, { ref: container, sx: {
height: 20,
display: 'flex',
}, children: [_jsx(Box, { sx: {
pt: 0.25,
}, children: token.name }), _jsx(Box, { sx: {
position: 'relative',
}, children: _jsx(Slide, { direction: "up", in: showAddress, container: container.current, style: {
position: 'absolute',
}, appear: false, mountOnEnter: true, children: _jsx(Box, { sx: {
display: 'flex',
}, children: _jsx(OpenTokenDetailsButton, { tokenAddress: token.address, withoutContractAddress: withoutContractAddress, chainId: token.chainId, onClick: onShowTokenDetails }) }) }) })] })) : (_jsxs(Box, { ref: container, sx: {
position: 'relative',
height: 20,
}, children: [_jsx(Slide, { direction: "down", in: !showAddress, container: container.current, style: {
position: 'absolute',
}, appear: false, children: _jsx(Box, { sx: {
pt: 0.25,
}, children: token.name }) }), _jsx(Slide, { direction: "up", in: showAddress, container: container.current, style: {
position: 'absolute',
}, appear: false, mountOnEnter: true, children: _jsxs(Box, { sx: {
display: 'flex',
}, children: [_jsx(Box, { sx: {
display: 'flex',
alignItems: 'center',
pt: 0.125,
}, children: shortenAddress(token.address) }), _jsx(OpenTokenDetailsButton, { tokenAddress: token.address, withoutContractAddress: withoutContractAddress, chainId: token.chainId, onClick: onShowTokenDetails })] }) })] })) }), isBalanceLoading ? (_jsx(TokenAmountSkeleton, {})) : (_jsxs(Box, { sx: { textAlign: 'right' }, children: [token.amount ? (_jsx(Typography, { noWrap: true, sx: {
fontWeight: 600,
}, title: tokenAmount, children: t('format.tokenAmount', {
value: tokenAmount,
}) })) : null, token.amount && token.priceUSD ? (_jsx(Typography, { "data-price": token.priceUSD, sx: {
fontWeight: 500,
fontSize: 12,
color: 'text.secondary',
}, children: t('format.currency', {
value: tokenPrice,
}) })) : null] }))] }));
});
export const TokenListItemSkeleton = () => {
return (_jsxs(ListItem, { secondaryAction: _jsx(TokenAmountSkeleton, {}), disablePadding: true, sx: (theme) => ({
position: 'relative',
flexDirection: 'row',
alignItems: 'center',
padding: 0,
[`& .${listItemSecondaryActionClasses.root}`]: {
right: theme.spacing(1.5),
},
}), children: [_jsx(ListItemAvatar, { children: _jsx(Skeleton, { variant: "circular", width: 40, height: 40, sx: { marginLeft: 1.5, marginRight: 2 } }) }), _jsx(ListItemText, { primary: _jsx(Skeleton, { variant: "text", width: 56, height: 24 }), secondary: _jsx(Skeleton, { variant: "text", width: 96, height: 16 }) })] }));
};
const TokenAmountSkeleton = () => {
return (_jsxs(Box, { sx: {
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
}, children: [_jsx(Skeleton, { variant: "text", width: 56, height: 24 }), _jsx(Skeleton, { variant: "text", width: 48, height: 16 })] }));
};
//# sourceMappingURL=TokenListItem.js.map