UNPKG

@rainbow-me/rainbowkit

Version:
1,603 lines (1,562 loc) 109 kB
"use client"; import { useFingerprint } from "./chunk-2XMNEWGC.js"; import { clearWalletConnectDeepLink, setWalletConnectDeepLink } from "./chunk-2OYWM5PT.js"; import { ShowBalanceProvider } from "./chunk-AN42NTNH.js"; import { SignIn, signInIcon } from "./chunk-HOUAFGC3.js"; import { useAuthenticationStatus } from "./chunk-HV6CXRKE.js"; import { QRCode, ScrollClassName, sidebar, sidebarCompactMode } from "./chunk-43UHM7WW.js"; import { InfoButton } from "./chunk-WNG7QZO3.js"; import { ProfileDetails } from "./chunk-2P7LL5L2.js"; import { ShowRecentTransactionsContext } from "./chunk-N5355GF6.js"; import { TransactionStoreProvider } from "./chunk-ZDHXDPKZ.js"; import { ModalSelection } from "./chunk-EVBYWOJ3.js"; import { useCoolMode } from "./chunk-FYSZGIQO.js"; import { CoolModeContext } from "./chunk-MTKKMYEM.js"; import { RefreshIcon, preloadRefreshIcon } from "./chunk-GS6ON4CP.js"; import { ScanIcon, preloadScanIcon } from "./chunk-UHKQ3VXU.js"; import { ConnectIcon, preloadConnectIcon } from "./chunk-K6QUU53N.js"; import { CreateIcon, preloadCreateIcon } from "./chunk-5CWMKPFM.js"; import { DisconnectSqIcon } from "./chunk-QHCI6IOK.js"; import { DialogContent } from "./chunk-HQ2UCA7U.js"; import { ModalSizeContext, ModalSizeOptions, ModalSizeProvider, useWindowSize } from "./chunk-FDGUNHHI.js"; import { WalletButtonContext, WalletButtonProvider } from "./chunk-GZW2ASFM.js"; import { FocusTrap } from "./chunk-BZM5SOML.js"; import { BackIcon } from "./chunk-UVHMW2HK.js"; import { ConnectModalIntro } from "./chunk-DZCPM6YD.js"; import { AppContext, defaultAppInfo } from "./chunk-FKYDNCKF.js"; import { preloadLoginIcon } from "./chunk-XHCFJPNB.js"; import { preloadAssetsIcon } from "./chunk-TQYOPFJ3.js"; import { DisclaimerLink } from "./chunk-JYW4WTWH.js"; import { DisclaimerText } from "./chunk-S4UEOOUP.js"; import { ActionButton } from "./chunk-7P76HI55.js"; import { CloseButton } from "./chunk-6EUFMSBE.js"; import { Chain_default } from "./chunk-XN6DBLYY.js"; import { RainbowKitChainProvider, useInitialChainId, useRainbowKitChains } from "./chunk-BI56UNYD.js"; import { isNotNullish } from "./chunk-QEKGRQAR.js"; import { MenuButton } from "./chunk-4LDQCPJF.js"; import { I18nContext, I18nProvider } from "./chunk-E5IRXM5F.js"; import { Text } from "./chunk-32RBZPUM.js"; import { touchableStyles } from "./chunk-2W63IDAD.js"; import { AsyncImage } from "./chunk-Z2CMCMO5.js"; import { isIOS, isMobile } from "./chunk-N6EWR2LO.js"; import { loadImages } from "./chunk-RFBRD22G.js"; import { AvatarContext, defaultAvatar } from "./chunk-Q5YA4B5I.js"; import { SpinnerIcon } from "./chunk-5NIYHKHP.js"; import { Box } from "./chunk-ZKEPQLOV.js"; import { themeVars } from "./chunk-RFUL46NX.js"; // src/components/Dialog/Dialog.tsx import React11, { useCallback as useCallback4, useEffect as useEffect6, useState as useState5 } from "react"; import { createPortal } from "react-dom"; import { RemoveScroll } from "react-remove-scroll"; // src/components/RainbowKitProvider/RainbowKitProvider.tsx import React10, { createContext as createContext2, useContext as useContext8 } from "react"; import { useAccountEffect as useAccountEffect2 } from "wagmi"; // src/css/cssObjectFromTheme.ts import { assignInlineVars } from "@vanilla-extract/dynamic"; var resolveThemeVars = (theme) => typeof theme === "function" ? theme() : theme; function cssObjectFromTheme(theme, { extends: baseTheme2 } = {}) { const resolvedThemeVars = { // We use an object spread here to ensure it's a plain object since vanilla-extract's // var objects have a custom 'toString' method that returns a CSS string, but we don't // want to leak this to our consumers since they're unaware we're using vanilla-extract. // Instead, we want them to handle this explicitly via our 'cssStringFromTheme' function. ...assignInlineVars(themeVars, resolveThemeVars(theme)) }; if (!baseTheme2) { return resolvedThemeVars; } const resolvedBaseThemeVars = assignInlineVars( themeVars, resolveThemeVars(baseTheme2) ); const filteredVars = Object.fromEntries( Object.entries(resolvedThemeVars).filter( ([varName, value]) => value !== resolvedBaseThemeVars[varName] ) ); return filteredVars; } // src/css/cssStringFromTheme.ts function cssStringFromTheme(theme, options = {}) { return Object.entries(cssObjectFromTheme(theme, options)).map(([key, value]) => `${key}:${value.replace(/[:;{}</>]/g, "")};`).join(""); } // src/themes/baseTheme.ts var systemFontStack = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"'; var fontStacks = { rounded: `SFRounded, ui-rounded, "SF Pro Rounded", ${systemFontStack}`, system: systemFontStack }; var radiusScales = { large: { actionButton: "9999px", connectButton: "12px", modal: "24px", modalMobile: "28px" }, medium: { actionButton: "10px", connectButton: "8px", modal: "16px", modalMobile: "18px" }, none: { actionButton: "0px", connectButton: "0px", modal: "0px", modalMobile: "0px" }, small: { actionButton: "4px", connectButton: "4px", modal: "8px", modalMobile: "8px" } }; var blurs = { large: { modalOverlay: "blur(20px)" }, none: { modalOverlay: "blur(0px)" }, small: { modalOverlay: "blur(4px)" } }; var baseTheme = ({ borderRadius = "large", fontStack = "rounded", overlayBlur = "none" }) => ({ blurs: { modalOverlay: blurs[overlayBlur].modalOverlay }, fonts: { body: fontStacks[fontStack] }, radii: { actionButton: radiusScales[borderRadius].actionButton, connectButton: radiusScales[borderRadius].connectButton, menuButton: radiusScales[borderRadius].connectButton, modal: radiusScales[borderRadius].modal, modalMobile: radiusScales[borderRadius].modalMobile } }); // src/themes/lightTheme.ts var accentColors = { blue: { accentColor: "#0E76FD", accentColorForeground: "#FFF" }, green: { accentColor: "#1DB847", accentColorForeground: "#FFF" }, orange: { accentColor: "#FF801F", accentColorForeground: "#FFF" }, pink: { accentColor: "#FF5CA0", accentColorForeground: "#FFF" }, purple: { accentColor: "#5F5AFA", accentColorForeground: "#FFF" }, red: { accentColor: "#FA423C", accentColorForeground: "#FFF" } }; var defaultAccentColor = accentColors.blue; var lightTheme = ({ accentColor = defaultAccentColor.accentColor, accentColorForeground = defaultAccentColor.accentColorForeground, ...baseThemeOptions } = {}) => ({ ...baseTheme(baseThemeOptions), colors: { accentColor, accentColorForeground, actionButtonBorder: "rgba(0, 0, 0, 0.04)", actionButtonBorderMobile: "rgba(0, 0, 0, 0.06)", actionButtonSecondaryBackground: "rgba(0, 0, 0, 0.06)", closeButton: "rgba(60, 66, 66, 0.8)", closeButtonBackground: "rgba(0, 0, 0, 0.06)", connectButtonBackground: "#FFF", connectButtonBackgroundError: "#FF494A", connectButtonInnerBackground: "linear-gradient(0deg, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.06))", connectButtonText: "#25292E", connectButtonTextError: "#FFF", connectionIndicator: "#30E000", downloadBottomCardBackground: "linear-gradient(126deg, rgba(255, 255, 255, 0) 9.49%, rgba(171, 171, 171, 0.04) 71.04%), #FFFFFF", downloadTopCardBackground: "linear-gradient(126deg, rgba(171, 171, 171, 0.2) 9.49%, rgba(255, 255, 255, 0) 71.04%), #FFFFFF", error: "#FF494A", generalBorder: "rgba(0, 0, 0, 0.06)", generalBorderDim: "rgba(0, 0, 0, 0.03)", menuItemBackground: "rgba(60, 66, 66, 0.1)", modalBackdrop: "rgba(0, 0, 0, 0.3)", modalBackground: "#FFF", modalBorder: "transparent", modalText: "#25292E", modalTextDim: "rgba(60, 66, 66, 0.3)", modalTextSecondary: "rgba(60, 66, 66, 0.6)", profileAction: "#FFF", profileActionHover: "rgba(255, 255, 255, 0.5)", profileForeground: "rgba(60, 66, 66, 0.06)", selectedOptionBorder: "rgba(60, 66, 66, 0.1)", standby: "#FFD641" }, shadows: { connectButton: "0px 4px 12px rgba(0, 0, 0, 0.1)", dialog: "0px 8px 32px rgba(0, 0, 0, 0.32)", profileDetailsAction: "0px 2px 6px rgba(37, 41, 46, 0.04)", selectedOption: "0px 2px 6px rgba(0, 0, 0, 0.24)", selectedWallet: "0px 2px 6px rgba(0, 0, 0, 0.12)", walletLogo: "0px 2px 16px rgba(0, 0, 0, 0.16)" } }); lightTheme.accentColors = accentColors; // src/components/RainbowKitProvider/ModalContext.tsx import React9, { createContext, useCallback as useCallback2, useContext as useContext7, useEffect as useEffect4, useMemo, useState as useState4 } from "react"; import { useAccount as useAccount5, useAccountEffect, useConfig as useConfig2 } from "wagmi"; // src/hooks/useConnectionStatus.ts import { useAccount } from "wagmi"; function useConnectionStatus() { const authenticationStatus = useAuthenticationStatus(); const { isConnected } = useAccount(); if (!isConnected) { return "disconnected"; } if (!authenticationStatus) { return "connected"; } if (authenticationStatus === "loading" || authenticationStatus === "unauthenticated") { return authenticationStatus; } return "connected"; } // src/components/AccountModal/AccountModal.tsx import React from "react"; import { useAccount as useAccount2, useDisconnect } from "wagmi"; // src/hooks/useProfile.ts import { useBalance } from "wagmi"; // src/hooks/useMainnetEnsAvatar.ts import { normalize } from "viem/ens"; import { useEnsAvatar } from "wagmi"; import { mainnet as mainnet2 } from "wagmi/chains"; // src/hooks/useIsMainnetConfigured.ts import { mainnet } from "wagmi/chains"; function useIsMainnetConfigured() { const rainbowKitChains = useRainbowKitChains(); const chainId = mainnet.id; const configured = rainbowKitChains.some( (rainbowKitChain) => rainbowKitChain.id === chainId ); return configured; } // src/hooks/useMainnetEnsAvatar.ts function useMainnetEnsAvatar(name) { const mainnetConfigured = useIsMainnetConfigured(); const safeNormalize = (ensName) => { try { return normalize(ensName); } catch { } }; const { data: ensAvatar } = useEnsAvatar({ chainId: mainnet2.id, name: name ? safeNormalize(name) : void 0, query: { enabled: mainnetConfigured } }); return ensAvatar; } // src/hooks/useMainnetEnsName.ts import { useQuery } from "@tanstack/react-query"; import { useEnsName } from "wagmi"; import { mainnet as mainnet3 } from "wagmi/chains"; // src/core/network/internal/rainbowFetch.ts async function rainbowFetch(url, opts) { const requestOpts = { headers: {}, method: "get", ...opts, // Any other fetch options timeout: opts.timeout ?? 1e4 // 10 secs }; if (!url) throw new Error("rainbowFetch: Missing url argument"); const controller = new AbortController(); const id = setTimeout(() => controller.abort(), requestOpts.timeout); const { body, params, headers, ...otherOpts } = requestOpts; const requestBody = body && typeof body === "object" ? JSON.stringify(body) : body; const response = await fetch(`${url}${createParams(params)}`, { ...otherOpts, body: requestBody, headers: { Accept: "application/json", "Content-Type": "application/json", ...headers }, signal: controller.signal }); clearTimeout(id); const responseBody = await getBody(response); if (response.ok) { const { headers: headers2, status } = response; return { data: responseBody, headers: headers2, status }; } const errorResponseBody = typeof responseBody === "string" ? { error: responseBody } : responseBody; const error = generateError({ requestBody: body, response, responseBody: errorResponseBody }); throw error; } function getBody(response) { const contentType = response.headers.get("Content-Type"); if (contentType?.startsWith("application/json")) { return response.json(); } return response.text(); } function createParams(params) { return params && Object.keys(params).length ? `?${new URLSearchParams(params)}` : ""; } function generateError({ requestBody, response, responseBody }) { const message = responseBody?.error || response?.statusText || "There was an error with the request."; const error = new Error(message); error.response = response; error.responseBody = responseBody; error.requestBody = requestBody; return error; } var RainbowFetchClient = class { constructor(opts = {}) { const { baseUrl = "", ...otherOpts } = opts; this.baseUrl = baseUrl; this.opts = otherOpts; } /** * Perform a GET request with the RainbowFetchClient. */ get(url, opts) { return rainbowFetch(`${this.baseUrl}${url}`, { ...this.opts, ...opts || {}, method: "get" }); } /** * Perform a DELETE request with the RainbowFetchClient. */ delete(url, opts) { return rainbowFetch(`${this.baseUrl}${url}`, { ...this.opts, ...opts || {}, method: "delete" }); } /** * Perform a HEAD request with the RainbowFetchClient. */ head(url, opts) { return rainbowFetch(`${this.baseUrl}${url}`, { ...this.opts, ...opts || {}, method: "head" }); } /** * Perform a OPTIONS request with the RainbowFetchClient. */ options(url, opts) { return rainbowFetch(`${this.baseUrl}${url}`, { ...this.opts, ...opts || {}, method: "options" }); } /** * Perform a POST request with the RainbowFetchClient. */ post(url, body, opts) { return rainbowFetch(`${this.baseUrl}${url}`, { ...this.opts, ...opts || {}, body, method: "post" }); } /** * Perform a PUT request with the RainbowFetchClient. */ put(url, body, opts) { return rainbowFetch(`${this.baseUrl}${url}`, { ...this.opts, ...opts || {}, body, method: "put" }); } /** * Perform a PATCH request with the RainbowFetchClient. */ patch(url, body, opts) { return rainbowFetch(`${this.baseUrl}${url}`, { ...this.opts, ...opts || {}, body, method: "patch" }); } }; // src/core/network/internal/createHttpClient.ts function createHttpClient({ baseUrl, headers, params, timeout }) { return new RainbowFetchClient({ baseUrl, headers, params, timeout }); } // src/core/network/enhancedProvider.ts var ENHANCED_PROVIDER_ENABLED = Boolean( typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.RAINBOW_PROVIDER_API_KEY ); var enhancedProviderHttp = createHttpClient({ baseUrl: "https://enhanced-provider.rainbow.me", headers: { "x-api-key": typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.RAINBOW_PROVIDER_API_KEY || "__rainbowProviderApiKey" } }); // src/core/react-query/createQuery.ts function createQueryKey(key, args, config = {}) { return [key, args, config]; } // src/utils/ens.ts import { isAddress } from "viem"; function getStorageEnsNameKey(address) { return `rk-ens-name-${address}`; } function safeParseJsonData(string) { try { const value = string ? JSON.parse(string) : null; return typeof value === "object" ? value : null; } catch { return null; } } function addEnsName(address, ensName) { if (!isAddress(address) || typeof window === "undefined") return; const now = /* @__PURE__ */ new Date(); const expiry = new Date(now.getTime() + 180 * 6e4); window.localStorage.setItem( getStorageEnsNameKey(address), JSON.stringify({ ensName, expires: expiry.getTime() }) ); } function getEnsName(address) { if (typeof window === "undefined") return null; const data = safeParseJsonData( window.localStorage.getItem(getStorageEnsNameKey(address)) ); if (!data) return null; const { ensName, expires } = data; if (typeof ensName !== "string" || Number.isNaN(Number(expires))) { window.localStorage.removeItem(getStorageEnsNameKey(address)); return null; } const now = /* @__PURE__ */ new Date(); if (now.getTime() > Number(expires)) { window.localStorage.removeItem(getStorageEnsNameKey(address)); return null; } return ensName; } // src/hooks/useMainnetEnsName.ts async function getEnhancedProviderEnsName({ address }) { const ensName = getEnsName(address); if (ensName) return ensName; const response = await enhancedProviderHttp.get("/v1/resolve-ens", { params: { address } }); const enhancedProviderEnsName = response.data.data; if (enhancedProviderEnsName) { addEnsName(address, enhancedProviderEnsName); } return enhancedProviderEnsName; } function useMainnetEnsName(address) { const mainnetConfigured = useIsMainnetConfigured(); const { data: ensName } = useEnsName({ chainId: mainnet3.id, address, query: { enabled: mainnetConfigured } }); const { data: enhancedProviderEnsName } = useQuery({ queryKey: createQueryKey("address", address), queryFn: () => getEnhancedProviderEnsName({ address }), enabled: !mainnetConfigured && !!address && ENHANCED_PROVIDER_ENABLED, staleTime: 10 * (60 * 1e3), // 10 minutes retry: 1 // Retry once before returning undefined if the request fails }); return ensName || enhancedProviderEnsName; } // src/hooks/useProfile.ts function useProfile({ address, includeBalance }) { const ensName = useMainnetEnsName(address); const ensAvatar = useMainnetEnsAvatar(ensName); const { data: balance } = useBalance({ address: includeBalance ? address : void 0 }); return { ensName, ensAvatar, balance }; } // src/components/AccountModal/AccountModal.tsx function AccountModal({ onClose, open }) { const { address } = useAccount2(); const { balance, ensAvatar, ensName } = useProfile({ address, includeBalance: open }); const { disconnect } = useDisconnect(); if (!address) { return null; } const titleId = "rk_account_modal_title"; return /* @__PURE__ */ React.createElement(React.Fragment, null, address && /* @__PURE__ */ React.createElement(Dialog, { onClose, open, titleId }, /* @__PURE__ */ React.createElement(DialogContent, { bottomSheetOnMobile: true, padding: "0" }, /* @__PURE__ */ React.createElement( ProfileDetails, { address, ensAvatar, ensName, balance, onClose, onDisconnect: disconnect } )))); } // src/components/ChainModal/ChainModal.tsx import React2, { useContext, useState } from "react"; import { useAccount as useAccount3, useConfig, useDisconnect as useDisconnect2, useSwitchChain } from "wagmi"; // src/components/ChainModal/ChainModal.css.ts var DesktopScrollClassName = "_18dqw9x0"; var MobileScrollClassName = "_18dqw9x1"; // src/components/ChainModal/ChainModal.tsx function ChainModal({ onClose, open }) { const { chainId } = useAccount3(); const { chains } = useConfig(); const [pendingChainId, setPendingChainId] = useState(null); const { switchChain } = useSwitchChain({ mutation: { onMutate: ({ chainId: _chainId }) => { setPendingChainId(_chainId); }, onSuccess: () => { if (pendingChainId) setPendingChainId(null); }, onError: () => { if (pendingChainId) setPendingChainId(null); }, onSettled: () => { onClose(); } } }); const { i18n } = useContext(I18nContext); const { disconnect } = useDisconnect2(); const titleId = "rk_chain_modal_title"; const mobile = isMobile(); const isCurrentChainSupported = chains.some((chain) => chain.id === chainId); const chainIconSize = mobile ? "36" : "28"; const rainbowkitChains = useRainbowKitChains(); if (!chainId) { return null; } return /* @__PURE__ */ React2.createElement(Dialog, { onClose, open, titleId }, /* @__PURE__ */ React2.createElement(DialogContent, { bottomSheetOnMobile: true, paddingBottom: "0" }, /* @__PURE__ */ React2.createElement(Box, { display: "flex", flexDirection: "column", gap: "14" }, /* @__PURE__ */ React2.createElement( Box, { display: "flex", flexDirection: "row", justifyContent: "space-between" }, mobile && /* @__PURE__ */ React2.createElement(Box, { width: "30" }), /* @__PURE__ */ React2.createElement(Box, { paddingBottom: "0", paddingLeft: "8", paddingTop: "4" }, /* @__PURE__ */ React2.createElement( Text, { as: "h1", color: "modalText", id: titleId, size: mobile ? "20" : "18", weight: "heavy" }, i18n.t("chains.title") )), /* @__PURE__ */ React2.createElement(CloseButton, { onClose }) ), !isCurrentChainSupported && /* @__PURE__ */ React2.createElement(Box, { marginX: "8", textAlign: mobile ? "center" : "left" }, /* @__PURE__ */ React2.createElement(Text, { color: "modalTextSecondary", size: "14", weight: "medium" }, i18n.t("chains.wrong_network"))), /* @__PURE__ */ React2.createElement( Box, { className: mobile ? MobileScrollClassName : DesktopScrollClassName, display: "flex", flexDirection: "column", gap: "4", padding: "2", paddingBottom: "16" }, rainbowkitChains.map( ({ iconBackground, iconUrl, id, name }, idx) => { return /* @__PURE__ */ React2.createElement( Chain_default, { key: id, chainId: id, currentChainId: chainId, switchChain, chainIconSize, isLoading: pendingChainId === id, src: iconUrl, name, iconBackground, idx } ); } ), !isCurrentChainSupported && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Box, { background: "generalBorderDim", height: "1", marginX: "8" }), /* @__PURE__ */ React2.createElement( MenuButton, { onClick: () => disconnect(), testId: "chain-option-disconnect" }, /* @__PURE__ */ React2.createElement( Box, { color: "error", fontFamily: "body", fontSize: "16", fontWeight: "bold" }, /* @__PURE__ */ React2.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "row", justifyContent: "space-between" }, /* @__PURE__ */ React2.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "row", gap: "4", height: chainIconSize }, /* @__PURE__ */ React2.createElement( Box, { alignItems: "center", color: "error", height: chainIconSize, justifyContent: "center", marginRight: "8" }, /* @__PURE__ */ React2.createElement(DisconnectSqIcon, { size: Number(chainIconSize) }) ), /* @__PURE__ */ React2.createElement("div", null, i18n.t("chains.disconnect")) ) ) ) )) )))); } // src/components/ConnectModal/ConnectModal.tsx import React8 from "react"; import { useAccount as useAccount4, useDisconnect as useDisconnect3 } from "wagmi"; // src/components/ConnectOptions/ConnectOptions.tsx import React7, { useContext as useContext6 } from "react"; // src/components/ConnectOptions/DesktopOptions.tsx import React4, { Fragment, useContext as useContext3, useEffect as useEffect2, useRef, useState as useState2 } from "react"; // src/utils/browsers.ts function isSafari() { return typeof navigator !== "undefined" && typeof navigator.userAgent !== "undefined" && /Version\/([0-9._]+).*Safari/.test(navigator.userAgent); } function isArc() { return typeof document !== "undefined" && getComputedStyle(document.body).getPropertyValue("--arc-palette-focus") !== ""; } function getBrowser() { if (typeof navigator === "undefined") return "Browser" /* Browser */; const ua2 = navigator.userAgent?.toLowerCase(); if (navigator.brave?.isBrave) return "Brave" /* Brave */; if (ua2?.indexOf("edg/") > -1) return "Edge" /* Edge */; if (ua2?.indexOf("op") > -1) return "Opera" /* Opera */; if (isArc()) return "Arc" /* Arc */; if (ua2?.indexOf("chrome") > -1) return "Chrome" /* Chrome */; if (ua2?.indexOf("firefox") > -1) return "Firefox" /* Firefox */; if (isSafari()) return "Safari" /* Safari */; return "Browser" /* Browser */; } // src/utils/groupBy.ts function groupBy(items, getKey) { const groupedItems = {}; for (const item of items) { const key = getKey(item); if (!key) { continue; } if (!groupedItems[key]) { groupedItems[key] = []; } groupedItems[key].push(item); } return groupedItems; } // src/wallets/latestWalletId.ts var storageKey = "rk-latest-id"; function getLatestWalletId() { return typeof window !== "undefined" ? window.localStorage.getItem(storageKey) || "" : ""; } function addLatestWalletId(walletId) { if (typeof window !== "undefined") { window.localStorage.setItem(storageKey, walletId); } } function clearLatestWalletId() { if (typeof window !== "undefined") { window.localStorage.removeItem(storageKey); } } // src/wallets/useWalletConnectors.ts import { useConnect } from "wagmi"; // src/utils/indexBy.ts function indexBy(items, getKey) { const indexedItems = {}; for (const item of items) { const key = getKey(item); if (!key) { continue; } indexedItems[key] = item; } return indexedItems; } // src/utils/platforms.ts import { UAParser } from "ua-parser-js"; var ua = UAParser(); var { os } = ua; function isWindows() { return os.name === "Windows"; } function isMacOS() { return os.name === "macOS"; } function isLinux() { return ["Ubuntu", "Mint", "Fedora", "Debian", "Arch", "Linux"].includes( os.name ); } function getPlatform() { if (isWindows()) return "Windows" /* Windows */; if (isMacOS()) return "macOS" /* MacOS */; if (isLinux()) return "Linux" /* Linux */; return "Desktop" /* Desktop */; } // src/wallets/downloadUrls.ts var getExtensionDownloadUrl = (wallet) => { const browser = getBrowser(); return { ["Arc" /* Arc */]: wallet?.downloadUrls?.chrome, ["Brave" /* Brave */]: wallet?.downloadUrls?.chrome, ["Chrome" /* Chrome */]: wallet?.downloadUrls?.chrome, ["Edge" /* Edge */]: wallet?.downloadUrls?.edge || wallet?.downloadUrls?.chrome, ["Firefox" /* Firefox */]: wallet?.downloadUrls?.firefox, ["Opera" /* Opera */]: wallet?.downloadUrls?.opera || wallet?.downloadUrls?.chrome, ["Safari" /* Safari */]: wallet?.downloadUrls?.safari, ["Browser" /* Browser */]: wallet?.downloadUrls?.browserExtension }[browser] ?? wallet?.downloadUrls?.browserExtension; }; var getMobileDownloadUrl = (wallet) => { const ios = isIOS(); return (ios ? wallet?.downloadUrls?.ios : wallet?.downloadUrls?.android) ?? wallet?.downloadUrls?.mobile; }; var getDesktopDownloadUrl = (wallet) => { const platform = getPlatform(); return { ["Windows" /* Windows */]: wallet?.downloadUrls?.windows, ["macOS" /* MacOS */]: wallet?.downloadUrls?.macos, ["Linux" /* Linux */]: wallet?.downloadUrls?.linux, ["Desktop" /* Desktop */]: wallet?.downloadUrls?.desktop }[platform] ?? wallet?.downloadUrls?.desktop; }; // src/wallets/groupedWallets.ts var isRecentWallet = (recentWallets, walletId) => { return recentWallets.some((recentWallet) => recentWallet.id === walletId); }; var isRainbowKitConnector = (wallet) => { return !!wallet.isRainbowKitConnector; }; var isEIP6963Connector = (wallet) => { return !!(!wallet.isRainbowKitConnector && wallet.icon?.replace(/\n/g, "").startsWith("data:image") && wallet.uid && wallet.name); }; var rainbowKitConnectorWithWalletConnect = (wallet, walletConnectModalConnector) => { const shouldUseWalletConnectModal = wallet.id === "walletConnect" && walletConnectModalConnector; return shouldUseWalletConnectModal ? { ...wallet, walletConnectModalConnector } : wallet; }; var connectorsWithRecentWallets = ({ wallets, recentWallets }) => { return [ ...recentWallets, ...wallets.filter((wallet) => !isRecentWallet(recentWallets, wallet.id)) ]; }; // src/wallets/recentWalletIds.ts var storageKey2 = "rk-recent"; function safeParseJsonArray(string) { try { const value = string ? JSON.parse(string) : []; return Array.isArray(value) ? value : []; } catch { return []; } } function getRecentWalletIds() { return typeof window !== "undefined" ? safeParseJsonArray(window.localStorage.getItem(storageKey2)) : []; } function dedupe(array) { return [...new Set(array)]; } function addRecentWalletId(walletId) { const newValue = dedupe([walletId, ...getRecentWalletIds()]); if (typeof window !== "undefined") { window.localStorage.setItem(storageKey2, JSON.stringify(newValue)); } } // src/wallets/useWalletConnectors.ts function useWalletConnectors(mergeEIP6963WithRkConnectors = false) { const rainbowKitChains = useRainbowKitChains(); const intialChainId = useInitialChainId(); const { connectAsync, connectors: defaultConnectors_untyped } = useConnect(); const defaultCreatedConnectors = defaultConnectors_untyped; const { setIsWalletConnectModalOpen } = useWalletConnectOpenState(); const defaultConnectors = defaultCreatedConnectors.map((connector) => ({ ...connector, // rkDetails is optional it does not exist in eip6963 connectors. // We only inject `rkDetails` in `connectorsForWallets` when we // want to have additional information in the connector. ...connector.rkDetails || {} })); async function connectWallet(connector, parameters) { const walletChainId = await connector.getChainId(); const result = await connectAsync({ ...parameters, chainId: parameters?.chainId ?? // The goal here is to ensure users are always on a supported chain when connecting. // If an `initialChain` prop was provided to RainbowKitProvider, use that. intialChainId ?? // Otherwise, if the wallet is already on a supported chain, use that to avoid a chain switch prompt. rainbowKitChains.find(({ id }) => id === walletChainId)?.id ?? // Finally, fall back to the first chain provided to RainbowKitProvider. rainbowKitChains[0]?.id, connector }); if (result) { addRecentWalletId(connector.id); } return result; } async function connectToWalletConnectModal(walletConnectModalConnector2) { try { setIsWalletConnectModalOpen(true); await connectWallet(walletConnectModalConnector2); setIsWalletConnectModalOpen(false); } catch (err) { const isUserRejection = ( // @ts-expect-error - Web3Modal v1 error name err.name === "UserRejectedRequestError" || // @ts-expect-error - Web3Modal v2 error message on desktop err.message === "Connection request reset. Please try again." ); setIsWalletConnectModalOpen(false); if (!isUserRejection) { throw err; } } } const getWalletConnectUri = async (connector, uriConverter) => { const provider = await connector.getProvider(); if (connector.id === "coinbase") { return provider.qrUrl; } return new Promise( (resolve) => ( // Wagmi v2 doesn't have a return type for provider yet // @ts-expect-error provider.once("display_uri", (uri) => { resolve(uriConverter(uri)); }) ) ); }; const walletConnectModalConnector = defaultConnectors.find( (connector) => connector.id === "walletConnect" && connector.isWalletConnectModalConnector ); const eip6963Connectors = defaultConnectors.filter(isEIP6963Connector).map((connector) => { return { ...connector, groupIndex: 0 }; }); const rainbowKitConnectors = defaultConnectors.filter(isRainbowKitConnector).filter((wallet) => !wallet.isWalletConnectModalConnector).filter((wallet) => { if (!mergeEIP6963WithRkConnectors) return true; const existsInEIP6963Connectors = eip6963Connectors.some( (eip6963) => eip6963.id === wallet.rdns ); return !existsInEIP6963Connectors; }).map( (wallet) => rainbowKitConnectorWithWalletConnect( wallet, walletConnectModalConnector ) ); const combinedConnectors = [...eip6963Connectors, ...rainbowKitConnectors]; const walletInstanceById = indexBy( combinedConnectors, (walletInstance) => walletInstance.id ); const MAX_RECENT_WALLETS = 3; const recentWallets = getRecentWalletIds().map((walletId) => walletInstanceById[walletId]).filter(Boolean).slice(0, MAX_RECENT_WALLETS); const walletConnectors = []; const combinedConnectorsWithRecentWallets = connectorsWithRecentWallets({ wallets: combinedConnectors, recentWallets }); for (const wallet of combinedConnectorsWithRecentWallets) { if (!wallet) continue; const eip6963 = isEIP6963Connector(wallet); const recent = isRecentWallet(recentWallets, wallet.id); if (eip6963) { walletConnectors.push({ ...wallet, iconUrl: wallet.icon, ready: true, connect: connectWallet.bind(null, wallet), groupName: "Installed", recent }); continue; } walletConnectors.push({ ...wallet, ready: wallet.installed ?? true, connect: connectWallet.bind(null, wallet), desktopDownloadUrl: getDesktopDownloadUrl(wallet), extensionDownloadUrl: getExtensionDownloadUrl(wallet), groupName: wallet.groupName, mobileDownloadUrl: getMobileDownloadUrl(wallet), getQrCodeUri: wallet.qrCode?.getUri ? () => getWalletConnectUri(wallet, wallet.qrCode.getUri) : void 0, getDesktopUri: wallet.desktop?.getUri ? () => getWalletConnectUri(wallet, wallet.desktop.getUri) : void 0, getMobileUri: wallet.mobile?.getUri ? () => getWalletConnectUri(wallet, wallet.mobile.getUri) : void 0, recent, showWalletConnectModal: wallet.walletConnectModalConnector ? () => connectToWalletConnectModal(wallet.walletConnectModalConnector) : void 0 }); } return walletConnectors; } // src/components/ConnectOptions/ConnectDetails.tsx import React3, { useContext as useContext2, useEffect } from "react"; // src/utils/colors.ts var convertHexToRGBA = (hexCode, opacity = 1) => { let hex = hexCode.replace("#", ""); if (hex.length === 3) { hex = `${hex[0]}${hex[0]}${hex[1]}${hex[1]}${hex[2]}${hex[2]}`; } const r = Number.parseInt(hex.substring(0, 2), 16); const g = Number.parseInt(hex.substring(2, 4), 16); const b = Number.parseInt(hex.substring(4, 6), 16); const normalizedOpacity = opacity > 1 && opacity <= 100 ? opacity / 100 : opacity; return `rgba(${r},${g},${b},${normalizedOpacity})`; }; var getGradientRGBAs = (hexColor) => { if (!hexColor) return null; return [ convertHexToRGBA(hexColor, 0.2), convertHexToRGBA(hexColor, 0.14), convertHexToRGBA(hexColor, 0.1) ]; }; // src/components/ConnectOptions/ConnectDetails.tsx var getBrowserSrc = async () => { const browser = getBrowser(); switch (browser) { case "Arc" /* Arc */: return (await import("./Arc-VDBY7LNS.js")).default; case "Brave" /* Brave */: return (await import("./Brave-BRAKJXDS.js")).default; case "Chrome" /* Chrome */: return (await import("./Chrome-65Q5P54Y.js")).default; case "Edge" /* Edge */: return (await import("./Edge-XSPUTORV.js")).default; case "Firefox" /* Firefox */: return (await import("./Firefox-AAHGJQIP.js")).default; case "Opera" /* Opera */: return (await import("./Opera-KQZLSACL.js")).default; case "Safari" /* Safari */: return (await import("./Safari-ZPL37GXR.js")).default; default: return (await import("./Browser-76IHF3Y2.js")).default; } }; var preloadBrowserIcon = () => loadImages(getBrowserSrc); var getPlatformSrc = async () => { const platform = getPlatform(); switch (platform) { case "Windows" /* Windows */: return (await import("./Windows-PPTHQER6.js")).default; case "macOS" /* MacOS */: return (await import("./Macos-MW4AE7LN.js")).default; case "Linux" /* Linux */: return (await import("./Linux-OO4TNCLJ.js")).default; default: return (await import("./Linux-OO4TNCLJ.js")).default; } }; var preloadPlatformIcon = () => loadImages(getPlatformSrc); function GetDetail({ getWalletDownload, compactModeEnabled }) { const wallets = useWalletConnectors().filter( (wallet) => wallet.isRainbowKitConnector ); const shownWallets = wallets.splice(0, 5); const { i18n } = useContext2(I18nContext); return /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "column", height: "full", marginTop: "18", width: "full" }, /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "column", gap: "28", height: "full", width: "full" }, shownWallets?.filter( (wallet) => wallet.extensionDownloadUrl || wallet.desktopDownloadUrl || wallet.qrCode && wallet.downloadUrls?.qrCode ).map((wallet) => { const { downloadUrls, iconBackground, iconUrl, id, name, qrCode } = wallet; const hasMobileCompanionApp = downloadUrls?.qrCode && qrCode; const hasExtension = !!wallet.extensionDownloadUrl; const hasMobileAndExtension = downloadUrls?.qrCode && hasExtension; const hasMobileAndDesktop = downloadUrls?.qrCode && !!wallet.desktopDownloadUrl; return /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", gap: "16", justifyContent: "space-between", key: wallet.id, width: "full" }, /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "row", gap: "16" }, /* @__PURE__ */ React3.createElement( AsyncImage, { background: iconBackground, borderColor: "actionButtonBorder", borderRadius: "10", height: "48", src: iconUrl, width: "48" } ), /* @__PURE__ */ React3.createElement(Box, { display: "flex", flexDirection: "column", gap: "2" }, /* @__PURE__ */ React3.createElement(Text, { color: "modalText", size: "14", weight: "bold" }, name), /* @__PURE__ */ React3.createElement(Text, { color: "modalTextSecondary", size: "14", weight: "medium" }, hasMobileAndExtension ? i18n.t("get.mobile_and_extension.description") : hasMobileAndDesktop ? i18n.t("get.mobile_and_desktop.description") : hasMobileCompanionApp ? i18n.t("get.mobile.description") : hasExtension ? i18n.t("get.extension.description") : null)) ), /* @__PURE__ */ React3.createElement(Box, { display: "flex", flexDirection: "column", gap: "4" }, /* @__PURE__ */ React3.createElement( ActionButton, { label: i18n.t("get.action.label"), onClick: () => getWalletDownload(id), type: "secondary" } )) ); }) ), /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", borderRadius: "10", display: "flex", flexDirection: "column", gap: "8", justifyContent: "space-between", marginBottom: "4", paddingY: "8", style: { maxWidth: 275, textAlign: "center" } }, /* @__PURE__ */ React3.createElement(Text, { color: "modalText", size: "14", weight: "bold" }, i18n.t("get.looking_for.title")), /* @__PURE__ */ React3.createElement(Text, { color: "modalTextSecondary", size: "14", weight: "medium" }, compactModeEnabled ? i18n.t("get.looking_for.desktop.compact_description") : i18n.t("get.looking_for.desktop.wide_description")) ) ); } var LOGO_SIZE = "44"; function ConnectDetail({ changeWalletStep, compactModeEnabled, connectionError, onClose, qrCodeUri, reconnect, wallet }) { const { downloadUrls, iconBackground, iconUrl, name, qrCode, ready, showWalletConnectModal, getDesktopUri } = wallet; const isDesktopDeepLinkAvailable = !!getDesktopUri; const safari = isSafari(); const { i18n } = useContext2(I18nContext); const hasExtension = !!wallet.extensionDownloadUrl; const hasQrCodeAndExtension = downloadUrls?.qrCode && hasExtension; const hasQrCodeAndDesktop = downloadUrls?.qrCode && !!wallet.desktopDownloadUrl; const hasQrCode = qrCode && qrCodeUri; const onDesktopUri = async () => { const uri = await getDesktopUri?.(); window.open(uri, safari ? "_blank" : "_self"); }; const secondaryAction = showWalletConnectModal ? { description: !compactModeEnabled ? i18n.t("connect.walletconnect.description.full") : i18n.t("connect.walletconnect.description.compact"), label: i18n.t("connect.walletconnect.open.label"), onClick: () => { onClose(); showWalletConnectModal(); } } : hasQrCode ? { description: i18n.t("connect.secondary_action.get.description", { wallet: name }), label: i18n.t("connect.secondary_action.get.label"), onClick: () => changeWalletStep( hasQrCodeAndExtension || hasQrCodeAndDesktop ? "DOWNLOAD_OPTIONS" /* DownloadOptions */ : "DOWNLOAD" /* Download */ ) } : null; const { width: windowWidth } = useWindowSize(); const smallWindow = windowWidth && windowWidth < 768; useEffect(() => { preloadBrowserIcon(); preloadPlatformIcon(); }, []); return /* @__PURE__ */ React3.createElement(Box, { display: "flex", flexDirection: "column", height: "full", width: "full" }, hasQrCode ? /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", height: "full", justifyContent: "center" }, /* @__PURE__ */ React3.createElement( QRCode, { logoBackground: iconBackground, logoSize: compactModeEnabled ? 60 : 72, logoUrl: iconUrl, size: compactModeEnabled ? 318 : smallWindow ? Math.max(280, Math.min(windowWidth - 308, 382)) : 382, uri: qrCodeUri } ) ) : /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", justifyContent: "center", style: { flexGrow: 1 } }, /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "column", gap: "8" }, /* @__PURE__ */ React3.createElement(Box, { borderRadius: "10", height: LOGO_SIZE, overflow: "hidden" }, /* @__PURE__ */ React3.createElement( AsyncImage, { useAsImage: !wallet.isRainbowKitConnector, height: LOGO_SIZE, src: iconUrl, width: LOGO_SIZE } )), /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "column", gap: "4", paddingX: "32", style: { textAlign: "center" } }, /* @__PURE__ */ React3.createElement(Text, { color: "modalText", size: "18", weight: "bold" }, ready ? i18n.t("connect.status.opening", { wallet: name }) : hasExtension ? i18n.t("connect.status.not_installed", { wallet: name }) : i18n.t("connect.status.not_available", { wallet: name })), !ready && hasExtension ? /* @__PURE__ */ React3.createElement(Box, { paddingTop: "20" }, /* @__PURE__ */ React3.createElement( ActionButton, { href: wallet.extensionDownloadUrl, label: i18n.t("connect.secondary_action.install.label"), type: "secondary" } )) : null, ready && !hasQrCode && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", display: "flex", flexDirection: "column", justifyContent: "center" }, /* @__PURE__ */ React3.createElement( Text, { color: "modalTextSecondary", size: "14", textAlign: "center", weight: "medium" }, i18n.t("connect.status.confirm") ) ), /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", color: "modalText", display: "flex", flexDirection: "row", height: "32", marginTop: "8" }, connectionError ? /* @__PURE__ */ React3.createElement( ActionButton, { label: i18n.t("connect.secondary_action.retry.label"), onClick: async () => { if (isDesktopDeepLinkAvailable) onDesktopUri(); reconnect(wallet); } } ) : /* @__PURE__ */ React3.createElement(Box, { color: "modalTextSecondary" }, /* @__PURE__ */ React3.createElement(SpinnerIcon, null)) )) ) ) ), /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", borderRadius: "10", display: "flex", flexDirection: "row", gap: "8", height: "28", justifyContent: "space-between", marginTop: "12" }, ready && secondaryAction && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(Text, { color: "modalTextSecondary", size: "14", weight: "medium" }, secondaryAction.description), /* @__PURE__ */ React3.createElement( ActionButton, { label: secondaryAction.label, onClick: secondaryAction.onClick, type: "secondary" } )) )); } var DownloadOptionsBox = ({ actionLabel, description, iconAccent, iconBackground, iconUrl, isCompact, onAction, title, url, variant }) => { const isBrowserCard = variant === "browser"; const gradientRgbas = !isBrowserCard && iconAccent && getGradientRGBAs(iconAccent); return /* @__PURE__ */ React3.createElement( Box, { alignItems: "center", borderRadius: "13", display: "flex", justifyContent: "center", overflow: "hidden", paddingX: isCompact ? "18" : "44", position: "relative", style: { flex: 1, isolation: "isolate" }, width: "full" }, /* @__PURE__ */ React3.createElement( Box, { borderColor: "actionButtonBorder", borderRadius: "13", borderStyle: "solid", borderWidth: "1", style: { bottom: "0", left: "0", position: "absolute", right: "0", top: "0", zIndex: 1 } } ), isBrowserCard && /* @__PURE__ */ React3.createElement( Box, { background: "downloadTopCardBackground", height: "full", position: "absolute", style: { zIndex: 0 }, width: "full" }, /* @__PURE__ */ React3.createElement( Box, { display: "flex", flexDirection: "row", justifyContent: "space-between", style: { bottom: "0", filter: "blur(20px)", left: "0", position: "absolute", right: "0", top: "0", transform: "translate3d(0, 0, 0)" } }, /* @__PURE__ */ React3.createElement( Box, { style: { filter: "blur(100px)", marginLeft: -27, marginTop: -20, opacity: 0.6, transform: "translate3d(0, 0, 0)" } }, /* @__PURE__ */ React3.createElement( AsyncImage, { borderRadius: "full", height: "200", src: iconUrl, width: "200" } ) ), /* @__PURE__ */ React3.createElement( Box, { style: { filter: "blur(100px)", marginRight: 0, marginTop: 105, opacity: 0.6, overflow: "auto", transform: "translate3d(0, 0, 0)" } }, /* @__PURE__ */ React3.createElement( AsyncImage, { borderRadius: "full", height: "200", src: iconUrl, width: "200" } ) ) ) ), !isBrowserCard && gradientRgbas && /* @__PURE__ */ React3.createElement( Box, { background: "downloadBottomCardBackground", style: { bottom: "0", left: "0", position: "absolute", right: "0", top: "0" } }, /* @__PURE__ */ React3.createElement( Box, { position: "absolute", style: { background: `radial-gradient(50% 50% at 50% 50%, ${gradientRgbas[0]} 0%, ${gradientRgbas[1]} 25%, rgba(0,0,0,0) 100%)`, height: 564, left: -215, top: -197, tr