Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
diff --git a/lib/cjs/WalletProvider.js b/lib/cjs/WalletProvider.js
index 9c3d07cabf94c064cf9750480a77a856ab799fda..9e7f01bd258288fe6705190842232f0c3788c619 100644
--- a/lib/cjs/WalletProvider.js
+++ b/lib/cjs/WalletProvider.js
@@ -144,26 +144,30 @@ function WalletProvider({ children, wallets: adapters, autoConnect, localStorage
});
}, [autoConnect, adapter]);
const isUnloadingRef = (0, react_1.useRef)(false);
- (0, react_1.useEffect)(() => {
- if (walletName === wallet_adapter_mobile_1.SolanaMobileWalletAdapterWalletName && getIsMobile(adaptersWithStandardAdapters)) {
- isUnloadingRef.current = false;
- return;
- }
- function handleBeforeUnload() {
- isUnloadingRef.current = true;
- }
- /**
- * Some wallets fire disconnection events when the window unloads. Since there's no way to
- * distinguish between a disconnection event received because a user initiated it, and one
- * that was received because they've closed the window, we have to track window unload
- * events themselves. Downstream components use this information to decide whether to act
- * upon or drop wallet events and errors.
- */
- window.addEventListener('beforeunload', handleBeforeUnload);
- return () => {
- window.removeEventListener('beforeunload', handleBeforeUnload);
- };
- }, [adaptersWithStandardAdapters, walletName]);
+ // beforeunload event removed to avoid bug with Chrome on Android
+ // We also only except to handle the MetaMask solana wallet standard provider
+ // which does not emit a disconnect event when the window is unloaded which
+ // the commented code block was trying to handle.
+ // (0, react_1.useEffect)(() => {
+ // if (walletName === wallet_adapter_mobile_1.SolanaMobileWalletAdapterWalletName && getIsMobile(adaptersWithStandardAdapters)) {
+ // isUnloadingRef.current = false;
+ // return;
+ // }
+ // function handleBeforeUnload() {
+ // isUnloadingRef.current = true;
+ // }
+ // /**
+ // * Some wallets fire disconnection events when the window unloads. Since there's no way to
+ // * distinguish between a disconnection event received because a user initiated it, and one
+ // * that was received because they've closed the window, we have to track window unload
+ // * events themselves. Downstream components use this information to decide whether to act
+ // * upon or drop wallet events and errors.
+ // */
+ // window.addEventListener('beforeunload', handleBeforeUnload);
+ // return () => {
+ // window.removeEventListener('beforeunload', handleBeforeUnload);
+ // };
+ // }, [adaptersWithStandardAdapters, walletName]);
const handleConnectError = (0, react_1.useCallback)(() => {
if (adapter) {
// If any error happens while connecting, unset the adapter.
diff --git a/lib/esm/WalletProvider.js b/lib/esm/WalletProvider.js
index d5dcd36332ead1ede05424537577158a033fa2f0..6eb1042aad4f52bf331023551dcbbc8b5e98877c 100644
--- a/lib/esm/WalletProvider.js
+++ b/lib/esm/WalletProvider.js
@@ -95,26 +95,30 @@ export function WalletProvider({ children, wallets: adapters, autoConnect, local
};
}, [autoConnect, adapter]);
const isUnloadingRef = useRef(false);
- useEffect(() => {
- if (walletName === SolanaMobileWalletAdapterWalletName && getIsMobile(adaptersWithStandardAdapters)) {
- isUnloadingRef.current = false;
- return;
- }
- function handleBeforeUnload() {
- isUnloadingRef.current = true;
- }
- /**
- * Some wallets fire disconnection events when the window unloads. Since there's no way to
- * distinguish between a disconnection event received because a user initiated it, and one
- * that was received because they've closed the window, we have to track window unload
- * events themselves. Downstream components use this information to decide whether to act
- * upon or drop wallet events and errors.
- */
- window.addEventListener('beforeunload', handleBeforeUnload);
- return () => {
- window.removeEventListener('beforeunload', handleBeforeUnload);
- };
- }, [adaptersWithStandardAdapters, walletName]);
+ // beforeunload event removed to avoid bug with Chrome on Android
+ // We also only except to handle the MetaMask solana wallet standard provider
+ // which does not emit a disconnect event when the window is unloaded which
+ // the commented code block was trying to handle.
+ // useEffect(() => {
+ // if (walletName === SolanaMobileWalletAdapterWalletName && getIsMobile(adaptersWithStandardAdapters)) {
+ // isUnloadingRef.current = false;
+ // return;
+ // }
+ // function handleBeforeUnload() {
+ // isUnloadingRef.current = true;
+ // }
+ // /**
+ // * Some wallets fire disconnection events when the window unloads. Since there's no way to
+ // * distinguish between a disconnection event received because a user initiated it, and one
+ // * that was received because they've closed the window, we have to track window unload
+ // * events themselves. Downstream components use this information to decide whether to act
+ // * upon or drop wallet events and errors.
+ // */
+ // window.addEventListener('beforeunload', handleBeforeUnload);
+ // return () => {
+ // window.removeEventListener('beforeunload', handleBeforeUnload);
+ // };
+ // }, [adaptersWithStandardAdapters, walletName]);
const handleConnectError = useCallback(() => {
if (adapter) {
// If any error happens while connecting, unset the adapter.
diff --git a/src/WalletProvider.tsx b/src/WalletProvider.tsx
index 7d4723ef7877ed1c2da3bd57f74ec7b12743e085..601470de23a877232ce11262cca1758990e64425 100644
--- a/src/WalletProvider.tsx
+++ b/src/WalletProvider.tsx
@@ -124,26 +124,30 @@ export function WalletProvider({
};
}, [autoConnect, adapter]);
const isUnloadingRef = useRef(false);
- useEffect(() => {
- if (walletName === SolanaMobileWalletAdapterWalletName && getIsMobile(adaptersWithStandardAdapters)) {
- isUnloadingRef.current = false;
- return;
- }
- function handleBeforeUnload() {
- isUnloadingRef.current = true;
- }
- /**
- * Some wallets fire disconnection events when the window unloads. Since there's no way to
- * distinguish between a disconnection event received because a user initiated it, and one
- * that was received because they've closed the window, we have to track window unload
- * events themselves. Downstream components use this information to decide whether to act
- * upon or drop wallet events and errors.
- */
- window.addEventListener('beforeunload', handleBeforeUnload);
- return () => {
- window.removeEventListener('beforeunload', handleBeforeUnload);
- };
- }, [adaptersWithStandardAdapters, walletName]);
+ // beforeunload event removed to avoid bug with Chrome on Android
+ // We also only except to handle the MetaMask solana wallet standard provider
+ // which does not emit a disconnect event when the window is unloaded which
+ // the commented code block was trying to handle.
+ // useEffect(() => {
+ // if (walletName === SolanaMobileWalletAdapterWalletName && getIsMobile(adaptersWithStandardAdapters)) {
+ // isUnloadingRef.current = false;
+ // return;
+ // }
+ // function handleBeforeUnload() {
+ // isUnloadingRef.current = true;
+ // }
+ // /**
+ // * Some wallets fire disconnection events when the window unloads. Since there's no way to
+ // * distinguish between a disconnection event received because a user initiated it, and one
+ // * that was received because they've closed the window, we have to track window unload
+ // * events themselves. Downstream components use this information to decide whether to act
+ // * upon or drop wallet events and errors.
+ // */
+ // window.addEventListener('beforeunload', handleBeforeUnload);
+ // return () => {
+ // window.removeEventListener('beforeunload', handleBeforeUnload);
+ // };
+ // }, [adaptersWithStandardAdapters, walletName]);
const handleConnectError = useCallback(() => {
if (adapter) {
// If any error happens while connecting, unset the adapter.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"pre-push": "yarn lint"
},
"resolutions": {
"bs58": "4.0.1"
"bs58": "4.0.1",
"@solana/wallet-adapter-react@npm:^0.15.39": "patch:@solana/wallet-adapter-react@npm%3A0.15.39#~/.yarn/patches/@solana-wallet-adapter-react-npm-0.15.39-86277fdcc0.patch"
},
"devDependencies": {
"@babel/core": "^7.28.4",
Expand Down
6 changes: 6 additions & 0 deletions playground/browser-playground/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Add disconnect buttons to cards ([#157](https://github.com/MetaMask/connect-monorepo/pull/157))
- Add `data-testid` attributes to Solana components ([#174](https://github.com/MetaMask/connect-monorepo/pull/174))
- Add `data-testid` attributes to Legacy EVM and Wagmi disconnect buttons ([#174](https://github.com/MetaMask/connect-monorepo/pull/174))

### Changed

- Patch `@solana/wallet-adapter-react` to work with android native browser ([#174](https://github.com/MetaMask/connect-monorepo/pull/174))

### Changed

Expand Down
2 changes: 1 addition & 1 deletion playground/browser-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"@metamask/utils": "^11.8.1",
"@open-rpc/meta-schema": "^1.14.9",
"@open-rpc/schema-utils-js": "^2.0.5",
"@solana/wallet-adapter-react": "^0.15.35",
"@solana/wallet-adapter-react": "patch:@solana/wallet-adapter-react@npm%3A0.15.39#~/.yarn/patches/@solana-wallet-adapter-react-npm-0.15.39-86277fdcc0.patch",
"@solana/wallet-adapter-react-ui": "^0.9.35",
"@solana/wallet-standard-chains": "^1.1.1",
"@solana/web3.js": "^1.98.0",
Expand Down
3 changes: 2 additions & 1 deletion playground/browser-playground/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ function App() {

const {
connected: solanaConnected,
connecting: solanaConnecting,
disconnecting: solanaDisconnecting,
publicKey: solanaPublicKey,
wallets,
select,
connect: solanaConnect,
} = useWallet();

const handleCheckboxChange = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export function LegacyEVMCard({
</h3>
<button
type="button"
data-testid={TEST_IDS.legacyEvm.btnDisconnect}
onClick={disconnect}
className="bg-red-500 text-white px-3 py-1 rounded text-sm hover:bg-red-600 transition-colors"
>
Expand Down
26 changes: 16 additions & 10 deletions playground/browser-playground/src/components/SolanaWalletCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { WalletMultiButton } from '@solana/wallet-adapter-react-ui';
import { PublicKey, SystemProgram, Transaction, LAMPORTS_PER_SOL } from '@solana/web3.js';
import { useCallback, useState } from 'react';
import { TEST_IDS } from '@metamask/playground-ui';

/**
* SolanaWalletCard component displays Solana wallet connection status
Expand Down Expand Up @@ -111,15 +112,16 @@ export const SolanaWalletCard: React.FC = () => {
}, [publicKey, sendTransaction, connection]);

return (
<div className="bg-white rounded-lg p-6 shadow-sm border border-gray-200">
<div data-testid={TEST_IDS.solana.card} className="bg-white rounded-lg p-6 shadow-sm border border-gray-200">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-gray-800 flex items-center gap-2">
<h3 data-testid={TEST_IDS.solana.title} className="text-lg font-semibold text-gray-800 flex items-center gap-2">
<span className="text-2xl">☀️</span>
Solana Wallet
</h3>
{connected && (
<button
type="button"
data-testid={TEST_IDS.solana.btnDisconnect}
onClick={disconnect}
className="bg-red-500 text-white px-3 py-1 rounded text-sm hover:bg-red-600 transition-colors"
>
Expand All @@ -130,7 +132,7 @@ export const SolanaWalletCard: React.FC = () => {

<div className="space-y-4">
{/* Connection Status */}
<div className="flex items-center gap-2">
<div data-testid={TEST_IDS.solana.status} className="flex items-center gap-2">
<span
className={`w-2 h-2 rounded-full ${connected ? 'bg-green-500' : 'bg-gray-400'}`}
/>
Expand All @@ -141,34 +143,36 @@ export const SolanaWalletCard: React.FC = () => {

{/* Wallet Address */}
{publicKey && (
<div className="bg-gray-50 rounded p-3">
<div data-testid={TEST_IDS.solana.addressContainer} className="bg-gray-50 rounded p-3">
<p className="text-xs text-gray-500 mb-1">Address</p>
<p className="text-sm font-mono break-all">{publicKey.toBase58()}</p>
</div>
)}

{/* Wallet Buttons */}
{!connected && (
<div className="flex gap-2 flex-wrap">
<div data-testid={TEST_IDS.solana.btnConnect} className="flex gap-2 flex-wrap">
<WalletMultiButton className="!bg-blue-500 hover:!bg-blue-600" />
</div>
)}

{/* Sign Message Section */}
{connected && (
<div className="border-t pt-4 mt-4">
<div data-testid={TEST_IDS.solana.signMessageSection} className="border-t pt-4 mt-4">
<h4 className="text-sm font-medium text-gray-700 mb-2">
Sign Message
</h4>
<input
type="text"
data-testid={TEST_IDS.solana.inputMessage}
value={message}
onChange={(e) => setMessage(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded text-sm mb-2"
placeholder="Enter message to sign"
/>
<button
type="button"
data-testid={TEST_IDS.solana.btnSignMessage}
onClick={handleSignMessage}
disabled={loading || !signMessage}
className="bg-purple-500 text-white px-4 py-2 rounded text-sm hover:bg-purple-600 disabled:bg-gray-400 disabled:cursor-not-allowed"
Expand All @@ -177,7 +181,7 @@ export const SolanaWalletCard: React.FC = () => {
</button>

{signedMessage && (
<div className="mt-3 bg-green-50 rounded p-3">
<div data-testid={TEST_IDS.solana.signedMessageResult} className="mt-3 bg-green-50 rounded p-3">
<p className="text-xs text-green-700 mb-1">Signed Message</p>
<p className="text-xs font-mono break-all text-green-800">
{signedMessage}
Expand All @@ -189,13 +193,14 @@ export const SolanaWalletCard: React.FC = () => {

{/* Transaction Section */}
{connected && (
<div className="border-t pt-4 mt-4">
<div data-testid={TEST_IDS.solana.transactionsSection} className="border-t pt-4 mt-4">
<h4 className="text-sm font-medium text-gray-700 mb-2">
Transactions
</h4>
<div className="flex gap-2 flex-wrap">
<button
type="button"
data-testid={TEST_IDS.solana.btnSignTransaction}
onClick={handleSignTransaction}
disabled={loading || !signTransaction}
className="bg-orange-500 text-white px-4 py-2 rounded text-sm hover:bg-orange-600 disabled:bg-gray-400 disabled:cursor-not-allowed"
Expand All @@ -204,6 +209,7 @@ export const SolanaWalletCard: React.FC = () => {
</button>
<button
type="button"
data-testid={TEST_IDS.solana.btnSendTransaction}
onClick={handleSendTransaction}
disabled={loading || !sendTransaction}
className="bg-green-500 text-white px-4 py-2 rounded text-sm hover:bg-green-600 disabled:bg-gray-400 disabled:cursor-not-allowed"
Expand All @@ -213,7 +219,7 @@ export const SolanaWalletCard: React.FC = () => {
</div>

{transactionSignature && (
<div className="mt-3 bg-blue-50 rounded p-3">
<div data-testid={TEST_IDS.solana.transactionSignatureResult} className="mt-3 bg-blue-50 rounded p-3">
<p className="text-xs text-blue-700 mb-1">Transaction Signature</p>
<p className="text-xs font-mono break-all text-blue-800">
{transactionSignature}
Expand All @@ -225,7 +231,7 @@ export const SolanaWalletCard: React.FC = () => {

{/* Error Display */}
{error && (
<div className="bg-red-50 border border-red-200 rounded p-3">
<div data-testid={TEST_IDS.solana.errorContainer} className="bg-red-50 border border-red-200 rounded p-3">
<p className="text-sm text-red-700">{error}</p>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export function WagmiCard() {
</h3>
<button
type="button"
data-testid={TEST_IDS.wagmi.btnDisconnect}
onClick={() => disconnect()}
className="bg-red-500 text-white px-3 py-1 rounded text-sm hover:bg-red-600 transition-colors"
>
Expand Down
23 changes: 23 additions & 0 deletions playground/playground-ui/src/testIds/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export const TEST_IDS = {
legacyEvm: {
card: 'legacy-evm-card',
title: 'legacy-evm-title',
btnDisconnect: 'legacy-evm-btn-disconnect',

// Status display
chainIdLabel: 'legacy-evm-chain-id-label',
Expand Down Expand Up @@ -170,6 +171,7 @@ export const TEST_IDS = {
wagmi: {
card: 'wagmi-card',
title: 'wagmi-title',
btnDisconnect: 'wagmi-btn-disconnect',

// Status display
chainIdLabel: 'wagmi-chain-id-label',
Expand Down Expand Up @@ -209,6 +211,27 @@ export const TEST_IDS = {
connectorChainId: 'wagmi-connector-chain-id',
},

// ============================================
// SOLANA CARD
// ============================================
solana: {
card: 'solana-card',
title: 'solana-title',
btnConnect: 'solana-btn-connect',
btnDisconnect: 'solana-btn-disconnect',
status: 'solana-status',
addressContainer: 'solana-address-container',
signMessageSection: 'solana-section-sign-message',
inputMessage: 'solana-input-message',
btnSignMessage: 'solana-btn-sign-message',
signedMessageResult: 'solana-signed-message-result',
transactionsSection: 'solana-section-transactions',
btnSignTransaction: 'solana-btn-sign-transaction',
btnSendTransaction: 'solana-btn-send-transaction',
transactionSignatureResult: 'solana-transaction-signature-result',
errorContainer: 'solana-error-container',
},

// ============================================
// WALLET LIST (Browser only)
// ============================================
Expand Down
Loading
Loading