@rainbow-me/rainbowkit
Version:
The best way to connect a wallet
1,603 lines (1,562 loc) • 109 kB
JavaScript
"use client";
import {
clearWalletConnectDeepLink,
setWalletConnectDeepLink
} from "./chunk-2OYWM5PT.js";
import {
useFingerprint
} from "./chunk-2XMNEWGC.js";
import {
ShowBalanceProvider
} from "./chunk-AN42NTNH.js";
import {
SignIn,
signInIcon
} from "./chunk-ECEOMTJ4.js";
import {
useAuthenticationStatus
} from "./chunk-HV6CXRKE.js";
import {
ScanIcon,
preloadScanIcon
} from "./chunk-UHKQ3VXU.js";
import {
QRCode,
ScrollClassName,
sidebar,
sidebarCompactMode
} from "./chunk-43UHM7WW.js";
import {
ModalSelection
} from "./chunk-EUVA3UIR.js";
import {
useCoolMode
} from "./chunk-FYSZGIQO.js";
import {
CoolModeContext
} from "./chunk-MTKKMYEM.js";
import {
CreateIcon,
preloadCreateIcon
} from "./chunk-5CWMKPFM.js";
import {
DisconnectSqIcon
} from "./chunk-QHCI6IOK.js";
import {
RefreshIcon,
preloadRefreshIcon
} from "./chunk-GS6ON4CP.js";
import {
FocusTrap
} from "./chunk-BZM5SOML.js";
import {
BackIcon
} from "./chunk-UVHMW2HK.js";
import {
ConnectIcon,
preloadConnectIcon
} from "./chunk-K6QUU53N.js";
import {
InfoButton
} from "./chunk-WNG7QZO3.js";
import {
ProfileDetails
} from "./chunk-AZYJGE7V.js";
import {
ShowRecentTransactionsContext
} from "./chunk-N5355GF6.js";
import {
TransactionStoreProvider
} from "./chunk-ZEV4IGYH.js";
import {
DialogContent
} from "./chunk-HQ2UCA7U.js";
import {
ModalSizeContext,
ModalSizeOptions,
ModalSizeProvider,
useWindowSize
} from "./chunk-FDGUNHHI.js";
import {
WalletButtonContext,
WalletButtonProvider
} from "./chunk-GZW2ASFM.js";
import {
CloseButton
} from "./chunk-6EUFMSBE.js";
import {
ConnectModalIntro
} from "./chunk-B3YCHM62.js";
import {
preloadLoginIcon
} from "./chunk-XHCFJPNB.js";
import {
preloadAssetsIcon
} from "./chunk-TQYOPFJ3.js";
import {
AppContext,
defaultAppInfo
} from "./chunk-FKYDNCKF.js";
import {
DisclaimerLink
} from "./chunk-JYW4WTWH.js";
import {
DisclaimerText
} from "./chunk-S4UEOOUP.js";
import {
ActionButton
} from "./chunk-NJZMOW4M.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 {
touchableStyles
} from "./chunk-2W63IDAD.js";
import {
Text
} from "./chunk-32RBZPUM.js";
import {
AvatarContext,
defaultAvatar
} from "./chunk-Q5YA4B5I.js";
import {
SpinnerIcon
} from "./chunk-5NIYHKHP.js";
import {
AsyncImage
} from "./chunk-Z2CMCMO5.js";
import {
isIOS,
isMobile
} from "./chunk-N6EWR2LO.js";
import {
loadImages
} from "./chunk-RFBRD22G.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