@web3auth/modal
Version:
Multi chain wallet aggregator for web3Auth
261 lines (257 loc) • 11.8 kB
JavaScript
'use strict';
var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
var jsxRuntime = require('react/jsx-runtime');
var noModal = require('@web3auth/no-modal');
var react = require('react');
var constants = require('../../constants.js');
var AnalyticsContext = require('../../context/AnalyticsContext.js');
var RootContext = require('../../context/RootContext.js');
var ConnectWalletChainFilter = require('./ConnectWalletChainFilter/ConnectWalletChainFilter.js');
var ConnectWalletHeader = require('./ConnectWalletHeader/ConnectWalletHeader.js');
var ConnectWalletList = require('./ConnectWalletList/ConnectWalletList.js');
var ConnectWalletQrCode = require('./ConnectWalletQrCode/ConnectWalletQrCode.js');
var ConnectWalletSearch = require('./ConnectWalletSearch/ConnectWalletSearch.js');
function ConnectWallet(props) {
var _selectedButton$walle;
const {
isDark,
config,
walletConnectUri,
metamaskConnectUri,
walletRegistry,
allExternalButtons,
customConnectorButtons,
connectorVisibilityMap,
deviceDetails,
buttonRadius = "pill",
chainNamespace,
onBackClick,
handleExternalWalletClick,
handleWalletDetailsHeight
} = props;
const {
bodyState,
setBodyState
} = react.useContext(RootContext.RootContext);
const {
analytics
} = react.useContext(AnalyticsContext.AnalyticsContext);
const [currentPage, setCurrentPage] = react.useState(constants.CONNECT_WALLET_PAGES.CONNECT_WALLET);
const [selectedWallet, setSelectedWallet] = react.useState(false);
const [isLoading] = react.useState(false);
const [selectedButton, setSelectedButton] = react.useState(null);
const [walletSearch, setWalletSearch] = react.useState("");
const [selectedChain, setSelectedChain] = react.useState("all");
const [isShowAllWallets, setIsShowAllWallets] = react.useState(false);
const handleBack = () => {
if (!selectedWallet && currentPage === constants.CONNECT_WALLET_PAGES.CONNECT_WALLET && onBackClick) {
onBackClick(false);
return;
}
if (selectedWallet) {
setCurrentPage(constants.CONNECT_WALLET_PAGES.CONNECT_WALLET);
setSelectedWallet(false);
handleWalletDetailsHeight();
}
};
const walletDiscoverySupported = react.useMemo(() => {
const supported = walletRegistry && Object.keys(walletRegistry.default || {}).length > 0 && Object.keys(walletRegistry.others || {}).length > 0;
return supported;
}, [walletRegistry]);
const allUniqueButtons = react.useMemo(() => {
const uniqueButtonSet = new Set();
return customConnectorButtons.concat(allExternalButtons).filter(button => {
if (uniqueButtonSet.has(button.name)) return false;
uniqueButtonSet.add(button.name);
return true;
});
}, [allExternalButtons, customConnectorButtons]);
const defaultButtonKeys = react.useMemo(() => new Set(Object.keys(walletRegistry.default)), [walletRegistry]);
const defaultButtons = react.useMemo(() => {
// display order: default injected buttons > custom adapter buttons > default non-injected buttons
const buttons = [...allExternalButtons.filter(button => button.hasInjectedWallet && defaultButtonKeys.has(button.name)), ...customConnectorButtons, ...allExternalButtons.filter(button => !button.hasInjectedWallet && defaultButtonKeys.has(button.name))].sort((a, b) => {
// favor MetaMask over other wallets
if (a.name === noModal.WALLET_CONNECTORS.METAMASK && b.name === noModal.WALLET_CONNECTORS.METAMASK) {
// favor injected MetaMask over non-injected MetaMask
if (a.hasInjectedWallet) return -1;
if (b.hasInjectedWallet) return 1;
// favor installed MetaMask over non-installed MetaMask
if (a.isInstalled) return -1;
if (b.isInstalled) return 1;
return 0;
}
if (a.name === noModal.WALLET_CONNECTORS.METAMASK) return -1;
if (b.name === noModal.WALLET_CONNECTORS.METAMASK) return 1;
return 0;
});
const buttonSet = new Set();
return buttons.filter(button => {
if (buttonSet.has(button.name)) return false;
buttonSet.add(button.name);
return true;
}).filter(button => {
var _button$chainNamespac;
return selectedChain === "all" || ((_button$chainNamespac = button.chainNamespaces) === null || _button$chainNamespac === void 0 ? void 0 : _button$chainNamespac.includes(selectedChain));
});
}, [allExternalButtons, customConnectorButtons, defaultButtonKeys, selectedChain]);
const installedWalletButtons = react.useMemo(() => {
const visibilityMap = connectorVisibilityMap;
return Object.keys(config).reduce((acc, localConnector) => {
if (localConnector !== noModal.WALLET_CONNECTORS.WALLET_CONNECT_V2 && visibilityMap[localConnector]) {
acc.push({
name: localConnector,
displayName: config[localConnector].label || localConnector,
hasInjectedWallet: config[localConnector].isInjected,
hasWalletConnect: false,
hasInstallLinks: false
});
}
return acc;
}, []);
}, [connectorVisibilityMap, config]);
const handleWalletSearch = e => {
const searchValue = e.target.value;
setWalletSearch(searchValue);
};
const handleChainFilterChange = chain => {
setSelectedChain(chain);
setIsShowAllWallets(false);
};
const filteredButtons = react.useMemo(() => {
if (walletDiscoverySupported) {
return [...allUniqueButtons.filter(button => button.hasInjectedWallet), ...allUniqueButtons.filter(button => !button.hasInjectedWallet)].sort((a, _) => a.name === noModal.WALLET_CONNECTORS.METAMASK ? -1 : 1).filter(button => selectedChain === "all" || button.chainNamespaces.includes(selectedChain)).filter(button => button.name.toLowerCase().includes(walletSearch.toLowerCase()));
}
return installedWalletButtons;
}, [walletDiscoverySupported, installedWalletButtons, walletSearch, allUniqueButtons, selectedChain]);
const externalButtons = react.useMemo(() => {
if (walletDiscoverySupported && !walletSearch && !isShowAllWallets) {
return defaultButtons;
}
return filteredButtons;
}, [walletDiscoverySupported, walletSearch, filteredButtons, defaultButtons, isShowAllWallets]);
const totalExternalWalletsCount = react.useMemo(() => filteredButtons.length, [filteredButtons]);
const initialWalletCount = react.useMemo(() => {
if (isShowAllWallets) return totalExternalWalletsCount;
return walletDiscoverySupported ? defaultButtons.length : installedWalletButtons.length;
}, [walletDiscoverySupported, defaultButtons, installedWalletButtons, isShowAllWallets, totalExternalWalletsCount]);
/**
* Wallet click logic
* - For installed wallets
* - For MetaMask non-injected on desktop, show QR code for connection
* - Ask user to select a chain namespace if it has multiple namespaces
* - Otherwise, use their connectors to connect
* - For wallet-discovery wallets (not installed)
* - On desktop, show QR code for connection if wallet connect v2 is supported, otherwise show install links
* - On mobile, open deeplink with wallet connect uri (won't go into this function as it'll open the deeplink)
*/
const handleWalletClick = button => {
analytics === null || analytics === void 0 || analytics.track(noModal.ANALYTICS_EVENTS.EXTERNAL_WALLET_SELECTED, {
connector: button.isInstalled ? button.name : button.hasWalletConnect ? noModal.WALLET_CONNECTORS.WALLET_CONNECT_V2 : "",
wallet_name: button.displayName,
is_installed: button.isInstalled,
is_injected: button.hasInjectedWallet,
chain_namespaces: button.chainNamespaces,
has_wallet_connect: button.hasWalletConnect,
has_install_links: button.hasInstallLinks,
has_wallet_registry_item: !!button.walletRegistryItem,
total_external_wallets: allUniqueButtons.length
});
// for installed wallets
if (button.isInstalled) {
var _button$chainNamespac2;
// for MetaMask non-injected on desktop, show QR code for connection
if (button.name === noModal.WALLET_CONNECTORS.METAMASK && !button.hasInjectedWallet && deviceDetails.platform === "desktop") {
handleExternalWalletClick({
connector: button.name
});
setSelectedButton(button);
setSelectedWallet(true);
setCurrentPage(constants.CONNECT_WALLET_PAGES.SELECTED_WALLET);
handleWalletDetailsHeight();
return;
}
// show chain namespace selector if the button has multiple chain namespaces
if (((_button$chainNamespac2 = button.chainNamespaces) === null || _button$chainNamespac2 === void 0 ? void 0 : _button$chainNamespac2.length) > 1) {
setBodyState(_objectSpread(_objectSpread({}, bodyState), {}, {
multiChainSelector: {
show: true,
wallet: button
}
}));
return;
}
// otherwise, use their connectors to connect
handleExternalWalletClick({
connector: button.name
});
return;
} else {
// show QR code if wallet connect v2 is supported
if (button.hasWalletConnect) {
setSelectedButton(button);
setSelectedWallet(true);
setCurrentPage(constants.CONNECT_WALLET_PAGES.SELECTED_WALLET);
handleWalletDetailsHeight();
} else {
// otherwise, show install links
setBodyState(_objectSpread(_objectSpread({}, bodyState), {}, {
installLinks: {
show: true,
wallet: button
}
}));
}
}
};
const handleMoreWallets = () => {
setIsShowAllWallets(true);
};
const qrCodeValue = react.useMemo(() => {
if (!selectedWallet) return null;
if (selectedButton.name === noModal.WALLET_CONNECTORS.METAMASK && !selectedButton.hasInjectedWallet) {
return metamaskConnectUri;
}
return walletConnectUri;
}, [metamaskConnectUri, selectedButton, selectedWallet, walletConnectUri]);
return jsxRuntime.jsxs("div", {
className: "w3a--relative w3a--flex w3a--flex-1 w3a--flex-col w3a--gap-y-4",
children: [jsxRuntime.jsx(ConnectWalletHeader, {
onBackClick: handleBack,
currentPage: currentPage,
selectedButton: selectedButton
}), selectedWallet ? jsxRuntime.jsx(ConnectWalletQrCode, {
qrCodeValue: qrCodeValue,
isDark: isDark,
selectedButton: selectedButton,
primaryColor: (_selectedButton$walle = selectedButton.walletRegistryItem) === null || _selectedButton$walle === void 0 ? void 0 : _selectedButton$walle.primaryColor,
logoImage: `https://images.web3auth.io/login-${selectedButton.name}.${selectedButton.imgExtension}`
}) : jsxRuntime.jsxs("div", {
className: "w3a--flex w3a--flex-col w3a--gap-y-2",
children: [jsxRuntime.jsx(ConnectWalletChainFilter, {
isDark: isDark,
isLoading: isLoading,
selectedChain: selectedChain,
setSelectedChain: handleChainFilterChange,
chainNamespace: chainNamespace
}), jsxRuntime.jsx(ConnectWalletSearch, {
totalExternalWalletCount: totalExternalWalletsCount,
isLoading: isLoading,
walletSearch: walletSearch,
handleWalletSearch: handleWalletSearch,
buttonRadius: buttonRadius
}), jsxRuntime.jsx(ConnectWalletList, {
externalButtons: externalButtons,
isLoading: isLoading,
totalExternalWalletsCount: totalExternalWalletsCount,
initialWalletCount: initialWalletCount,
handleWalletClick: handleWalletClick,
handleMoreWallets: handleMoreWallets,
isDark: isDark,
deviceDetails: deviceDetails,
walletConnectUri: walletConnectUri,
buttonRadius: buttonRadius
})]
})]
});
}
module.exports = ConnectWallet;