diff --git a/src/app/components/account/account-list-item-layout.tsx b/src/app/components/account/account-list-item-layout.tsx
index 5fde1bb6215..82cc25d2a59 100644
--- a/src/app/components/account/account-list-item-layout.tsx
+++ b/src/app/components/account/account-list-item-layout.tsx
@@ -1,58 +1,82 @@
+import { ComponentProps, ReactNode } from 'react';
+
import { SettingsSelectors } from '@tests/selectors/settings.selectors';
-import { Flex, HStack, Stack, StackProps, styled } from 'leather-styles/jsx';
+import { HStack } from 'leather-styles/jsx';
import { useViewportMinWidth } from '@app/common/hooks/use-media-query';
import { BulletSeparator } from '@app/ui/components/bullet-separator/bullet-separator';
import { CheckmarkIcon } from '@app/ui/components/icons/checkmark-icon';
+import { Item } from '@app/ui/components/items/item';
+import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
import { Spinner } from '@app/ui/components/spinner';
import { truncateMiddle } from '@app/ui/utils/truncate-middle';
-import { Flag } from '../layout/flag';
import { StacksAccountLoader } from '../loaders/stacks-account-loader';
import { BitcoinNativeSegwitAccountLoader } from './bitcoin-account-loader';
-interface AccountListItemLayoutProps extends StackProps {
- isLoading: boolean;
- isActive: boolean;
+interface AccountListItemLayoutProps extends ComponentProps<'div'> {
+ accountName: ReactNode;
+ avatar: ReactNode;
+ balanceLabel: ReactNode;
index: number;
- accountName: React.ReactNode;
- avatar: React.JSX.Element;
- balanceLabel: React.ReactNode;
+ isLoading: boolean;
+ isPressable?: boolean;
+ isSelected: boolean;
onSelectAccount(): void;
}
export function AccountListItemLayout(props: AccountListItemLayoutProps) {
const {
- index,
- isLoading,
- isActive,
accountName,
avatar,
balanceLabel,
+ index,
+ isLoading,
+ isPressable,
+ isSelected,
onSelectAccount,
- children = null,
- ...rest
} = props;
const isBreakpointSm = useViewportMinWidth('sm');
return (
-
-
-
-
-
- {accountName}
- {isActive && }
+
+
+ {accountName}
+ {isSelected && }
- {isLoading ? (
+ }
+ contentLeftBottom={
+
+
+
+ {account => (
+
+ {truncateMiddle(account.address, isBreakpointSm ? 4 : 3)}
+
+ )}
+
+
+ {signer => (
+
+ {truncateMiddle(signer.address, 5)}
+
+ )}
+
+
+
+ }
+ contentRightTop={
+ isLoading ? (
) : (
- balanceLabel
- )}
-
-
-
-
- {account => (
-
- {truncateMiddle(account.address, isBreakpointSm ? 4 : 3)}
-
- )}
-
-
-
- {signer => (
-
- {truncateMiddle(signer.address, 5)}
-
- )}
-
-
-
-
-
- {children}
-
+ {balanceLabel}
+ )
+ }
+ />
+
+
);
}
diff --git a/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx b/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx
index 227990cc93f..3838cd0a656 100644
--- a/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx
+++ b/src/app/components/bitcoin-transaction-item/bitcoin-transaction-item.tsx
@@ -1,8 +1,6 @@
import { useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
-import { BoxProps } from 'leather-styles/jsx';
-
import { BitcoinTx } from '@shared/models/transactions/bitcoin-transaction.model';
import { RouteUrls } from '@shared/route-urls';
@@ -15,7 +13,6 @@ import {
isBitcoinTxInbound,
} from '@app/common/transactions/bitcoin/utils';
import { openInNewTab } from '@app/common/utils/open-in-new-tab';
-import { usePressable } from '@app/components/item-hover';
import { IncreaseFeeButton } from '@app/components/stacks-transaction-item/increase-fee-button';
import { TransactionTitle } from '@app/components/transaction/transaction-title';
import {
@@ -34,11 +31,10 @@ import { InscriptionIcon } from './bitcoin-transaction-inscription-icon';
import { BitcoinTransactionStatus } from './bitcoin-transaction-status';
import { BitcoinTransactionValue } from './bitcoin-transaction-value';
-interface BitcoinTransactionItemProps extends BoxProps {
+interface BitcoinTransactionItemProps {
transaction: BitcoinTx;
}
-export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransactionItemProps) {
- const [component, bind, { isHovered }] = usePressable(true);
+export function BitcoinTransactionItem({ transaction }: BitcoinTransactionItemProps) {
const { pathname } = useLocation();
const navigate = useNavigate();
@@ -92,7 +88,6 @@ export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransact
const increaseFeeButton = (
@@ -101,6 +96,7 @@ export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransact
return (
}
txTitle={}
txValue={txValue}
- belowCaptionEl={increaseFeeButton}
- {...bind}
- {...rest}
- >
- {component}
-
+ />
);
}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx
index 5bd77800863..8652feb9670 100644
--- a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx
+++ b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list.tsx
@@ -3,11 +3,13 @@ import { useNavigate } from 'react-router-dom';
import { RouteUrls } from '@shared/route-urls';
import { noop } from '@shared/utils';
-import { Brc20TokenAssetItem } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/btc-native-segwit-balance.hooks';
import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
+import { Brc20TokenAssetItemLayout } from './components/brc20-token-asset-item.layout';
+import { Brc20AssetListLayout } from './components/brc20-token-asset-list.layout';
+
export function Brc20TokenAssetList(props: { brc20Tokens?: Brc20Token[] }) {
const navigate = useNavigate();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
@@ -24,13 +26,18 @@ export function Brc20TokenAssetList(props: { brc20Tokens?: Brc20Token[] }) {
}
if (!props.brc20Tokens?.length) return null;
- return props.brc20Tokens.map(token => (
- navigateToBrc20SendForm(token) : noop}
- displayNotEnoughBalance={!hasPositiveBtcBalanceForFees}
- key={token.tick}
- />
- ));
+
+ return (
+
+ {props.brc20Tokens?.map(token => (
+ navigateToBrc20SendForm(token) : noop}
+ />
+ ))}
+
+ );
}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx
index 0e9223ec493..750b729abc4 100644
--- a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx
+++ b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout.tsx
@@ -1,69 +1,52 @@
-import { BoxProps, Flex, HStack, styled } from 'leather-styles/jsx';
-
-import type { Money } from '@shared/models/money.model';
+import { createMoney } from '@shared/models/money.model';
import { formatBalance } from '@app/common/format-balance';
-import { AssetCaption } from '@app/components/crypto-assets/components/asset-caption';
-import { usePressable } from '@app/components/item-hover';
-import { Flag } from '@app/components/layout/flag';
+import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
import { Brc20TokenIcon } from '@app/ui/components/icons/brc20-token-icon';
+import { Item } from '@app/ui/components/items/item';
+import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';
-interface Brc20TokenAssetItemLayoutProps extends BoxProps {
- balance: Money;
- caption: string;
+interface Brc20TokenAssetItemLayoutProps {
+ token: Brc20Token;
isPressable?: boolean;
onClick?(): void;
- title: string;
displayNotEnoughBalance?: boolean;
}
export function Brc20TokenAssetItemLayout({
- balance,
- caption,
isPressable,
onClick,
- title,
displayNotEnoughBalance,
+ token,
}: Brc20TokenAssetItemLayoutProps) {
- const [component, bind] = usePressable(isPressable);
-
+ const balance = createMoney(Number(token.overall_balance), token.tick, 0);
const formattedBalance = formatBalance(balance.amount.toString());
return (
-
- } spacing="space.04" width="100%">
-
-
- {title}
-
-
-
- {formattedBalance.value}
-
-
-
-
-
-
- {component}
-
-
+
+
+ }
+ contentLeftTop={{token.tick}}
+ contentLeftBottom={{'BRC-20'}}
+ contentRightTop={
+
+ {formattedBalance.value}
+
+ }
+ />
+
+
);
}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.tsx
deleted file mode 100644
index 29820b11099..00000000000
--- a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { createMoney } from '@shared/models/money.model';
-
-import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
-
-import { Brc20TokenAssetItemLayout } from './brc20-token-asset-item.layout';
-
-interface Brc20TokenAssetItemProps {
- token: Brc20Token;
- isPressable?: boolean;
- onClick?(): void;
- displayNotEnoughBalance?: boolean;
-}
-export function Brc20TokenAssetItem({
- token,
- isPressable,
- onClick,
- displayNotEnoughBalance,
-}: Brc20TokenAssetItemProps) {
- return (
-
- );
-}
diff --git a/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-list.layout.tsx b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-list.layout.tsx
new file mode 100644
index 00000000000..41ea4db9c38
--- /dev/null
+++ b/src/app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-list.layout.tsx
@@ -0,0 +1,10 @@
+import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors';
+import { Stack, StackProps } from 'leather-styles/jsx';
+
+export function Brc20AssetListLayout({ children }: StackProps) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list-item.tsx b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list-item.tsx
index e98f899f166..81eb70a1ecc 100644
--- a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list-item.tsx
+++ b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list-item.tsx
@@ -1,7 +1,6 @@
import type { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-asset-balance.model';
-import { CryptoCurrencyAssetItem } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item';
-
+import { CryptoCurrencyAssetItemLayout } from '../crypto-currency-asset/crypto-currency-asset-item.layout';
import { CryptoCurrencyAssetIcon } from './crypto-currency-asset-icon';
import { FungibleTokenAssetItem } from './fungible-token-asset-item';
@@ -16,7 +15,7 @@ export function CryptoAssetListItem(props: CryptoAssetListItemProps) {
switch (type) {
case 'crypto-currency':
return (
- }
isPressable
diff --git a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx
index e1803d73421..c5c9418347b 100644
--- a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx
+++ b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.layout.tsx
@@ -3,12 +3,7 @@ import { Stack, StackProps } from 'leather-styles/jsx';
export function CryptoAssetListLayout({ children }: StackProps) {
return (
-
+
{children}
);
diff --git a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx
index fd1fb2f0e0f..d40c64ede1f 100644
--- a/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx
+++ b/src/app/components/crypto-assets/choose-crypto-asset/crypto-asset-list.tsx
@@ -8,7 +8,7 @@ import { Brc20TokensLoader } from '@app/components/brc20-tokens-loader';
import { Brc20TokenAssetList } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/brc20-token-asset-list';
import { BtcIcon } from '@app/ui/components/icons/btc-icon';
-import { CryptoCurrencyAssetItem } from '../crypto-currency-asset/crypto-currency-asset-item';
+import { CryptoCurrencyAssetItemLayout } from '../crypto-currency-asset/crypto-currency-asset-item.layout';
import { CryptoAssetListItem } from './crypto-asset-list-item';
import { CryptoAssetListLayout } from './crypto-asset-list.layout';
@@ -25,7 +25,7 @@ export function CryptoAssetList({ cryptoAssetBalances, onItemClick }: CryptoAsse
{signer => (
{balance => (
- }
onClick={() => onItemClick(balance)}
diff --git a/src/app/components/crypto-assets/choose-crypto-asset/fungible-token-asset-item.tsx b/src/app/components/crypto-assets/choose-crypto-asset/fungible-token-asset-item.tsx
index 0ce6b98c4ff..8d7389ea14f 100644
--- a/src/app/components/crypto-assets/choose-crypto-asset/fungible-token-asset-item.tsx
+++ b/src/app/components/crypto-assets/choose-crypto-asset/fungible-token-asset-item.tsx
@@ -2,7 +2,7 @@ import { FlexProps } from 'leather-styles/jsx';
import type { StacksFungibleTokenAssetBalance } from '@shared/models/crypto-asset-balance.model';
-import { StacksFungibleTokenAssetItem } from '@app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item';
+import { StacksFungibleTokenAssetItemLayout } from '../stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout';
interface FungibleTokenAssetItemProps extends FlexProps {
assetBalance: StacksFungibleTokenAssetBalance;
@@ -14,7 +14,11 @@ export function FungibleTokenAssetItem({ assetBalance, onClick }: FungibleTokenA
switch (blockchain) {
case 'stacks':
return (
-
+
);
default:
return null;
diff --git a/src/app/components/crypto-assets/components/asset-caption.tsx b/src/app/components/crypto-assets/components/asset-caption.tsx
deleted file mode 100644
index 36dd07d71d4..00000000000
--- a/src/app/components/crypto-assets/components/asset-caption.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { Flex, styled } from 'leather-styles/jsx';
-
-interface AssetCaptionProps {
- caption: string;
-}
-export function AssetCaption({ caption }: AssetCaptionProps) {
- return (
-
- {caption}{' '}
-
- );
-}
diff --git a/src/app/components/crypto-assets/components/asset-row-grid.tsx b/src/app/components/crypto-assets/components/asset-row-grid.tsx
deleted file mode 100644
index 3508934ab32..00000000000
--- a/src/app/components/crypto-assets/components/asset-row-grid.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Grid, GridItem } from 'leather-styles/jsx';
-
-interface AssetRowGridProps {
- title: React.ReactNode;
- balance: React.ReactNode;
- caption: React.ReactNode;
- usdBalance?: React.ReactNode;
- rightElement?: React.ReactNode;
-}
-export function AssetRowGrid({
- title,
- balance,
- caption,
- usdBalance,
- rightElement,
-}: AssetRowGridProps) {
- const balanceItem = rightElement ? (
-
- {rightElement}
-
- ) : (
- {balance}
- );
- return (
-
-
- {title}
-
- {balanceItem}
- {caption}
- {usdBalance && {usdBalance}}
-
- );
-}
diff --git a/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx b/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx
index bf4a65215d5..d5ff281458e 100644
--- a/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx
+++ b/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout.tsx
@@ -1,103 +1,73 @@
-import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors';
-import { Flex, styled } from 'leather-styles/jsx';
+import { ReactNode } from 'react';
-import { CryptoCurrencies } from '@shared/models/currencies.model';
-import { Money } from '@shared/models/money.model';
+import { AllCryptoCurrencyAssetBalances } from '@shared/models/crypto-asset-balance.model';
-import { formatBalance } from '@app/common/format-balance';
-import { ftDecimals } from '@app/common/stacks-utils';
-import { usePressable } from '@app/components/item-hover';
-import { Flag } from '@app/components/layout/flag';
+import { Item } from '@app/ui/components/items/item';
+import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';
-import { truncateMiddle } from '@app/ui/utils/truncate-middle';
-import { AssetRowGrid } from '../components/asset-row-grid';
+import { parseCryptoCurrencyAssetBalance } from './crypto-currency-asset.utils';
interface CryptoCurrencyAssetItemLayoutProps {
- balance: Money;
- caption: string;
+ additionalBalanceInfo?: ReactNode;
+ additionalUsdBalanceInfo?: ReactNode;
+ address?: string;
+ assetBalance: AllCryptoCurrencyAssetBalances;
icon: React.ReactNode;
- copyIcon?: React.ReactNode;
isPressable?: boolean;
- title: string;
- usdBalance?: string;
- address?: string;
- isHovered?: boolean;
- currency?: CryptoCurrencies;
- additionalBalanceInfo?: React.ReactNode;
- additionalUsdBalanceInfo?: React.ReactNode;
- rightElement?: React.ReactNode;
onClick?(): void;
+ rightElement?: React.ReactNode;
+ usdBalance?: string;
}
export function CryptoCurrencyAssetItemLayout({
- balance,
- caption,
- icon,
- copyIcon,
- isPressable,
- title,
- usdBalance,
- address = '',
- isHovered = false,
additionalBalanceInfo,
additionalUsdBalanceInfo,
- rightElement,
+ address = '',
+ assetBalance,
+ icon,
+ isPressable,
onClick,
+ rightElement,
+ usdBalance,
}: CryptoCurrencyAssetItemLayoutProps) {
- const [component, bind] = usePressable(isPressable);
-
- const amount = balance.decimals
- ? ftDecimals(balance.amount, balance.decimals)
- : balance.amount.toString();
- const dataTestId = CryptoAssetSelectors.CryptoAssetListItem.replace(
- '{symbol}',
- balance.symbol.toLowerCase()
- );
- const formattedBalance = formatBalance(amount);
+ const { balance, dataTestId, formattedBalance, title } =
+ parseCryptoCurrencyAssetBalance(assetBalance);
return (
-
-
-
- {isHovered ? truncateMiddle(address, 6) : title}
-
- }
- balance={
-
-
- {formattedBalance.value} {additionalBalanceInfo}
-
-
- }
- caption={
-
- {caption}
-
+
+
+ {title}}
+ contentLeftBottom={{balance.symbol}}
+ contentRightTop={
+ rightElement ? (
+ rightElement
+ ) : (
+
+
+ {formattedBalance.value} {additionalBalanceInfo}
+
+
+ )
}
- usdBalance={
-
- {balance.amount.toNumber() > 0 && address ? (
-
- {usdBalance}
-
- ) : null}
- {additionalUsdBalanceInfo}
-
+ contentRightBottom={
+ !rightElement && (
+ <>
+ {balance.amount.toNumber() > 0 && address ? (
+ {usdBalance}
+ ) : null}
+ {additionalUsdBalanceInfo}
+ >
+ )
}
- rightElement={rightElement}
/>
-
- {component}
-
+
+
);
}
diff --git a/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.tsx b/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.tsx
deleted file mode 100644
index bddbae243ac..00000000000
--- a/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import type { AllCryptoCurrencyAssetBalances } from '@shared/models/crypto-asset-balance.model';
-
-import { spamFilter } from '@app/common/utils/spam-filter';
-
-import { CryptoCurrencyAssetItemLayout } from './crypto-currency-asset-item.layout';
-
-interface CryptoCurrencyAssetItemProps {
- assetBalance: AllCryptoCurrencyAssetBalances;
- icon: React.ReactNode;
- usdBalance?: string;
- address?: string;
- isPressable?: boolean;
- additionalBalanceInfo?: React.ReactNode;
- additionalUsdBalanceInfo?: React.ReactNode;
- rightElement?: React.ReactNode;
- onClick?(): void;
-}
-export function CryptoCurrencyAssetItem({
- additionalBalanceInfo,
- additionalUsdBalanceInfo,
- address,
- assetBalance,
- icon,
- isPressable,
- onClick,
- rightElement,
- usdBalance,
-}: CryptoCurrencyAssetItemProps) {
- const { balance, asset } = assetBalance;
-
- return (
-
- );
-}
diff --git a/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset.utils.ts b/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset.utils.ts
new file mode 100644
index 00000000000..041ca288ea5
--- /dev/null
+++ b/src/app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset.utils.ts
@@ -0,0 +1,28 @@
+import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors';
+
+import { AllCryptoCurrencyAssetBalances } from '@shared/models/crypto-asset-balance.model';
+
+import { formatBalance } from '@app/common/format-balance';
+import { ftDecimals } from '@app/common/stacks-utils';
+import { spamFilter } from '@app/common/utils/spam-filter';
+
+export function parseCryptoCurrencyAssetBalance(assetBalance: AllCryptoCurrencyAssetBalances) {
+ const { asset, balance } = assetBalance;
+
+ const amount = balance.decimals
+ ? ftDecimals(balance.amount, balance.decimals)
+ : balance.amount.toString();
+ const dataTestId = CryptoAssetSelectors.CryptoAssetListItem.replace(
+ '{symbol}',
+ balance.symbol.toLowerCase()
+ );
+ const formattedBalance = formatBalance(amount);
+ const title = spamFilter(asset.name);
+
+ return {
+ balance,
+ dataTestId,
+ formattedBalance,
+ title,
+ };
+}
diff --git a/src/app/components/crypto-assets/stacks/components/stacks-asset-avatar.tsx b/src/app/components/crypto-assets/stacks/components/stacks-asset-avatar.tsx
index f731aea9a1f..08d771dd2d1 100644
--- a/src/app/components/crypto-assets/stacks/components/stacks-asset-avatar.tsx
+++ b/src/app/components/crypto-assets/stacks/components/stacks-asset-avatar.tsx
@@ -15,7 +15,7 @@ export function StacksAssetAvatar({
gradientString,
imageCanonicalUri,
isStx,
- size = '36',
+ size = '40',
...props
}: StacksAssetAvatarProps) {
if (isStx) return ;
diff --git a/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.tsx b/src/app/components/crypto-assets/stacks/fungible-token-asset/fungible-token-asset.utils.ts
similarity index 58%
rename from src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.tsx
rename to src/app/components/crypto-assets/stacks/fungible-token-asset/fungible-token-asset.utils.ts
index 62c76e02d1c..06336273364 100644
--- a/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.tsx
+++ b/src/app/components/crypto-assets/stacks/fungible-token-asset/fungible-token-asset.utils.ts
@@ -1,46 +1,41 @@
import { CryptoAssetSelectors } from '@tests/selectors/crypto-asset.selectors';
-import { FlexProps } from 'leather-styles/jsx';
import type { StacksFungibleTokenAssetBalance } from '@shared/models/crypto-asset-balance.model';
import { getImageCanonicalUri } from '@app/common/crypto-assets/stacks-crypto-asset.utils';
+import { formatBalance } from '@app/common/format-balance';
+import { ftDecimals } from '@app/common/stacks-utils';
import { formatContractId, getTicker } from '@app/common/utils';
import { spamFilter } from '@app/common/utils/spam-filter';
import { getAssetName } from '@app/ui/utils/get-asset-name';
-import { StacksFungibleTokenAssetItemLayout } from './stacks-fungible-token-asset-item.layout';
-
-interface StacksFungibleTokenAssetItemProps extends FlexProps {
- assetBalance: StacksFungibleTokenAssetBalance;
- isPressable?: boolean;
- onClick?(): void;
-}
-export function StacksFungibleTokenAssetItem({
- assetBalance,
- isPressable,
- onClick,
-}: StacksFungibleTokenAssetItemProps) {
+export function parseStacksFungibleTokenAssetBalance(
+ assetBalance: StacksFungibleTokenAssetBalance
+) {
const { asset, balance } = assetBalance;
const { contractAddress, contractAssetName, contractName, name, symbol } = asset;
+ const amount = balance.decimals
+ ? ftDecimals(balance.amount, balance.decimals || 0)
+ : balance.amount.toString();
const avatar = `${formatContractId(contractAddress, contractName)}::${contractAssetName}`;
const dataTestId =
symbol && CryptoAssetSelectors.CryptoAssetListItem.replace('{symbol}', symbol.toLowerCase());
+ const formattedBalance = formatBalance(amount);
const friendlyName =
name ||
(contractAssetName.includes('::') ? getAssetName(contractAssetName) : contractAssetName);
const imageCanonicalUri = getImageCanonicalUri(asset.imageCanonicalUri, asset.name);
const caption = symbol || getTicker(friendlyName);
- return (
-
- );
+ const title = spamFilter(friendlyName);
+
+ return {
+ amount,
+ avatar,
+ caption,
+ dataTestId,
+ formattedBalance,
+ imageCanonicalUri,
+ title,
+ };
}
diff --git a/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx b/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx
index a259f6fbf0b..d47bb580151 100644
--- a/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx
+++ b/src/app/components/crypto-assets/stacks/fungible-token-asset/stacks-fungible-token-asset-item.layout.tsx
@@ -1,71 +1,52 @@
-import { Flex, FlexProps, styled } from 'leather-styles/jsx';
+import { StacksFungibleTokenAssetBalance } from '@shared/models/crypto-asset-balance.model';
-import type { Money } from '@shared/models/money.model';
-
-import { formatBalance } from '@app/common/format-balance';
-import { ftDecimals } from '@app/common/stacks-utils';
import { StacksAssetAvatar } from '@app/components/crypto-assets/stacks/components/stacks-asset-avatar';
-import { usePressable } from '@app/components/item-hover';
-import { Flag } from '@app/components/layout/flag';
+import { Item } from '@app/ui/components/items/item';
+import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
import { BasicTooltip } from '@app/ui/components/tooltip/basic-tooltip';
-import { AssetCaption } from '../../components/asset-caption';
-import { AssetRowGrid } from '../../components/asset-row-grid';
+import { parseStacksFungibleTokenAssetBalance } from './fungible-token-asset.utils';
-interface StacksFungibleTokenAssetItemLayoutProps extends FlexProps {
- avatar: string;
- balance: Money;
- caption: string;
- imageCanonicalUri?: string;
+interface StacksFungibleTokenAssetItemLayoutProps {
+ assetBalance: StacksFungibleTokenAssetBalance;
isPressable?: boolean;
- title: string;
onClick?(): void;
}
export function StacksFungibleTokenAssetItemLayout({
- avatar,
- balance,
- caption,
- imageCanonicalUri,
+ assetBalance,
isPressable,
- title,
onClick,
}: StacksFungibleTokenAssetItemLayoutProps) {
- const [component, bind] = usePressable(isPressable);
-
- const amount = balance.decimals
- ? ftDecimals(balance.amount, balance.decimals || 0)
- : balance.amount.toString();
- const formattedBalance = formatBalance(amount);
+ const { amount, avatar, caption, dataTestId, formattedBalance, imageCanonicalUri, title } =
+ parseStacksFungibleTokenAssetBalance(assetBalance);
return (
-
-
- {title[0]}
-
- }
- spacing="space.04"
- width="100%"
- >
- {title}}
- balance={
-
-
- {formattedBalance.value}
-
+
+
+
+ {title[0]}
+
+ }
+ contentLeftTop={{title}}
+ contentLeftBottom={{caption}}
+ contentRightTop={
+
+ {formattedBalance.value}
}
- caption={}
/>
- {component}
-
-
+
+
);
}
diff --git a/src/app/components/stacks-transaction-item/increase-fee-button.tsx b/src/app/components/stacks-transaction-item/increase-fee-button.tsx
index 7cb383c8fef..cf924f4e988 100644
--- a/src/app/components/stacks-transaction-item/increase-fee-button.tsx
+++ b/src/app/components/stacks-transaction-item/increase-fee-button.tsx
@@ -4,13 +4,12 @@ import { ChevronsRightIcon } from '@app/ui/components/icons/chevrons-right-icon'
interface IncreaseFeeButtonProps {
isEnabled?: boolean;
- isHovered: boolean;
isSelected: boolean;
onIncreaseFee(): void;
}
export function IncreaseFeeButton(props: IncreaseFeeButtonProps) {
- const { isEnabled, isHovered, isSelected, onIncreaseFee } = props;
- const isActive = isEnabled && isHovered && !isSelected;
+ const { isEnabled, isSelected, onIncreaseFee } = props;
+ const isActive = isEnabled && !isSelected;
return (
@@ -99,16 +95,12 @@ export function StacksTransactionItem({
return (
}
txValue={txValue}
- belowCaptionEl={increaseFeeButton}
- {...bind}
- {...rest}
- >
- {component}
-
+ />
);
}
diff --git a/src/app/components/transaction-item/transaction-item.layout.tsx b/src/app/components/transaction-item/transaction-item.layout.tsx
index bb961b93108..4248f843e04 100644
--- a/src/app/components/transaction-item/transaction-item.layout.tsx
+++ b/src/app/components/transaction-item/transaction-item.layout.tsx
@@ -1,49 +1,43 @@
import { ReactNode } from 'react';
-import { Box, Flex, HStack } from 'leather-styles/jsx';
+import { Item } from '@app/ui/components/items/item';
+import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
interface TransactionItemLayoutProps {
openTxLink(): void;
+ rightElement?: ReactNode;
txCaption: ReactNode;
txTitle: ReactNode;
txValue: ReactNode;
txIcon?: ReactNode;
txStatus?: ReactNode;
- belowCaptionEl?: ReactNode;
children?: ReactNode;
}
export function TransactionItemLayout({
openTxLink,
+ rightElement,
txCaption,
txIcon,
txStatus,
txTitle,
txValue,
- belowCaptionEl,
- children,
- ...rest
}: TransactionItemLayoutProps) {
return (
-
-
- {txIcon && txIcon}
-
-
- {txTitle} {txValue}
-
-
- {txCaption} {txStatus && txStatus}
- {belowCaptionEl ? belowCaptionEl : null}
-
-
-
- {children}
-
+
+
+ {txTitle}}
+ contentLeftBottom={
+ <>
+ {txCaption}
+ {txStatus && txStatus}
+ >
+ }
+ contentRightTop={rightElement ? rightElement : {txValue}}
+ />
+
+
);
}
diff --git a/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.layout.tsx b/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.layout.tsx
index 3d2fb787563..44acfa0e297 100644
--- a/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.layout.tsx
+++ b/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.layout.tsx
@@ -11,7 +11,7 @@ export function PendingTransactionListLayout({ children }: PendingTransactionLis
Pending
-
+
{children}
>
diff --git a/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.tsx b/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.tsx
index 6fa22d355a1..2fe58970c23 100644
--- a/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.tsx
+++ b/src/app/features/activity-list/components/pending-transaction-list/pending-transaction-list.tsx
@@ -2,9 +2,9 @@ import { MempoolTransaction } from '@stacks/stacks-blockchain-api-types';
import { BitcoinTx } from '@shared/models/transactions/bitcoin-transaction.model';
+import { BitcoinTransactionItem } from '@app/components/bitcoin-transaction-item/bitcoin-transaction-item';
import { StacksTransactionItem } from '@app/components/stacks-transaction-item/stacks-transaction-item';
-import { BitcoinTransactionItem } from '../../../../components/bitcoin-transaction-item/bitcoin-transaction-item';
import { PendingTransactionListLayout } from './pending-transaction-list.layout';
interface PendingTransactionListProps {
diff --git a/src/app/features/activity-list/components/transaction-list/transaction-list.layout.tsx b/src/app/features/activity-list/components/transaction-list/transaction-list.layout.tsx
index eed16bebc44..7d3f7c2e50a 100644
--- a/src/app/features/activity-list/components/transaction-list/transaction-list.layout.tsx
+++ b/src/app/features/activity-list/components/transaction-list/transaction-list.layout.tsx
@@ -6,9 +6,5 @@ interface TransactionListLayoutProps {
children: ReactNode;
}
export function TransactionListLayout({ children }: TransactionListLayoutProps) {
- return (
-
- {children}
-
- );
+ return {children};
}
diff --git a/src/app/features/activity-list/components/transaction-list/transactions-by-date.layout.tsx b/src/app/features/activity-list/components/transaction-list/transactions-by-date.layout.tsx
index 117d795d447..f9b3bde1d8d 100644
--- a/src/app/features/activity-list/components/transaction-list/transactions-by-date.layout.tsx
+++ b/src/app/features/activity-list/components/transaction-list/transactions-by-date.layout.tsx
@@ -17,9 +17,7 @@ export function TransactionsByDateLayout({
{displayDate}
-
- {children}
-
+ {children}
);
}
diff --git a/src/app/features/asset-list/asset-list.tsx b/src/app/features/asset-list/asset-list.tsx
index d6703e2c534..096f86f20b0 100644
--- a/src/app/features/asset-list/asset-list.tsx
+++ b/src/app/features/asset-list/asset-list.tsx
@@ -7,7 +7,7 @@ import { useBtcAssetBalance } from '@app/common/hooks/balance/btc/use-btc-balanc
import { useWalletType } from '@app/common/use-wallet-type';
import { BitcoinContractEntryPoint } from '@app/components/bitcoin-contract-entry-point/bitcoin-contract-entry-point';
import { Brc20TokensLoader } from '@app/components/brc20-tokens-loader';
-import { CryptoCurrencyAssetItem } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item';
+import { CryptoCurrencyAssetItemLayout } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout';
import { CurrentStacksAccountLoader } from '@app/components/loaders/stacks-account-loader';
import { useHasBitcoinLedgerKeychain } from '@app/store/accounts/blockchain/bitcoin/bitcoin.ledger';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
@@ -31,10 +31,10 @@ export function AssetsList() {
const { whenWallet } = useWalletType();
return (
-
+
{whenWallet({
software: (
- }
@@ -42,7 +42,7 @@ export function AssetsList() {
/>
),
ledger: (
- }
diff --git a/src/app/features/asset-list/components/add-stacks-ledger-keys-item.tsx b/src/app/features/asset-list/components/add-stacks-ledger-keys-item.tsx
index a09c669a03f..ff0f0ed281a 100644
--- a/src/app/features/asset-list/components/add-stacks-ledger-keys-item.tsx
+++ b/src/app/features/asset-list/components/add-stacks-ledger-keys-item.tsx
@@ -1,6 +1,6 @@
import BigNumber from 'bignumber.js';
-import { CryptoCurrencyAssetItem } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item';
+import { CryptoCurrencyAssetItemLayout } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout';
import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar';
import { createStacksCryptoCurrencyAssetTypeWrapper } from '@app/query/stacks/balance/stacks-ft-balances.utils';
@@ -8,7 +8,7 @@ import { ConnectLedgerAssetBtn } from './connect-ledger-asset-button';
export function AddStacksLedgerKeysItem() {
return (
- }
rightElement={}
diff --git a/src/app/features/asset-list/components/bitcoin-fungible-tokens-asset-list.tsx b/src/app/features/asset-list/components/bitcoin-fungible-tokens-asset-list.tsx
index c8ce70ef4b9..e71915b3ee3 100644
--- a/src/app/features/asset-list/components/bitcoin-fungible-tokens-asset-list.tsx
+++ b/src/app/features/asset-list/components/bitcoin-fungible-tokens-asset-list.tsx
@@ -1,6 +1,6 @@
import { Stack } from 'leather-styles/jsx';
-import { Brc20TokenAssetItem } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item';
+import { Brc20TokenAssetItemLayout } from '@app/components/crypto-assets/bitcoin/brc20-token-asset-list/components/brc20-token-asset-item.layout';
import { Brc20Token } from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';
interface BitcoinFungibleTokenAssetListProps {
@@ -12,7 +12,7 @@ export function BitcoinFungibleTokenAssetList({ brc20Tokens }: BitcoinFungibleTo
return (
{brc20Tokens.map(token => (
-
+
))}
);
diff --git a/src/app/features/asset-list/components/stacks-asset-list.tsx b/src/app/features/asset-list/components/stacks-asset-list.tsx
index 13019d672e4..a58c3a82834 100644
--- a/src/app/features/asset-list/components/stacks-asset-list.tsx
+++ b/src/app/features/asset-list/components/stacks-asset-list.tsx
@@ -2,7 +2,7 @@ import { styled } from 'leather-styles/jsx';
import { useStxBalance } from '@app/common/hooks/balance/stx/use-stx-balance';
import { ftDecimals } from '@app/common/stacks-utils';
-import { CryptoCurrencyAssetItem } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item';
+import { CryptoCurrencyAssetItemLayout } from '@app/components/crypto-assets/crypto-currency-asset/crypto-currency-asset-item.layout';
import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar';
import { useStacksFungibleTokenAssetBalancesWithMetadata } from '@app/query/stacks/balance/stacks-ft-balances.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
@@ -36,7 +36,7 @@ export function StacksAssetList({ account }: StacksAssetListProps) {
return (
<>
-
+
{assetBalances.map(assetBalance => (
-
diff --git a/src/app/features/collectibles/components/collectibes.layout.tsx b/src/app/features/collectibles/components/collectibes.layout.tsx
index ccdae07f19e..091fa5196c5 100644
--- a/src/app/features/collectibles/components/collectibes.layout.tsx
+++ b/src/app/features/collectibles/components/collectibes.layout.tsx
@@ -23,7 +23,7 @@ export function CollectiblesLayout({
}: CollectiblesLayoutProps) {
return (
<>
-
+
{title}
{isLoading ? (
diff --git a/src/app/features/increase-fee-drawer/components/increase-btc-fee-form.tsx b/src/app/features/increase-fee-drawer/components/increase-btc-fee-form.tsx
index c9520a69f7b..bb6bff62f2a 100644
--- a/src/app/features/increase-fee-drawer/components/increase-btc-fee-form.tsx
+++ b/src/app/features/increase-fee-drawer/components/increase-btc-fee-form.tsx
@@ -50,7 +50,7 @@ export function IncreaseBtcFeeForm({ btcTx }: IncreaseBtcFeeFormProps) {
validationSchema={validationSchema}
>
- {btcTx && }
+ {btcTx && }
diff --git a/src/app/features/increase-fee-drawer/components/increase-stx-fee-form.tsx b/src/app/features/increase-fee-drawer/components/increase-stx-fee-form.tsx
index a54b6467629..3b3a943cb29 100644
--- a/src/app/features/increase-fee-drawer/components/increase-stx-fee-form.tsx
+++ b/src/app/features/increase-fee-drawer/components/increase-stx-fee-form.tsx
@@ -93,7 +93,7 @@ export function IncreaseStxFeeForm() {
>
{props => (
- {tx && }
+ {tx && }
{balances?.stx.unlockedStx.amount && (
diff --git a/src/app/features/leather-intro-dialog/leather-intro-steps.tsx b/src/app/features/leather-intro-dialog/leather-intro-steps.tsx
index 29b62738bfc..48d8f80131a 100644
--- a/src/app/features/leather-intro-dialog/leather-intro-steps.tsx
+++ b/src/app/features/leather-intro-dialog/leather-intro-steps.tsx
@@ -16,7 +16,7 @@ export function LeatherIntroDialog({ children }: HasChildren) {
return (
e.preventDefault()}
onInteractOutside={e => e.preventDefault()}
className={css({ maxWidth: '500px', backgroundColor: 'accent.background-primary' })}
diff --git a/src/app/features/switch-account-drawer/components/switch-account-list-item.tsx b/src/app/features/switch-account-drawer/components/switch-account-list-item.tsx
index 761823e7bc1..d5e77122983 100644
--- a/src/app/features/switch-account-drawer/components/switch-account-list-item.tsx
+++ b/src/app/features/switch-account-drawer/components/switch-account-list-item.tsx
@@ -5,7 +5,6 @@ import { useSwitchAccount } from '@app/common/hooks/account/use-switch-account';
import { useLoading } from '@app/common/hooks/use-loading';
import { AccountTotalBalance } from '@app/components/account-total-balance';
import { AccountListItemLayout } from '@app/components/account/account-list-item-layout';
-import { usePressable } from '@app/components/item-hover';
import { useNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
@@ -28,7 +27,6 @@ export const SwitchAccountListItem = memo(
'SWITCH_ACCOUNTS' + stacksAddress || bitcoinAddress
);
const { handleSwitchAccount } = useSwitchAccount(handleClose);
- const [component, bind] = usePressable(true);
const name = useAccountDisplayName({ address: stacksAddress, index });
const handleClick = async () => {
@@ -41,9 +39,7 @@ export const SwitchAccountListItem = memo(
return (
{name}}
avatar={
}
- onSelectAccount={handleClick}
- accountName={{name}}
balanceLabel={
}
- mt="space.05"
- {...bind}
- >
- {component}
-
+ index={index}
+ isLoading={isLoading}
+ isPressable
+ isSelected={currentAccountIndex === index}
+ onSelectAccount={handleClick}
+ />
);
}
);
diff --git a/src/app/features/switch-account-drawer/components/switch-account-list.tsx b/src/app/features/switch-account-drawer/components/switch-account-list.tsx
index 809dccd3804..0cafce7570f 100644
--- a/src/app/features/switch-account-drawer/components/switch-account-list.tsx
+++ b/src/app/features/switch-account-drawer/components/switch-account-list.tsx
@@ -23,7 +23,7 @@ export const SwitchAccountList = memo(
style={{ paddingTop: '24px', height: '70vh' }}
totalCount={addressesNum}
itemContent={index => (
-
+
{
- const [component, bind] = usePressable(true);
const name = useAccountDisplayName(account);
const btcAddress = useNativeSegwitAccountIndexAddressIndexZero(account.index);
const accountSlug = useMemo(() => slugify(`Account ${account?.index + 1}`), [account?.index]);
return (
- // Padding required on outer element to prevent jumpy list behaviours in
- // virtualised list library
+ // Padding required on outer element to prevent jumpy virtualized list
}>
{name}
@@ -65,13 +61,12 @@ const ChooseAccountItem = memo(
balanceLabel={
}
+ data-testid={`account-${accountSlug}-${account.index}`}
+ index={account.index}
isLoading={isLoading}
+ isSelected={false}
onSelectAccount={() => onSelectAccount(account.index)}
- data-testid={`account-${accountSlug}-${account.index}`}
- {...bind}
- >
- {component}
-
+ />
);
}
diff --git a/src/app/pages/receive/components/receive-item.tsx b/src/app/pages/receive/components/receive-item.tsx
index 95d97cec82c..a6d7e11f078 100644
--- a/src/app/pages/receive/components/receive-item.tsx
+++ b/src/app/pages/receive/components/receive-item.tsx
@@ -1,9 +1,10 @@
-import { Flex, HStack, Stack, styled } from 'leather-styles/jsx';
+import { HStack } from 'leather-styles/jsx';
-import { Flag } from '@app/components/layout/flag';
import { Button } from '@app/ui/components/button/button';
import { CopyIcon } from '@app/ui/components/icons/copy-icon';
import { QrCodeIcon } from '@app/ui/components/icons/qr-code-icon';
+import { Item } from '@app/ui/components/items/item';
+import { ItemWithButtonsLayout } from '@app/ui/components/items/item-with-buttons.layout';
import { truncateMiddle } from '@app/ui/utils/truncate-middle';
interface ReceiveItemProps {
@@ -24,23 +25,33 @@ export function ReceiveItem({
}: ReceiveItemProps) {
if (!address) return null;
return (
-
-
-
- {title}
- {truncateMiddle(address, 6)}
-
-
-
- {onClickQrCode && (
-
- )}
-
-
-
+
+
+ {title}}
+ contentLeftBottom={
+ {truncateMiddle(address, 6)}
+ }
+ contentRightTop={
+
+
+ {onClickQrCode && (
+
+ )}
+
+ }
+ />
+
+
);
}
diff --git a/src/app/pages/receive/components/receive-items.tsx b/src/app/pages/receive/components/receive-items.tsx
index d1c2d674ae9..4f89ecee966 100644
--- a/src/app/pages/receive/components/receive-items.tsx
+++ b/src/app/pages/receive/components/receive-items.tsx
@@ -13,7 +13,7 @@ export function ReceiveItemList({ children, title }: ReceiveItemListProps) {
)}
-
+
{children}
>
diff --git a/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/account-list-item.tsx b/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/account-list-item.tsx
index 971e0aa5bb5..c55652b6522 100644
--- a/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/account-list-item.tsx
+++ b/src/app/pages/send/send-crypto-asset-form/components/recipient-accounts-drawer/account-list-item.tsx
@@ -9,7 +9,6 @@ import { AccountTotalBalance } from '@app/components/account-total-balance';
import { AccountAvatarItem } from '@app/components/account/account-avatar-item';
import { AccountListItemLayout } from '@app/components/account/account-list-item-layout';
import { AccountNameLayout } from '@app/components/account/account-name';
-import { usePressable } from '@app/components/item-hover';
import { useNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
@@ -22,7 +21,6 @@ export const AccountListItem = memo(({ index, stacksAccount, onClose }: AccountL
const { setFieldValue, values, setFieldTouched } = useFormikContext<
BitcoinSendFormValues | StacksSendFormValues
>();
- const [component, bind] = usePressable(true);
const stacksAddress = stacksAccount?.address || '';
const name = useAccountDisplayName({ address: stacksAddress, index });
@@ -48,13 +46,10 @@ export const AccountListItem = memo(({ index, stacksAccount, onClose }: AccountL
}
balanceLabel={}
index={index}
- isActive={false}
+ isSelected={false}
+ isPressable
isLoading={false}
- mt="space.05"
onSelectAccount={onSelectAccount}
- {...bind}
- >
- {component}
-
+ />
);
});
diff --git a/src/app/pages/swap/swap-choose-asset/components/swap-asset-item.layout.tsx b/src/app/pages/swap/swap-choose-asset/components/swap-asset-item.layout.tsx
deleted file mode 100644
index 6f85aeafa2c..00000000000
--- a/src/app/pages/swap/swap-choose-asset/components/swap-asset-item.layout.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Stack } from 'leather-styles/jsx';
-
-import { HasChildren } from '@app/common/has-children';
-import { Flag } from '@app/components/layout/flag';
-
-export function SwapAssetItemLayout({
- children,
- icon,
- ...rest
-}: HasChildren & { icon: React.JSX.Element }) {
- return (
-
- {children}
-
- );
-}
diff --git a/src/app/pages/swap/swap-choose-asset/components/swap-asset-item.tsx b/src/app/pages/swap/swap-choose-asset/components/swap-asset-item.tsx
index 06b608c7194..2ef1aecb9df 100644
--- a/src/app/pages/swap/swap-choose-asset/components/swap-asset-item.tsx
+++ b/src/app/pages/swap/swap-choose-asset/components/swap-asset-item.tsx
@@ -1,19 +1,20 @@
-import { HStack, styled } from 'leather-styles/jsx';
+import { styled } from 'leather-styles/jsx';
import { formatMoneyWithoutSymbol } from '@app/common/money/format-money';
-import { usePressable } from '@app/components/item-hover';
import { useGetFungibleTokenMetadataQuery } from '@app/query/stacks/tokens/fungible-tokens/fungible-token-metadata.query';
import { isFtAsset } from '@app/query/stacks/tokens/token-metadata.utils';
+import { Item } from '@app/ui/components/items/item';
+import { ItemDefaultLayout } from '@app/ui/components/items/item-default.layout';
import { useAlexSdkBalanceAsFiat } from '../../hooks/use-alex-sdk-fiat-price';
import { SwapAsset } from '../../hooks/use-swap-form';
-import { SwapAssetItemLayout } from './swap-asset-item.layout';
interface SwapAssetItemProps {
asset: SwapAsset;
+ dataTestId: string;
+ onClick(): void;
}
-export function SwapAssetItem({ asset }: SwapAssetItemProps) {
- const [component, bind] = usePressable(true);
+export function SwapAssetItem({ asset, dataTestId, onClick }: SwapAssetItemProps) {
const balanceAsFiat = useAlexSdkBalanceAsFiat(asset.balance, asset.price);
const { data: ftMetadata } = useGetFungibleTokenMetadataQuery(asset.principal);
@@ -21,21 +22,17 @@ export function SwapAssetItem({ asset }: SwapAssetItemProps) {
const displayName = asset.displayName ?? ftMetadataName;
return (
- }
- {...bind}
- >
-
- {displayName}
- {formatMoneyWithoutSymbol(asset.balance)}
-
-
- {asset.name}
-
- {balanceAsFiat}
-
-
- {component}
-
+
+
+ }
+ contentLeftTop={{displayName}}
+ contentLeftBottom={{asset.name}}
+ contentRightTop={{formatMoneyWithoutSymbol(asset.balance)}}
+ contentRightBottom={{balanceAsFiat}}
+ />
+
+
);
}
diff --git a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx b/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx
index e7feee61700..eb40bfdcbf4 100644
--- a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx
+++ b/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.layout.tsx
@@ -2,7 +2,7 @@ import { Stack, StackProps } from 'leather-styles/jsx';
export function SwapAssetListLayout({ children }: StackProps) {
return (
-
+
{children}
);
diff --git a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx b/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx
index bc2875175ff..5419a1c2629 100644
--- a/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx
+++ b/src/app/pages/swap/swap-choose-asset/components/swap-asset-list.tsx
@@ -3,7 +3,6 @@ import { useNavigate } from 'react-router-dom';
import { SwapSelectors } from '@tests/selectors/swap.selectors';
import BigNumber from 'bignumber.js';
import { useFormikContext } from 'formik';
-import { styled } from 'leather-styles/jsx';
import { createMoney } from '@shared/models/money.model';
import { isUndefined } from '@shared/utils';
@@ -68,15 +67,12 @@ export function SwapAssetList({ assets }: SwapAssetList) {
return (
{selectableAssets.map(asset => (
- onChooseAsset(asset)}
- textAlign="left"
- type="button"
- >
-
-
+ />
))}
);
diff --git a/src/app/ui/components/button/button.stories.tsx b/src/app/ui/components/button/button.stories.tsx
index c0d2277c292..796d2a6a9a0 100644
--- a/src/app/ui/components/button/button.stories.tsx
+++ b/src/app/ui/components/button/button.stories.tsx
@@ -26,6 +26,18 @@ export const Button: Story = {
},
};
+export const Disabled: Story = {
+ parameters: {
+ controls: { include: ['size', 'variant'] },
+ },
+ args: {
+ disabled: true,
+ children: 'Button',
+ size: 'md',
+ variant: 'solid',
+ },
+};
+
// TODO: Remove invert code
export const InvertSolid: Story = {
parameters: {
diff --git a/src/app/ui/components/dynamic-color-circle.tsx b/src/app/ui/components/dynamic-color-circle.tsx
index e0d62e71db4..2b4d0f0e495 100644
--- a/src/app/ui/components/dynamic-color-circle.tsx
+++ b/src/app/ui/components/dynamic-color-circle.tsx
@@ -6,7 +6,7 @@ interface DynamicColorCircleProps extends CircleProps {
}
export function DynamicColorCircle({
children,
- sizeParam = '36',
+ sizeParam = '40',
value,
...props
}: DynamicColorCircleProps) {
diff --git a/src/app/ui/components/items/item-default.layout.tsx b/src/app/ui/components/items/item-default.layout.tsx
new file mode 100644
index 00000000000..ad9b7b0e7f5
--- /dev/null
+++ b/src/app/ui/components/items/item-default.layout.tsx
@@ -0,0 +1,59 @@
+import { ReactNode } from 'react';
+
+import { Grid, GridItem } from 'leather-styles/jsx';
+
+import { ChevronUpIcon } from '../icons/chevron-up-icon';
+
+interface ItemDefaultLayoutProps {
+ contentLeftTop: ReactNode;
+ contentLeftBottom?: ReactNode;
+ contentRightTop: ReactNode;
+ contentRightBottom?: ReactNode;
+ flagImg?: ReactNode;
+ isDisabled?: boolean;
+ isPressable?: boolean;
+}
+export function ItemDefaultLayout({
+ contentLeftTop,
+ contentLeftBottom,
+ contentRightTop,
+ contentRightBottom,
+ flagImg,
+ isDisabled,
+ isPressable,
+}: ItemDefaultLayoutProps) {
+ return (
+
+
+ {flagImg}
+
+
+ {contentLeftTop}
+
+
+ {contentRightTop}
+
+
+ {isPressable && (
+
+ )}
+
+ {/* Using scroll here for now bc possibly shows addresses */}
+
+ {contentLeftBottom}
+
+ {contentRightBottom && {contentRightBottom}}
+
+ );
+}
diff --git a/src/app/ui/components/items/item-with-buttons.layout.tsx b/src/app/ui/components/items/item-with-buttons.layout.tsx
new file mode 100644
index 00000000000..7900957c59e
--- /dev/null
+++ b/src/app/ui/components/items/item-with-buttons.layout.tsx
@@ -0,0 +1,45 @@
+import { ReactNode } from 'react';
+
+import { Grid, GridItem } from 'leather-styles/jsx';
+
+interface ItemWithButtonsLayoutProps {
+ contentLeftTop: ReactNode;
+ contentLeftBottom?: ReactNode;
+ contentRightTop: ReactNode;
+ contentRightBottom?: ReactNode;
+ flagImg?: ReactNode;
+ isDisabled?: boolean;
+ isPressable?: boolean;
+}
+export function ItemWithButtonsLayout({
+ contentLeftTop,
+ contentLeftBottom,
+ contentRightTop,
+ flagImg,
+}: ItemWithButtonsLayoutProps) {
+ return (
+
+
+ {flagImg}
+
+
+ {contentLeftTop}
+
+
+ {contentRightTop}
+
+ {/* Using scroll here for now bc possibly shows addresses */}
+
+ {contentLeftBottom}
+
+
+ );
+}
diff --git a/src/app/ui/components/items/item.stories.tsx b/src/app/ui/components/items/item.stories.tsx
new file mode 100644
index 00000000000..f739c1ce5b9
--- /dev/null
+++ b/src/app/ui/components/items/item.stories.tsx
@@ -0,0 +1,147 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { HStack } from 'leather-styles/jsx';
+
+import { Button } from '../button/button';
+import { BtcIcon } from '../icons/btc-icon';
+import { CheckmarkIcon } from '../icons/checkmark-icon';
+import { CopyIcon } from '../icons/copy-icon';
+import { QrCodeIcon } from '../icons/qr-code-icon';
+import { Item } from './item';
+import { ItemDefaultLayout } from './item-default.layout';
+import { ItemWithButtonsLayout } from './item-with-buttons.layout';
+
+const meta: Meta = {
+ component: Item.Root,
+ tags: ['autodocs'],
+ title: 'Item',
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+ // eslint-disable-next-line no-console
+
+
+ }
+ contentLeftTop={Label}
+ contentLeftBottom={Caption}
+ contentRightTop={1,000.00 ABC}
+ contentRightBottom={$1,000.00}
+ />
+
+
+ ),
+};
+
+export const DefaultPressable: Story = {
+ render: () => (
+ // eslint-disable-next-line no-console
+ console.log(`I'm interactive`)}>
+
+ }
+ contentLeftTop={Label}
+ contentLeftBottom={Caption}
+ contentRightTop={1,000.00 ABC}
+ contentRightBottom={$1,000.00}
+ />
+
+
+ ),
+};
+
+export const Selected: Story = {
+ render: () => (
+ // eslint-disable-next-line no-console
+ console.log(`I'm interactive`)}>
+
+ }
+ contentLeftTop={
+
+ Label
+
+
+ }
+ contentLeftBottom={Caption}
+ contentRightTop={1,000.00 ABC}
+ contentRightBottom={$1,000.00}
+ />
+
+
+ ),
+};
+
+export const Disabled: Story = {
+ render: () => (
+ // eslint-disable-next-line no-console
+ console.log(`I'm interactive`)}>
+
+ }
+ contentLeftTop={Label}
+ contentLeftBottom={Caption}
+ contentRightTop={1,000.00 ABC}
+ contentRightBottom={$1,000.00}
+ />
+
+
+ ),
+};
+
+export const WithButtons: Story = {
+ render: () => (
+ // eslint-disable-next-line no-console
+
+
+ }
+ contentLeftTop={Label}
+ contentLeftBottom={Caption}
+ contentRightTop={
+
+
+
+
+ }
+ />
+
+
+ ),
+};
+
+export const WithButtonsDisabled: Story = {
+ render: () => (
+ // eslint-disable-next-line no-console
+
+
+ }
+ contentLeftTop={Label}
+ contentLeftBottom={Caption}
+ contentRightTop={
+
+
+
+
+ }
+ />
+
+
+ ),
+};
diff --git a/src/app/ui/components/items/item.tsx b/src/app/ui/components/items/item.tsx
new file mode 100644
index 00000000000..eec33764e1e
--- /dev/null
+++ b/src/app/ui/components/items/item.tsx
@@ -0,0 +1,137 @@
+import { type ComponentProps, KeyboardEvent } from 'react';
+
+import { sva } from 'leather-styles/css';
+import { BoxProps, styled } from 'leather-styles/jsx';
+
+import { createStyleContext } from '@app/ui/utils/style-context';
+
+const item = sva({
+ slots: ['root', 'content', 'text', 'caption'],
+ base: {
+ root: {
+ bg: 'accent.background-primary',
+ height: 'auto',
+ userSelect: 'none',
+ p: 'space.03',
+ width: '100%',
+ },
+ content: {
+ width: '100%',
+ },
+ text: {
+ color: 'accent.text-primary',
+ fontWeight: 500,
+ textStyle: 'label.02',
+ },
+ caption: {
+ color: 'accent.text-subdued',
+ },
+ },
+ variants: {
+ isDisabled: {
+ true: {
+ root: {
+ _active: { bg: 'unset' },
+ _focus: { border: 'unset' },
+ _hover: { bg: 'unset' },
+ cursor: 'not-allowed',
+ },
+ content: {},
+ text: {
+ color: 'accent.non-interactive',
+ },
+ caption: {
+ color: 'accent.non-interactive',
+ },
+ },
+ },
+ isPressable: {
+ true: {
+ root: {
+ _active: {
+ bg: 'accent.component-background-pressed',
+ },
+ _focus: {
+ border: '2px solid {focus}',
+ },
+ _hover: {
+ bg: 'accent.component-background-hover',
+ },
+ },
+ },
+ },
+ isSelected: {
+ true: {
+ root: {
+ _active: {
+ bg: 'unset',
+ },
+ _focus: {
+ border: 'unset',
+ },
+ _hover: {
+ bg: 'unset',
+ },
+ },
+ },
+ },
+ },
+ compoundVariants: [
+ {
+ isDisabled: true,
+ isPressable: true,
+ css: {
+ root: {
+ _active: { bg: 'unset' },
+ _focus: { border: 'unset' },
+ _hover: { bg: 'unset' },
+ cursor: 'not-allowed',
+ },
+ },
+ },
+ ],
+});
+
+const { withProvider, withContext } = createStyleContext(item);
+
+const RootBase = withProvider('div', 'root');
+
+interface RootProps extends ComponentProps<'div'> {
+ isDisabled?: boolean;
+ isPressable?: boolean;
+ isSelected?: boolean;
+ onClick?(): void;
+}
+function Root({ isDisabled, isPressable, isSelected, onClick, ...props }: RootProps & BoxProps) {
+ const isRoleButton = !!onClick;
+
+ function onKeyDown(e: KeyboardEvent) {
+ if (!isRoleButton) return;
+ if (e.key === 'enter' || e.key === ' ') {
+ e.preventDefault();
+ onClick();
+ }
+ }
+
+ return (
+
+ );
+}
+
+const Content = withContext(styled('div'), 'content');
+
+const Text = withContext(styled('span'), 'text');
+
+const Caption = withContext(styled('span'), 'caption');
+
+export const Item = { Root, Content, Text, Caption };
diff --git a/src/app/ui/components/link/link.stories.tsx b/src/app/ui/components/link/link.stories.tsx
index b92fd85c7b8..8048b8a5091 100644
--- a/src/app/ui/components/link/link.stories.tsx
+++ b/src/app/ui/components/link/link.stories.tsx
@@ -22,6 +22,18 @@ export const Link: Story = {
},
};
+export const Disabled: Story = {
+ parameters: {
+ controls: { include: ['size', 'variant'] },
+ },
+ args: {
+ children: 'Link',
+ disabled: true,
+ size: 'md',
+ variant: 'underlined',
+ },
+};
+
// TODO: Remove invert code
export const InvertLink: Story = {
parameters: {
diff --git a/src/app/ui/components/link/link.tsx b/src/app/ui/components/link/link.tsx
index ff714540708..6890f139d90 100644
--- a/src/app/ui/components/link/link.tsx
+++ b/src/app/ui/components/link/link.tsx
@@ -9,12 +9,12 @@ type LinkProps = Omit, keyof LinkVariant
LinkVariantProps;
export const Link = forwardRef((props: LinkProps, ref: ForwardedRef) => {
- const { children, fullWidth, invert, size, variant, ...rest } = props;
+ const { children, disabled, fullWidth, invert, size, variant, ...rest } = props;
return (
diff --git a/src/app/ui/components/tooltip/basic-tooltip.tsx b/src/app/ui/components/tooltip/basic-tooltip.tsx
index e10e2d61616..56fcead792f 100644
--- a/src/app/ui/components/tooltip/basic-tooltip.tsx
+++ b/src/app/ui/components/tooltip/basic-tooltip.tsx
@@ -11,7 +11,6 @@ interface BasicTooltipProps {
side?: RadixTooltip.TooltipContentProps['side'];
asChild?: boolean;
}
-
export function BasicTooltip({ children, label, disabled, side, asChild }: BasicTooltipProps) {
const isDisabled = !label || disabled;
return (
diff --git a/theme/recipes/button-recipe.ts b/theme/recipes/button-recipe.ts
index 5e26e867360..36da0ac019b 100644
--- a/theme/recipes/button-recipe.ts
+++ b/theme/recipes/button-recipe.ts
@@ -30,9 +30,6 @@ export const buttonRecipe = defineRecipe({
className: 'button',
jsx: ['Button'],
base: {
- _disabled: {
- cursor: 'not-allowed',
- },
position: 'relative',
rounded: 'xs',
textStyle: 'label.02',
@@ -54,8 +51,10 @@ export const buttonRecipe = defineRecipe({
bg: 'accent.action-primary-default',
},
_disabled: {
+ _hover: { bg: 'accent.background-secondary' },
bg: 'accent.background-secondary',
color: 'accent.non-interactive',
+ cursor: 'not-allowed',
},
_focus: {
_before: {
@@ -74,6 +73,12 @@ export const buttonRecipe = defineRecipe({
_active: {
bg: 'accent.component-background-pressed',
},
+ _disabled: {
+ _hover: { bg: 'unset' },
+ border: '1px solid {colors.accent.non-interactive}',
+ color: 'accent.non-interactive',
+ cursor: 'not-allowed',
+ },
_focus: {
_before: {
border: '3px solid {colors.focus}',
@@ -90,6 +95,11 @@ export const buttonRecipe = defineRecipe({
_active: {
bg: 'accent.component-background-pressed',
},
+ _disabled: {
+ _hover: { bg: 'unset' },
+ color: 'accent.non-interactive',
+ cursor: 'not-allowed',
+ },
_focus: {
_before: {
border: '3px solid {focus}',
diff --git a/theme/recipes/link-recipe.ts b/theme/recipes/link-recipe.ts
index 88ba089d678..f64aba9716a 100644
--- a/theme/recipes/link-recipe.ts
+++ b/theme/recipes/link-recipe.ts
@@ -6,11 +6,7 @@ export const linkRecipe = defineRecipe({
className: 'link',
jsx: ['Link'],
base: {
- _disabled: {
- cursor: 'not-allowed',
- },
appearance: 'none',
- color: 'accent.text-primary',
display: 'inline',
mb: 'space.01',
p: 'unset',
@@ -48,12 +44,6 @@ export const linkRecipe = defineRecipe({
},
color: 'accent.text-primary',
},
- _disabled: {
- _before: {
- background: 'accent.non-interactive',
- },
- color: 'accent.non-interactive',
- },
_focus: {
_before: { background: 'focus' },
color: 'accent.text-primary',
@@ -64,6 +54,7 @@ export const linkRecipe = defineRecipe({
background: 'accent.action-primary-hover',
},
},
+ color: 'accent.text-primary',
},
text: {
@@ -84,13 +75,6 @@ export const linkRecipe = defineRecipe({
color: 'accent.text-primary',
visibility: 'visible',
},
- _disabled: {
- _before: {
- background: 'accent.non-interactive',
- visibility: 'visible',
- },
- color: 'accent.non-interactive',
- },
_focus: {
_before: {
background: 'focus',
@@ -105,12 +89,13 @@ export const linkRecipe = defineRecipe({
visibility: 'visible',
},
},
+ color: 'accent.text-primary',
},
},
// TODO: Remove invert code
invert: { true: {} },
-
+ disabled: { true: {} },
fullWidth: { true: { width: '100%' } },
},
@@ -122,8 +107,6 @@ export const linkRecipe = defineRecipe({
// TODO: Remove invert code
compoundVariants: [
{
- variant: 'underlined',
- invert: true,
css: {
_focus: {
_before: {
@@ -140,6 +123,43 @@ export const linkRecipe = defineRecipe({
},
color: 'accent.background-secondary',
},
+ invert: true,
+ variant: 'underlined',
+ },
+ {
+ css: {
+ _before: {
+ content: '""',
+ background: 'accent.non-interactive',
+ bottom: '-2px',
+ height: '2px',
+ left: 0,
+ position: 'absolute',
+ right: 0,
+ },
+ color: 'accent.non-interactive',
+ cursor: 'not-allowed',
+ },
+ disabled: true,
+ variant: 'underlined',
+ },
+ {
+ css: {
+ _before: {
+ content: '""',
+ background: 'accent.non-interactive',
+ bottom: '-2px',
+ height: '2px',
+ left: 0,
+ position: 'absolute',
+ right: 0,
+ visibility: 'visible',
+ },
+ color: 'accent.non-interactive',
+ cursor: 'not-allowed',
+ },
+ disabled: true,
+ variant: 'text',
},
],
});