"use client"; import { Bell, Eye, EyeOff } from "lucide-react"; import { useState } from "react"; import { ActionSwapText } from "@/components/motion/action-swap"; import { Button } from "@/components/motion/button"; import { cn } from "@/lib/utils"; import { AccountSwitcher } from "./account-switcher"; import { WalletActions } from "./actions"; import { BalanceDelta } from "./balance-delta"; import { SearchBar } from "./search-bar"; import type { WalletCardProps } from "./types"; export type { WalletAccount, WalletCardProps } from "./types"; /** * Composed wallet overview card: an account switcher whose trigger morphs open * into a full-width panel, a search icon that morphs into a search bar, a * rolling balance with a transient change indicator, and Send / Deposit * actions. Actions and search are plain callbacks — the resulting flow is left * to the consumer. */ export function WalletCard({ accounts, accountId, defaultAccountId, onAccountChange, balance, balancePrefix = "$", defaultChange, defaultBalanceHidden = false, onSend, onDeposit, onSwap, onBuy, searchPlaceholder, searchRecent, onSearchChange, onSearchSubmit, hasNotifications = false, onNotifications, className, }: WalletCardProps) { const accountControlled = accountId !== undefined; const [internalAccountId, setInternalAccountId] = useState( defaultAccountId ?? accounts[0]?.id, ); const [balanceHidden, setBalanceHidden] = useState(defaultBalanceHidden); const shownBalance = `${balancePrefix}${balance.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, })}`; const maskedBalance = "*".repeat(7); const activeAccountId = accountControlled ? accountId : internalAccountId; const activeAccount = accounts.find((a) => a.id === activeAccountId) ?? accounts[0]; const handleAccountChange = (id: string) => { if (!accountControlled) setInternalAccountId(id); onAccountChange?.(id); }; return (
{/* relative anchor so the switcher + search panels span the whole row */}

Balance

{/* One ActionSwapText swaps the number and the asterisk mask with a per-letter cascade — same baseline, no overlap or layout shift. */} {balanceHidden ? maskedBalance : shownBalance} {balanceHidden ? (
*****
) : ( )}
); }