Skip to content

Commit 9b930b0

Browse files
committed
refactor signInWith, provider interface, wallet selector modal
1 parent 88eb0c0 commit 9b930b0

File tree

30 files changed

+880
-513
lines changed

30 files changed

+880
-513
lines changed

apps/nextjs-example/src/app/swap/components/walletSelector/WalletItem.tsx

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
"use client";
22

3-
import { AdapterWallet } from "@aptos-labs/wallet-adapter-aggregator-core";
4-
import { useCrossChainWallet } from "@aptos-labs/cross-chain-react";
3+
import {
4+
AdapterWallet,
5+
WalletReadyState,
6+
} from "@aptos-labs/wallet-adapter-aggregator-core";
7+
import {
8+
AptosNotDetectedWallet,
9+
useCrossChainWallet,
10+
} from "@aptos-labs/cross-chain-react";
511
import { Slot } from "@radix-ui/react-slot";
612
import {
713
cloneElement,
@@ -13,10 +19,11 @@ import {
1319
useContext,
1420
} from "react";
1521
import { useToast } from "@/components/ui/use-toast";
22+
import { isRedirectable } from "@aptos-labs/wallet-adapter-core";
1623

1724
export interface WalletItemProps extends HeadlessComponentProps {
1825
/** The wallet option to be displayed. */
19-
wallet: AdapterWallet;
26+
wallet: AdapterWallet | AptosNotDetectedWallet;
2027
/** A callback to be invoked when the wallet is connected. */
2128
onConnect?: () => void;
2229
/** A callback to be invoked when the wallet is signed in. */
@@ -34,7 +41,7 @@ function useWalletItemContext(displayName: string) {
3441
}
3542

3643
const WalletItemContext = createContext<{
37-
wallet: AdapterWallet;
44+
wallet: AdapterWallet | AptosNotDetectedWallet;
3845
connectWallet: () => void;
3946
signInWithWallet: () => void;
4047
} | null>(null);
@@ -44,23 +51,28 @@ const Root = forwardRef<HTMLDivElement, WalletItemProps>(
4451
const { connect, signInWith } = useCrossChainWallet();
4552
const { toast } = useToast();
4653
const connectWallet = useCallback(async () => {
47-
await connect(wallet);
54+
await connect(wallet as AdapterWallet);
4855
onConnect?.();
4956
}, [wallet, onConnect]);
5057

5158
const signInWithWallet = useCallback(async () => {
52-
await signInWith(wallet);
59+
await signInWith({
60+
wallet: wallet as AdapterWallet,
61+
input: {
62+
statement: "address::module::function",
63+
},
64+
});
5365
onSignInWith?.();
5466
}, [wallet, onSignInWith]);
5567

56-
// const isWalletReady =
57-
// wallet.readyState === WalletReadyState.Installed ||
58-
// wallet.readyState === WalletReadyState.Loadable;
68+
if (wallet.originChain === "Aptos") {
69+
const isWalletReady = wallet.readyState === WalletReadyState.Installed;
5970

60-
// const mobileSupport =
61-
// "deeplinkProvider" in wallet && wallet.deeplinkProvider;
71+
const mobileSupport =
72+
"deeplinkProvider" in wallet && wallet.deeplinkProvider;
6273

63-
// if (!isWalletReady && isRedirectable() && !mobileSupport) return null;
74+
if (!isWalletReady && isRedirectable() && !mobileSupport) return null;
75+
}
6476

6577
const Component = asChild ? Slot : "div";
6678

apps/nextjs-example/src/app/swap/components/walletSelector/WalletSelector.tsx

Lines changed: 182 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
"use client";
22

3-
import { Copy, LogOut } from "lucide-react";
3+
import {
4+
ChevronDown,
5+
ArrowRight,
6+
Copy,
7+
LogOut,
8+
User,
9+
ArrowLeft,
10+
} from "lucide-react";
411
import { useCallback, useEffect, useState } from "react";
512

613
import { useToast } from "@/components/ui/use-toast";
7-
import { useCrossChainWallet } from "@aptos-labs/cross-chain-react";
14+
import {
15+
useCrossChainWallet,
16+
AptosNotDetectedWallet,
17+
} from "@aptos-labs/cross-chain-react";
818
import { Button } from "@/components/ui/button";
919
import {
1020
DropdownMenu,
@@ -15,6 +25,7 @@ import {
1525
import {
1626
Dialog,
1727
DialogContent,
28+
DialogHeader,
1829
DialogTitle,
1930
DialogTrigger,
2031
} from "@/components/ui/dialog";
@@ -24,6 +35,16 @@ import {
2435
AdapterWallet,
2536
WalletReadyState,
2637
} from "@aptos-labs/wallet-adapter-aggregator-core";
38+
import { isAptosConnectWallet } from "@aptos-labs/wallet-adapter-core";
39+
import { CollapsibleContent } from "@/components/ui/collapsible";
40+
import { CollapsibleTrigger } from "@/components/ui/collapsible";
41+
import { APTOS_CONNECT_ACCOUNT_URL } from "@aptos-labs/wallet-adapter-core";
42+
import {
43+
AboutAptosConnect,
44+
AboutAptosConnectEducationScreen,
45+
AptosPrivacyPolicy,
46+
} from "@aptos-labs/wallet-adapter-react";
47+
import { Collapsible } from "@/components/ui/collapsible";
2748

2849
export function WalletSelector({
2950
transactionInProgress,
@@ -67,6 +88,18 @@ export function WalletSelector({
6788
<DropdownMenuItem onSelect={copyAddress} className="gap-2">
6889
<Copy className="h-4 w-4" /> Copy address
6990
</DropdownMenuItem>
91+
{wallet && isAptosConnectWallet(wallet) && (
92+
<DropdownMenuItem asChild>
93+
<a
94+
href={APTOS_CONNECT_ACCOUNT_URL}
95+
target="_blank"
96+
rel="noopener noreferrer"
97+
className="flex gap-2"
98+
>
99+
<User className="h-4 w-4" /> Account
100+
</a>
101+
</DropdownMenuItem>
102+
)}
70103
<DropdownMenuItem onSelect={disconnect} className="gap-2">
71104
<LogOut className="h-4 w-4" /> Disconnect
72105
</DropdownMenuItem>
@@ -75,7 +108,7 @@ export function WalletSelector({
75108
) : (
76109
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
77110
<DialogTrigger asChild>
78-
<Button disabled={!sourceChain}>Connect Wallet</Button>
111+
<Button disabled={!sourceChain}>Connect a Wallet</Button>
79112
</DialogTrigger>
80113
<ConnectWalletDialog close={closeDialog} sourceChain={sourceChain} />
81114
</Dialog>
@@ -88,8 +121,15 @@ interface ConnectWalletDialogProps {
88121
}
89122

90123
function ConnectWalletDialog({ close, sourceChain }: ConnectWalletDialogProps) {
91-
const { getSolanaWallets, getAptosWallets, getEthereumWallets } =
92-
useCrossChainWallet();
124+
const {
125+
getSolanaWallets,
126+
getAptosWallets,
127+
getEthereumWallets,
128+
fetchAptosNotDetectedWallets,
129+
} = useCrossChainWallet();
130+
const [aptosNotDetectedWallets, setAptosNotDetectedWallets] = useState<
131+
ReadonlyArray<AptosNotDetectedWallet>
132+
>([]);
93133

94134
const [wallets, setWallets] = useState<ReadonlyArray<AdapterWallet>>([]);
95135

@@ -102,7 +142,9 @@ function ConnectWalletDialog({ close, sourceChain }: ConnectWalletDialogProps) {
102142
break;
103143
case "Aptos":
104144
const aptosWallets = await getAptosWallets();
145+
const notDetectedWallets = fetchAptosNotDetectedWallets();
105146
setWallets(aptosWallets);
147+
setAptosNotDetectedWallets(notDetectedWallets);
106148
break;
107149
default:
108150
const ethereumWallets = await getEthereumWallets();
@@ -112,6 +154,77 @@ function ConnectWalletDialog({ close, sourceChain }: ConnectWalletDialogProps) {
112154
getWallets();
113155
}, [sourceChain]);
114156

157+
if (sourceChain === "Aptos") {
158+
const aptosConnectWallets = wallets.filter((item) =>
159+
isAptosConnectWallet(item)
160+
);
161+
const aptosWallets = wallets.filter((item) => !isAptosConnectWallet(item));
162+
163+
return (
164+
<DialogContent className="max-h-screen overflow-auto">
165+
<AboutAptosConnect renderEducationScreen={renderEducationScreen}>
166+
<DialogHeader>
167+
<DialogTitle className="flex flex-col text-center leading-snug">
168+
<>
169+
<span>Log in or sign up</span>
170+
<span>with Social + Aptos Connect</span>
171+
</>
172+
</DialogTitle>
173+
</DialogHeader>
174+
175+
<div className="flex flex-col gap-2 pt-3">
176+
{aptosConnectWallets.map((wallet) => (
177+
<AptosConnectWalletRow
178+
key={wallet.name}
179+
wallet={wallet}
180+
onConnect={close}
181+
/>
182+
))}
183+
<p className="flex gap-1 justify-center items-center text-muted-foreground text-sm">
184+
Learn more about{" "}
185+
<AboutAptosConnect.Trigger className="flex gap-1 py-3 items-center text-foreground">
186+
Aptos Connect <ArrowRight size={16} />
187+
</AboutAptosConnect.Trigger>
188+
</p>
189+
<AptosPrivacyPolicy className="flex flex-col items-center py-1">
190+
<p className="text-xs leading-5">
191+
<AptosPrivacyPolicy.Disclaimer />{" "}
192+
<AptosPrivacyPolicy.Link className="text-muted-foreground underline underline-offset-4" />
193+
<span className="text-muted-foreground">.</span>
194+
</p>
195+
<AptosPrivacyPolicy.PoweredBy className="flex gap-1.5 items-center text-xs leading-5 text-muted-foreground" />
196+
</AptosPrivacyPolicy>
197+
<div className="flex items-center gap-3 pt-4 text-muted-foreground">
198+
<div className="h-px w-full bg-secondary" />
199+
Or
200+
<div className="h-px w-full bg-secondary" />
201+
</div>
202+
</div>
203+
204+
<div className="flex flex-col gap-3 pt-3">
205+
{aptosWallets.map((wallet) => (
206+
<WalletRow key={wallet.name} wallet={wallet} onConnect={close} />
207+
))}
208+
{!!aptosNotDetectedWallets.length && (
209+
<Collapsible className="flex flex-col gap-3">
210+
<CollapsibleTrigger asChild>
211+
<Button size="sm" variant="ghost" className="gap-2">
212+
More wallets <ChevronDown />
213+
</Button>
214+
</CollapsibleTrigger>
215+
<CollapsibleContent className="flex flex-col gap-3">
216+
{aptosNotDetectedWallets.map((wallet) => (
217+
<WalletRow key={wallet.name} wallet={wallet} />
218+
))}
219+
</CollapsibleContent>
220+
</Collapsible>
221+
)}
222+
</div>
223+
</AboutAptosConnect>
224+
</DialogContent>
225+
);
226+
}
227+
115228
return (
116229
<DialogContent className="max-h-screen overflow-auto">
117230
<DialogTitle className="flex flex-col text-center leading-snug">
@@ -132,7 +245,7 @@ function ConnectWalletDialog({ close, sourceChain }: ConnectWalletDialogProps) {
132245
}
133246

134247
interface WalletRowProps {
135-
wallet: AdapterWallet;
248+
wallet: AdapterWallet | AptosNotDetectedWallet;
136249
onConnect?: () => void;
137250
onSignInWith?: () => void;
138251
}
@@ -167,3 +280,66 @@ function WalletRow({ wallet, onConnect, onSignInWith }: WalletRowProps) {
167280
</WalletItem>
168281
);
169282
}
283+
284+
function AptosConnectWalletRow({ wallet, onConnect }: WalletRowProps) {
285+
return (
286+
<WalletItem wallet={wallet} onConnect={onConnect}>
287+
<WalletItem.ConnectButton asChild>
288+
<Button size="lg" variant="outline" className="w-full gap-4">
289+
<WalletItem.Icon className="h-5 w-5" />
290+
<WalletItem.Name className="text-base font-normal" />
291+
</Button>
292+
</WalletItem.ConnectButton>
293+
</WalletItem>
294+
);
295+
}
296+
297+
function renderEducationScreen(screen: AboutAptosConnectEducationScreen) {
298+
return (
299+
<>
300+
<DialogHeader className="grid grid-cols-[1fr_4fr_1fr] items-center space-y-0">
301+
<Button variant="ghost" size="icon" onClick={screen.cancel}>
302+
<ArrowLeft />
303+
</Button>
304+
<DialogTitle className="leading-snug text-base text-center">
305+
About Aptos Connect
306+
</DialogTitle>
307+
</DialogHeader>
308+
309+
<div className="flex h-[162px] pb-3 items-end justify-center">
310+
<screen.Graphic />
311+
</div>
312+
<div className="flex flex-col gap-2 text-center pb-4">
313+
<screen.Title className="text-xl" />
314+
<screen.Description className="text-sm text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a]:text-foreground" />
315+
</div>
316+
317+
<div className="grid grid-cols-3 items-center">
318+
<Button
319+
size="sm"
320+
variant="ghost"
321+
onClick={screen.back}
322+
className="justify-self-start"
323+
>
324+
Back
325+
</Button>
326+
<div className="flex items-center gap-2 place-self-center">
327+
{screen.screenIndicators.map((ScreenIndicator, i) => (
328+
<ScreenIndicator key={i} className="py-4">
329+
<div className="h-0.5 w-6 transition-colors bg-muted [[data-active]>&]:bg-foreground" />
330+
</ScreenIndicator>
331+
))}
332+
</div>
333+
<Button
334+
size="sm"
335+
variant="ghost"
336+
onClick={screen.next}
337+
className="gap-2 justify-self-end"
338+
>
339+
{screen.screenIndex === screen.totalScreens - 1 ? "Finish" : "Next"}
340+
<ArrowRight size={16} />
341+
</Button>
342+
</div>
343+
</>
344+
);
345+
}

0 commit comments

Comments
 (0)