import type { WalletName } from '@solana/wallet-adapter-base'; import { WalletReadyState } from '@solana/wallet-adapter-base'; import { useWallet } from '@solana/wallet-adapter-react'; import { UnsafeBurnerWalletName } from '@solana/wallet-adapter-wallets'; import type { FC, MouseEvent } from 'react'; import React, { useCallback, useLayoutEffect, useMemo, useRef, useState, useEffect } from 'react'; import { createPortal } from 'react-dom'; import { WalletListItem } from './WalletListItem.js'; import { WalletInfoContent } from './WalletInfoModal.js'; import { WalletSVG } from './WalletSVG.js'; import { useWalletModal } from './useWalletModal.js'; import { motion, AnimatePresence } from 'framer-motion'; export interface WalletModalProps { className?: string; container?: string; } export const WalletModal: FC = ({ className = '', container = 'body' }) => { const ref = useRef(null); const contentRef = useRef(null); const [wrapperStyle, setWrapperStyle] = useState({}); const { wallets, select } = useWallet(); const { setVisible } = useWalletModal(); const [fadeIn, setFadeIn] = useState(false); const [portal, setPortal] = useState(null); const [showInfo, setShowInfo] = useState(false); const allWallets = useMemo(() => { // Filter out unsupported wallets return wallets.filter((wallet) => wallet.readyState !== WalletReadyState.Unsupported); }, [wallets]); const hideModal = useCallback(() => { setFadeIn(false); setTimeout(() => setVisible(false), 150); }, [setVisible]); const handleClose = useCallback( (event: MouseEvent) => { event.preventDefault(); hideModal(); }, [hideModal] ); const handleInfoClick = useCallback(() => { setShowInfo((prevShowInfo) => !prevShowInfo); }, []); const handleWalletClick = useCallback( (event: MouseEvent, walletName: WalletName) => { select(walletName); handleClose(event); }, [select, handleClose] ); const handleTabKey = useCallback( (event: KeyboardEvent) => { const node = ref.current; if (!node) return; // here we query all focusable elements const focusableElements = node.querySelectorAll('button'); const firstElement = focusableElements[0]; const lastElement = focusableElements[focusableElements.length - 1]; if (event.shiftKey) { // if going backward by pressing tab and firstElement is active, shift focus to last focusable element if (document.activeElement === firstElement) { lastElement?.focus(); event.preventDefault(); } } else { // if going forward by pressing tab and lastElement is active, shift focus to first focusable element if (document.activeElement === lastElement) { firstElement?.focus(); event.preventDefault(); } } }, [ref] ); useEffect(() => { if (contentRef.current) { const height = contentRef.current.offsetHeight; const width = contentRef.current.offsetWidth; setWrapperStyle({ height: `${height}px`, width: `${width}px` }); } }, [showInfo, allWallets.length]); useLayoutEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape') { hideModal(); } else if (event.key === 'Tab') { handleTabKey(event); } }; // Get original overflow const { overflow } = window.getComputedStyle(document.body); // Hack to enable fade in animation after mount setTimeout(() => setFadeIn(true), 0); // Prevent scrolling on mount document.body.style.overflow = 'hidden'; // Listen for keydown events window.addEventListener('keydown', handleKeyDown, false); return () => { // Re-enable scrolling when component unmounts document.body.style.overflow = overflow; window.removeEventListener('keydown', handleKeyDown, false); }; }, [hideModal, handleTabKey]); useLayoutEffect(() => setPortal(document.querySelector(container)), [container]); return ( portal && createPortal(
{showInfo ? ( ) : allWallets.length ? (

Connect a wallet

{allWallets.some( (wallet) => wallet.adapter.name !== UnsafeBurnerWalletName ) ? null : (

No Wallets Detected

You'll need add a wallet to your browser to interact with Solana if you want to continue using this app.

{/* */}
Don't want to connect one?
)}
    {allWallets.map((wallet) => ( handleWalletClick(event, wallet.adapter.name) } wallet={wallet} className={ wallet.adapter.name === UnsafeBurnerWalletName ? 'wallet-adapter-modal-burner-wallet' : '' } /> ))}
) : (

No Wallets Detected

{/*

No Wallets Detected

*/}

You'll need add a wallet to your browser to interact with Solana if you want to continue using this app.

Don't have a wallet?
)}
, portal ) ); };