Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/UI modal fix #1935

Merged
merged 11 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/base/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ export interface WalletRegistryItem {
universal?: string;
inAppBrowser?: string;
};
primaryColor?: string;
}

export type WalletRegistry = Record<string, WalletRegistryItem>;
export type WalletRegistry = { others: Record<string, WalletRegistryItem>; default: Record<string, WalletRegistryItem> };

export function storageAvailable(type: "sessionStorage" | "localStorage"): boolean {
let storageExists = false;
Expand Down
2 changes: 1 addition & 1 deletion packages/modal/src/modalManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export class Web3Auth extends Web3AuthNoModal implements IWeb3AuthModal {
if (!this.options.uiConfig.defaultLanguage) this.options.uiConfig.defaultLanguage = getUserLanguage(this.options.uiConfig.defaultLanguage);
if (!this.options.uiConfig.mode) this.options.uiConfig.mode = "light";

let walletRegistry: WalletRegistry = {};
let walletRegistry: WalletRegistry = { others: {}, default: {} };
try {
walletRegistry = await fetchWalletRegistry(walletRegistryUrl);
} catch (e) {
Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/Button/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ a.t-btn:not(.t-btn-text) {
}
#w3a-modal .size-xl {
height: 52px;
@apply px-6 py-3.5 text-base;
@apply px-4 py-3.5 text-base;
}
/* #w3a-modal .icon {
@apply rounded-full;
Expand Down Expand Up @@ -160,14 +160,14 @@ a.t-btn:not(.t-btn-text) {
#w3a-modal .btn-link {
@apply no-underline;
}
#w3a-modal button.t-btn:hover>.hover-icon {
#w3a-modal button.t-btn:hover > .hover-icon {
display: block;
transition: display 150ms;
transition-timing-function: cubic-bezier(0, 0.54, 0.63, 0.99);
}

#w3a-modal button.t-btn:hover>.image-icon {
#w3a-modal button.t-btn:hover > .image-icon {
display: none;
transition: display 150ms;
transition-timing-function: cubic-bezier(0, 0.54, 0.63, 0.99);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ export default function ExternalWalletButton(props: ExternalWalletButtonProps) {
variant="tertiary"
type="button"
onClick={() => handleWalletClick(button)}
className="w-full rounded-xl size-xl flex !justify-between items-center bg-app-gray-100 hover:bg-app-gray-200 dark:bg-app-gray-700 dark:hover:bg-app-gray-800 !px-2"
className="w-full rounded-xl size-xl flex !justify-between items-center wallet-btn"
title={adapterConfig?.label || button.name}
>
<div className="flex items-center">
<Image imageId={`login-${button.name}`} hoverImageId={`login-${button.name}`} fallbackImageId="wallet" height="30" width="30" isButton />
<p className="ml-2 text-left">{adapterConfig?.label || button.displayName}</p>
<Image imageId={`login-${button.name}`} hoverImageId={`login-${button.name}`} fallbackImageId="wallet" height="24" width="24" isButton />
<p className="ml-2 text-left text-sm">{adapterConfig?.label || button.displayName}</p>
</div>
{button.hasInjectedWallet && (
<span className="inline-flex items-center rounded-lg px-2 py-1 text-xs font-medium bg-app-primary-100 text-app-primary-800">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,16 @@ export default function ExternalWalletConnect(props: ExternalWalletConnectProps)
{!walletConnectUri ? (
<Loader modalStatus={MODAL_STATUS.CONNECTING} canEmit={false} />
) : (
<WalletConnect walletConnectUri={walletConnectUri} logoImage={`https://images.web3auth.io/login-${connectButton.name}.svg`} />
<WalletConnect
walletConnectUri={walletConnectUri}
logoImage={`https://images.web3auth.io/login-${connectButton.name}.svg`}
primaryColor={connectButton.walletRegistryItem.primaryColor}
/>
)}

{/* Install links */}
{connectButton.hasInstallLinks && (
<div className="flex flex-row items-center justify-between gap-2 bg-app-gray-50 dark:bg-app-gray-700 text-app-gray-900 dark:text-app-white px-3 py-2 rounded-xl mt-3">
<div className="flex flex-row items-center justify-between gap-2 bg-app-gray-50 dark:bg-app-gray-700 text-app-gray-900 dark:text-app-white px-3 py-2 rounded-xl">
<span className="text-sm truncate flex-grow-0">
{t("modal.external.dont-have")} <span>{connectButton.displayName}</span>?
</span>
Expand Down
71 changes: 42 additions & 29 deletions packages/ui/src/components/ExternalWallets.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BaseAdapterConfig, ChainNamespaceType, log, WALLET_ADAPTERS, WalletRegistry } from "@web3auth/base";
import { BaseAdapterConfig, ChainNamespaceType, log, WALLET_ADAPTERS, WalletRegistry, WalletRegistryItem } from "@web3auth/base";
import bowser from "bowser";
import { ChangeEvent, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
Expand Down Expand Up @@ -43,7 +43,7 @@ export default function ExternalWallet(props: ExternalWalletsProps) {
showBackButton,
modalStatus,
chainNamespace,
walletRegistry = {},
walletRegistry,
} = props;
const [externalButtons, setExternalButtons] = useState<ExternalButton[]>([]);
const [adapterVisibilityMap, setAdapterVisibilityMap] = useState<Record<string, boolean>>({});
Expand Down Expand Up @@ -77,7 +77,6 @@ export default function ExternalWallet(props: ExternalWalletsProps) {
if (wcAvailable && !walletConnectUri) {
handleExternalWalletClick({ adapter: WALLET_ADAPTERS.WALLET_CONNECT_V2 });
}

const canShowMap: Record<string, boolean> = {};
Object.keys(config).forEach((adapter) => {
const adapterConfig = config[adapter];
Expand All @@ -102,18 +101,20 @@ export default function ExternalWallet(props: ExternalWalletsProps) {
useEffect(() => {
if (isWalletDiscoveryReady) {
const isWalletConnectAdapterIncluded = Object.keys(config).some((adapter) => adapter === WALLET_ADAPTERS.WALLET_CONNECT_V2);
const buttons: ExternalButton[] = Object.keys(walletRegistry).reduce((acc, wallet) => {
if (adapterVisibilityMap[wallet] !== false) {
const walletRegistryItem = walletRegistry[wallet];
// don't include wallets that don't support sign v2
if (!walletRegistryItem.walletConnect?.sdks?.includes("sign_v2")) return acc;
const defaultButtonKeys = new Set(Object.keys(walletRegistry.default));

const generateWalletButtons = (wallets: Record<string, WalletRegistryItem>): ExternalButton[] => {
return Object.keys(wallets).reduce((acc, wallet) => {
if (adapterVisibilityMap[wallet] === false) return acc;

const walletRegistryItem: WalletRegistryItem = wallets[wallet];
let href = "";
if (deviceDetails.platform === bowser.PLATFORMS_MAP.mobile && walletConnectUri) {
const universalLink = walletRegistryItem?.mobile?.universal;
const deepLink = walletRegistryItem?.mobile?.native;
href = universalLink || deepLink ? formatIOSMobile({ uri: walletConnectUri, universalLink, deepLink }) : walletConnectUri;
}
// All injected wallets are present in wallet registry

const button = {
name: wallet,
displayName: walletRegistryItem.name,
Expand All @@ -123,15 +124,23 @@ export default function ExternalWallet(props: ExternalWalletsProps) {
hasInstallLinks: Object.keys(walletRegistryItem.app || {}).length > 0,
walletRegistryItem,
};

if (!button.hasInjectedWallet && !button.hasWalletConnect && !button.hasInstallLinks) return acc;

const chainNamespaces = new Set(walletRegistryItem.chains?.map((chain) => chain.split(":")[0]));
if (!chainNamespaces.has(chainNamespace)) return acc;

acc.push(button);
}
return acc;
}, [] as ExternalButton[]);
return acc;
}, [] as ExternalButton[]);
};

// Generate buttons for default and other wallets
const defaultButtons = generateWalletButtons(walletRegistry.default);
const otherButtons = generateWalletButtons(walletRegistry.others);

// Generate custom adapter buttons
const customAdapterButtons: ExternalButton[] = Object.keys(config).reduce((acc, adapter) => {
log.debug("external adapter installed buttons", adapter, adapterVisibilityMap[adapter]);
if (![WALLET_ADAPTERS.WALLET_CONNECT_V2].includes(adapter) && !config[adapter].isInjected && adapterVisibilityMap[adapter]) {
acc.push({
name: adapter,
Expand All @@ -143,21 +152,25 @@ export default function ExternalWallet(props: ExternalWalletsProps) {
}
return acc;
}, [] as ExternalButton[]);
setTotalExternalWallets(buttons.length + customAdapterButtons.length);
// sort wallets so that injected wallets come first and then ones without wallet connect and then rest
const injectedWallets = buttons.filter((button) => button.hasInjectedWallet);
const nonInjectedWallets = buttons.filter((button) => !button.hasInjectedWallet);

const filteredButtons = injectedWallets
.concat(customAdapterButtons)
.concat(nonInjectedWallets)
.filter((button) => {
if (!walletSearch) return true;
return button.displayName.toLowerCase().includes(walletSearch.toLowerCase());
})
.slice(0, 15); // show at most 15 wallets
log.debug("external buttons", buttons, filteredButtons);
setExternalButtons(filteredButtons);
const allButtons = [...defaultButtons, ...otherButtons];
const sortedButtons = [
...allButtons.filter((button) => button.hasInjectedWallet),
smgv marked this conversation as resolved.
Show resolved Hide resolved
...customAdapterButtons,
...allButtons.filter((button) => !button.hasInjectedWallet),
].filter((button) => defaultButtonKeys.has(button.name));

// Filter and set external buttons based on search input
if (walletSearch) {
const filteredList = allButtons.filter((button) => button.name.toLowerCase().includes(walletSearch.toLowerCase()));
setExternalButtons(filteredList);
} else {
setExternalButtons(sortedButtons);
}

setTotalExternalWallets(allButtons.length + customAdapterButtons.length);

log.debug("external buttons", allButtons);
} else {
const buttons: ExternalButton[] = Object.keys(config).reduce((acc, adapter) => {
log.debug("external buttons", adapter, adapterVisibilityMap[adapter]);
Expand Down Expand Up @@ -209,7 +222,7 @@ export default function ExternalWallet(props: ExternalWalletsProps) {

{/* Search */}
{isWalletDiscoveryReady && (
<div className="pt-4">
<div className="py-4">
<input
className="w-full w3a-text-field"
name="passwordless-input"
Expand All @@ -234,7 +247,7 @@ export default function ExternalWallet(props: ExternalWalletsProps) {
</div>
) : (
<div className="w3a-adapter-list-container">
<ul className="w3a-adapter-list w3ajs-wallet-adapters mt-4">
<ul className="w3a-adapter-list w3ajs-wallet-adapters">
{externalButtons.map((button) => {
return (
<li className="w3a-adapter-item w3a-adapter-item--full" key={button.name}>
Expand Down
10 changes: 8 additions & 2 deletions packages/ui/src/components/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function Image(props: ImageProps) {
height={height}
width={width}
alt={imageId}
className="image-icon"
className="image-icon object-contain rounded"
onError={({ currentTarget }) => {
if (fallbackImageId) {
// eslint-disable-next-line no-param-reassign
Expand All @@ -26,7 +26,13 @@ export default function Image(props: ImageProps) {
}}
/>
{isButton ? (
<img src={`https://images.web3auth.io/${hoverImageId}.svg`} height={height} width={width} alt={hoverImageId} className="hover-icon" />
<img
src={`https://images.web3auth.io/${hoverImageId}.svg`}
height={height}
width={width}
alt={hoverImageId}
className="hover-icon object-contain rounded"
/>
) : null}
</>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/SelfCustodyViaWeb3Auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function SelfCustodyViaWeb3Auth() {
const [t] = useTranslation(undefined, { i18n });

return (
<div className="flex items-center gap-2 justify-center p-2">
<div className="flex items-center gap-2 justify-center">
<div className="text-xs text-app-gray-300 dark:text-app-gray-500">{t("modal.footer.message-new")}</div>
<img height="16" src="https://images.web3auth.io/web3auth-footer-logo-light.svg" alt="Web3Auth Logo Light" className="h-4 block dark:hidden" />
<img height="16" src="https://images.web3auth.io/web3auth-footer-logo-dark.svg" alt="Web3Auth Logo Dark" className="h-4 hidden dark:block" />
Expand Down
13 changes: 9 additions & 4 deletions packages/ui/src/components/WalletConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import i18n from "../localeImport";
interface WalletConnectProps {
walletConnectUri: string;
logoImage?: string;
primaryColor?: string;
}

function WalletConnect(props: WalletConnectProps) {
const { walletConnectUri, logoImage } = props;
const { walletConnectUri, logoImage, primaryColor } = props;

const isDesktop = useMemo<boolean>(() => {
const browser = Bowser.getParser(window.navigator.userAgent);
Expand All @@ -36,9 +37,9 @@ function WalletConnect(props: WalletConnectProps) {
<div className="w3ajs-wallet-connect w3a-wallet-connect">
<div className="w3ajs-wallet-connect__container w3a-wallet-connect__container">
<div className="w3a-wallet-connect__container-desktop">
<div className="text-app-gray-500 dark:text-app-gray-400">{t("modal.external.walletconnect-subtitle")}</div>
{/* <div className="text-app-gray-500 dark:text-app-gray-400 text-xs">Scan the QR code with a wallet that supports WalletConnect.</div> */}
smgv marked this conversation as resolved.
Show resolved Hide resolved
<div
className="w3ajs-wallet-connect-qr w3a-wallet-connect-qr rounded-md my-2"
className="w3ajs-wallet-connect-qr w3a-wallet-connect-qr rounded-md mb-2"
tabIndex={0}
role="button"
onClick={handleCopy}
Expand All @@ -57,9 +58,13 @@ function WalletConnect(props: WalletConnectProps) {
removeQrCodeBehindLogo
logoImage={logoImage || WALLET_CONNECT_LOGO}
value={walletConnectUri}
logoHeight={32}
logoWidth={32}
logoPadding={10}
eyeColor={primaryColor}
/>
</div>
<div>{t("modal.external.walletconnect-copy")}</div>
<div className="text-xs">{t("modal.external.walletconnect-copy")}</div>
</div>
</div>
</div>
Expand Down
10 changes: 7 additions & 3 deletions packages/ui/src/css/web3auth.css
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,13 @@

/* Adapter List */
#w3a-modal div.w3a-adapter-list-container {
height: calc(100dvh - 450px);
height: 380px;
scrollbar-width: none;
overflow-y: auto;
}

#w3a-modal ul.w3a-adapter-list {
@apply grid grid-cols-6 overflow-y-auto gap-x-2 gap-y-2 h-[294px];
@apply grid grid-cols-6 overflow-y-auto gap-x-2 gap-y-2;
padding: 1px;
transition: height 0.35s;
transition-timing-function: cubic-bezier(0.92, 0, 0.74, 1);
Expand Down Expand Up @@ -612,7 +612,7 @@
}

#w3a-modal .w3a-modal__loader-social-logo {
@apply bg-app-gray-100 dark:bg-app-gray-50 w-14 h-14 flex rounded-full items-center justify-center p-1;
@apply w-14 h-14 flex rounded-full items-center justify-center p-1;
}

#w3a-modal .w3a-modal__loader-social-logo img {
Expand Down Expand Up @@ -672,6 +672,10 @@
animation: beat5 2.4s infinite;
}

.wallet-btn {
@apply !bg-app-gray-100 hover:!bg-app-gray-200 dark:!bg-app-gray-700 dark:hover:bg-app-gray-800;
}

@keyframes beat1 {
0% {
transform: scale(0);
Expand Down
Loading