@reown/appkit-react-native 0.0.0-chore-added-import-20251002170458 → 0.0.0-chore-qr-borders-20251104183806
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/AppKit.js +32 -17
- package/lib/commonjs/AppKit.js.map +1 -1
- package/lib/commonjs/hooks/useAccount.js +65 -2
- package/lib/commonjs/hooks/useAccount.js.map +1 -1
- package/lib/commonjs/hooks/useProvider.js +20 -8
- package/lib/commonjs/hooks/useProvider.js.map +1 -1
- package/lib/commonjs/modal/w3m-modal/styles.js +2 -1
- package/lib/commonjs/modal/w3m-modal/styles.js.map +1 -1
- package/lib/commonjs/partials/w3m-all-wallets-list/components/WalletList.js +62 -25
- package/lib/commonjs/partials/w3m-all-wallets-list/components/WalletList.js.map +1 -1
- package/lib/commonjs/partials/w3m-all-wallets-list/index.js +1 -1
- package/lib/commonjs/partials/w3m-all-wallets-list/index.js.map +1 -1
- package/lib/commonjs/partials/w3m-all-wallets-search/index.js +1 -0
- package/lib/commonjs/partials/w3m-all-wallets-search/index.js.map +1 -1
- package/lib/commonjs/partials/w3m-connecting-qrcode/index.js +5 -1
- package/lib/commonjs/partials/w3m-connecting-qrcode/index.js.map +1 -1
- package/lib/commonjs/partials/w3m-send-input-token/index.js +6 -3
- package/lib/commonjs/partials/w3m-send-input-token/index.js.map +1 -1
- package/lib/commonjs/partials/w3m-swap-input/index.js +6 -3
- package/lib/commonjs/partials/w3m-swap-input/index.js.map +1 -1
- package/lib/commonjs/views/w3m-account-default-view/index.js +2 -1
- package/lib/commonjs/views/w3m-account-default-view/index.js.map +1 -1
- package/lib/commonjs/views/w3m-connect-view/components/all-wallet-list.js +28 -3
- package/lib/commonjs/views/w3m-connect-view/components/all-wallet-list.js.map +1 -1
- package/lib/commonjs/views/w3m-onramp-settings-view/index.js +2 -0
- package/lib/commonjs/views/w3m-onramp-settings-view/index.js.map +1 -1
- package/lib/commonjs/views/w3m-onramp-view/index.js +3 -2
- package/lib/commonjs/views/w3m-onramp-view/index.js.map +1 -1
- package/lib/commonjs/views/w3m-swap-view/components/select-token-modal/index.js +2 -1
- package/lib/commonjs/views/w3m-swap-view/components/select-token-modal/index.js.map +1 -1
- package/lib/commonjs/views/w3m-swap-view/index.js +4 -2
- package/lib/commonjs/views/w3m-swap-view/index.js.map +1 -1
- package/lib/commonjs/views/w3m-wallet-send-view/index.js +2 -1
- package/lib/commonjs/views/w3m-wallet-send-view/index.js.map +1 -1
- package/lib/module/AppKit.js +32 -17
- package/lib/module/AppKit.js.map +1 -1
- package/lib/module/hooks/useAccount.js +66 -2
- package/lib/module/hooks/useAccount.js.map +1 -1
- package/lib/module/hooks/useProvider.js +21 -9
- package/lib/module/hooks/useProvider.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/modal/w3m-modal/styles.js +2 -1
- package/lib/module/modal/w3m-modal/styles.js.map +1 -1
- package/lib/module/partials/w3m-all-wallets-list/components/WalletList.js +63 -26
- package/lib/module/partials/w3m-all-wallets-list/components/WalletList.js.map +1 -1
- package/lib/module/partials/w3m-all-wallets-list/index.js +1 -1
- package/lib/module/partials/w3m-all-wallets-list/index.js.map +1 -1
- package/lib/module/partials/w3m-all-wallets-search/index.js +1 -0
- package/lib/module/partials/w3m-all-wallets-search/index.js.map +1 -1
- package/lib/module/partials/w3m-connecting-qrcode/index.js +5 -1
- package/lib/module/partials/w3m-connecting-qrcode/index.js.map +1 -1
- package/lib/module/partials/w3m-send-input-token/index.js +6 -3
- package/lib/module/partials/w3m-send-input-token/index.js.map +1 -1
- package/lib/module/partials/w3m-swap-input/index.js +6 -3
- package/lib/module/partials/w3m-swap-input/index.js.map +1 -1
- package/lib/module/views/w3m-account-default-view/index.js +2 -1
- package/lib/module/views/w3m-account-default-view/index.js.map +1 -1
- package/lib/module/views/w3m-connect-view/components/all-wallet-list.js +29 -4
- package/lib/module/views/w3m-connect-view/components/all-wallet-list.js.map +1 -1
- package/lib/module/views/w3m-onramp-settings-view/index.js +2 -0
- package/lib/module/views/w3m-onramp-settings-view/index.js.map +1 -1
- package/lib/module/views/w3m-onramp-view/index.js +3 -2
- package/lib/module/views/w3m-onramp-view/index.js.map +1 -1
- package/lib/module/views/w3m-swap-view/components/select-token-modal/index.js +2 -1
- package/lib/module/views/w3m-swap-view/components/select-token-modal/index.js.map +1 -1
- package/lib/module/views/w3m-swap-view/index.js +4 -2
- package/lib/module/views/w3m-swap-view/index.js.map +1 -1
- package/lib/module/views/w3m-wallet-send-view/index.js +2 -1
- package/lib/module/views/w3m-wallet-send-view/index.js.map +1 -1
- package/lib/typescript/AppKit.d.ts +10 -3
- package/lib/typescript/AppKit.d.ts.map +1 -1
- package/lib/typescript/AppKitContext.d.ts +1 -1
- package/lib/typescript/hooks/useAccount.d.ts +57 -33
- package/lib/typescript/hooks/useAccount.d.ts.map +1 -1
- package/lib/typescript/hooks/useAppKitEvents.d.ts +13 -0
- package/lib/typescript/hooks/useAppKitEvents.d.ts.map +1 -1
- package/lib/typescript/hooks/useProvider.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/modal/w3m-modal/styles.d.ts +1 -0
- package/lib/typescript/modal/w3m-modal/styles.d.ts.map +1 -1
- package/lib/typescript/partials/w3m-all-wallets-list/components/WalletList.d.ts +2 -1
- package/lib/typescript/partials/w3m-all-wallets-list/components/WalletList.d.ts.map +1 -1
- package/lib/typescript/partials/w3m-all-wallets-search/index.d.ts.map +1 -1
- package/lib/typescript/partials/w3m-connecting-qrcode/index.d.ts.map +1 -1
- package/lib/typescript/partials/w3m-send-input-token/index.d.ts +2 -1
- package/lib/typescript/partials/w3m-send-input-token/index.d.ts.map +1 -1
- package/lib/typescript/partials/w3m-swap-input/index.d.ts +2 -1
- package/lib/typescript/partials/w3m-swap-input/index.d.ts.map +1 -1
- package/lib/typescript/views/w3m-account-default-view/index.d.ts.map +1 -1
- package/lib/typescript/views/w3m-connect-view/components/all-wallet-list.d.ts.map +1 -1
- package/lib/typescript/views/w3m-onramp-settings-view/index.d.ts.map +1 -1
- package/lib/typescript/views/w3m-onramp-view/index.d.ts.map +1 -1
- package/lib/typescript/views/w3m-swap-view/index.d.ts.map +1 -1
- package/lib/typescript/views/w3m-wallet-send-view/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/AppKit.ts +40 -18
- package/src/hooks/useAccount.ts +89 -3
- package/src/hooks/useProvider.ts +15 -6
- package/src/index.ts +1 -1
- package/src/modal/w3m-modal/styles.ts +2 -1
- package/src/partials/w3m-all-wallets-list/components/WalletList.tsx +73 -25
- package/src/partials/w3m-all-wallets-list/index.tsx +1 -1
- package/src/partials/w3m-all-wallets-search/index.tsx +8 -1
- package/src/partials/w3m-connecting-qrcode/index.tsx +10 -1
- package/src/partials/w3m-send-input-token/index.tsx +5 -1
- package/src/partials/w3m-swap-input/index.tsx +5 -1
- package/src/views/w3m-account-default-view/index.tsx +6 -1
- package/src/views/w3m-connect-view/components/all-wallet-list.tsx +40 -11
- package/src/views/w3m-onramp-settings-view/index.tsx +7 -1
- package/src/views/w3m-onramp-view/index.tsx +3 -2
- package/src/views/w3m-swap-view/components/select-token-modal/index.tsx +1 -1
- package/src/views/w3m-swap-view/index.tsx +2 -0
- package/src/views/w3m-wallet-send-view/index.tsx +1 -0
package/src/AppKit.ts
CHANGED
|
@@ -214,6 +214,7 @@ export class AppKit {
|
|
|
214
214
|
SendController.resetState();
|
|
215
215
|
OnRampController.resetState();
|
|
216
216
|
WcController.resetState();
|
|
217
|
+
EventsController.resetState();
|
|
217
218
|
|
|
218
219
|
if (ConnectionsController.state.activeNamespace === undefined) {
|
|
219
220
|
ConnectionsController.setActiveNamespace(
|
|
@@ -244,7 +245,7 @@ export class AppKit {
|
|
|
244
245
|
/**
|
|
245
246
|
* Returns the provider for a given namespace.
|
|
246
247
|
* @param namespace - The namespace to get the provider for.
|
|
247
|
-
* @returns The provider for the given namespace.
|
|
248
|
+
* @returns The provider for the given namespace, or null if not available or not yet initialized.
|
|
248
249
|
*/
|
|
249
250
|
getProvider<T extends Provider>(namespace?: string): T | null {
|
|
250
251
|
const activeNamespace = namespace ?? ConnectionsController.state.activeNamespace;
|
|
@@ -255,36 +256,64 @@ export class AppKit {
|
|
|
255
256
|
);
|
|
256
257
|
if (!connection || !connection.adapter || !connection.adapter.connector) return null;
|
|
257
258
|
|
|
258
|
-
|
|
259
|
+
try {
|
|
260
|
+
return connection.adapter.connector.getProvider() as T | null;
|
|
261
|
+
} catch (error) {
|
|
262
|
+
// Provider not initialized yet during session restoration
|
|
263
|
+
// This can happen on app restart when restoring a previous connection
|
|
264
|
+
LogController.sendError(error, 'AppKit.ts', 'getProvider');
|
|
265
|
+
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
259
268
|
}
|
|
260
269
|
|
|
261
270
|
getNetworks() {
|
|
262
271
|
return this.networks;
|
|
263
272
|
}
|
|
264
273
|
|
|
265
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Switches to a different network.
|
|
276
|
+
* @param network - Either an AppKitNetwork object or a CAIP network ID string (e.g., 'eip155:1')
|
|
277
|
+
* @throws {Error} When the network is not found in configured networks
|
|
278
|
+
* @throws {Error} When no active adapter is available (only when connected)
|
|
279
|
+
* @returns Promise that resolves when the network switch is complete
|
|
280
|
+
*/
|
|
281
|
+
async switchNetwork(network: AppKitNetwork | CaipNetworkId): Promise<void> {
|
|
266
282
|
const { isConnected } = ConnectionsController.state;
|
|
267
283
|
|
|
284
|
+
const appKitNetwork =
|
|
285
|
+
typeof network === 'string' ? this.networks.find(n => n.caipNetworkId === network) : network;
|
|
286
|
+
|
|
287
|
+
if (!appKitNetwork) {
|
|
288
|
+
const error = new Error(`Network not found: ${network}`);
|
|
289
|
+
LogController.sendError(`Network not found: ${network}`, 'AppKit.ts', 'switchNetwork');
|
|
290
|
+
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
|
|
268
294
|
if (!isConnected) {
|
|
269
|
-
OptionsController.setDefaultNetwork(
|
|
295
|
+
OptionsController.setDefaultNetwork(appKitNetwork);
|
|
270
296
|
|
|
271
|
-
return
|
|
297
|
+
return;
|
|
272
298
|
}
|
|
273
299
|
|
|
274
|
-
const adapter = this.getAdapterByNamespace(
|
|
300
|
+
const adapter = this.getAdapterByNamespace(appKitNetwork.chainNamespace);
|
|
275
301
|
if (!adapter) throw new Error('No active adapter');
|
|
276
302
|
|
|
277
|
-
await adapter.switchNetwork(
|
|
303
|
+
await adapter.switchNetwork(appKitNetwork);
|
|
278
304
|
|
|
279
305
|
EventsController.sendEvent({
|
|
280
306
|
type: 'track',
|
|
281
307
|
event: 'SWITCH_NETWORK',
|
|
282
308
|
properties: {
|
|
283
|
-
network:
|
|
309
|
+
network: appKitNetwork.caipNetworkId
|
|
284
310
|
}
|
|
285
311
|
});
|
|
286
312
|
|
|
287
|
-
ConnectionsController.setActiveNetwork(
|
|
313
|
+
ConnectionsController.setActiveNetwork(
|
|
314
|
+
appKitNetwork.chainNamespace,
|
|
315
|
+
appKitNetwork.caipNetworkId
|
|
316
|
+
);
|
|
288
317
|
}
|
|
289
318
|
|
|
290
319
|
open(options?: AppKitOpenOptions) {
|
|
@@ -308,6 +337,7 @@ export class AppKit {
|
|
|
308
337
|
|
|
309
338
|
RouterUtil.checkOnRampBack();
|
|
310
339
|
RouterUtil.checkSocialLoginBack();
|
|
340
|
+
EventsController.sendWalletImpressions();
|
|
311
341
|
}
|
|
312
342
|
|
|
313
343
|
back() {
|
|
@@ -634,12 +664,6 @@ export class AppKit {
|
|
|
634
664
|
const namespace = adapter.getSupportedNamespace();
|
|
635
665
|
const chain = `${namespace}:${chainId}` as CaipNetworkId;
|
|
636
666
|
|
|
637
|
-
const activeNetwork = ConnectionsController.getActiveNetworkId(namespace);
|
|
638
|
-
if (activeNetwork === chain) {
|
|
639
|
-
// No need to update the active network
|
|
640
|
-
return;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
667
|
ConnectionsController.setActiveNetwork(namespace, chain);
|
|
644
668
|
|
|
645
669
|
const connection = ConnectionsController.state.connections.get(namespace);
|
|
@@ -692,10 +716,8 @@ export class AppKit {
|
|
|
692
716
|
this.setCustomWallets(options);
|
|
693
717
|
OptionsController.setFeaturedWalletIds(options.featuredWalletIds);
|
|
694
718
|
OptionsController.setEnableAnalytics(options.enableAnalytics);
|
|
695
|
-
OptionsController.setDebug(options.debug
|
|
719
|
+
OptionsController.setDebug(options.debug);
|
|
696
720
|
|
|
697
|
-
// Initialize LogController after debug option is set
|
|
698
|
-
LogController.initialize();
|
|
699
721
|
LogController.sendInfo('AppKit initialization started', 'AppKit.ts', 'initControllers', {
|
|
700
722
|
projectId: options.projectId,
|
|
701
723
|
adapters: this.adapters.map(a => a.constructor.name),
|
package/src/hooks/useAccount.ts
CHANGED
|
@@ -1,9 +1,68 @@
|
|
|
1
1
|
/* eslint-disable valtio/state-snapshot-rule */
|
|
2
|
+
import {
|
|
3
|
+
ConnectionsController,
|
|
4
|
+
CoreHelperUtil,
|
|
5
|
+
LogController
|
|
6
|
+
} from '@reown/appkit-core-react-native';
|
|
2
7
|
import { useMemo } from 'react';
|
|
3
8
|
import { useSnapshot } from 'valtio';
|
|
4
|
-
import { ConnectionsController, CoreHelperUtil } from '@reown/appkit-core-react-native';
|
|
5
9
|
import { useAppKit } from './useAppKit';
|
|
10
|
+
import type { AccountType, AppKitNetwork } from '@reown/appkit-common-react-native';
|
|
6
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Represents a blockchain account with its associated metadata
|
|
14
|
+
*/
|
|
15
|
+
export interface Account {
|
|
16
|
+
/** The blockchain address of the account */
|
|
17
|
+
address: string;
|
|
18
|
+
/** The blockchain namespace (e.g., 'eip155' for Ethereum, 'solana' for Solana) */
|
|
19
|
+
namespace: string;
|
|
20
|
+
/** The chain ID where this account is active */
|
|
21
|
+
chainId: string;
|
|
22
|
+
/** Optional account type (e.g. 'eoa' or 'smartAccount') */
|
|
23
|
+
type?: AccountType;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Hook to access the current account state and connection information
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* This hook provides access to all connected accounts, the currently active account,
|
|
31
|
+
* connection status, and active chain information. It automatically subscribes to
|
|
32
|
+
* connection state changes via valtio.
|
|
33
|
+
*
|
|
34
|
+
* The hook parses account data from CAIP-10 format (namespace:chainId:address)
|
|
35
|
+
* and provides a normalized structure.
|
|
36
|
+
*
|
|
37
|
+
* @returns An object containing:
|
|
38
|
+
* - `allAccounts` - Array of all connected accounts across all connections
|
|
39
|
+
* - `address` - The plain address of the currently active account (without namespace or chain prefix)
|
|
40
|
+
* - `isConnected` - Boolean indicating if a wallet is currently connected
|
|
41
|
+
* - `chainId` - The ID of the currently active chain
|
|
42
|
+
* - `chain` - The full chain/network object of the currently active chain
|
|
43
|
+
* - `namespace` - The namespace of the currently active account (e.g. 'eip155', 'solana' or 'bip122')
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* function MyComponent() {
|
|
48
|
+
* const { address, isConnected, chainId, allAccounts } = useAccount();
|
|
49
|
+
*
|
|
50
|
+
* if (!isConnected) {
|
|
51
|
+
* return <Text>Not connected</Text>;
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* return (
|
|
55
|
+
* <View>
|
|
56
|
+
* <Text>Connected: {address}</Text>
|
|
57
|
+
* <Text>Chain: {chainId}</Text>
|
|
58
|
+
* <Text>Total accounts: {allAccounts.length}</Text>
|
|
59
|
+
* </View>
|
|
60
|
+
* );
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @throws Will log errors via LogController if account parsing fails
|
|
65
|
+
*/
|
|
7
66
|
export function useAccount() {
|
|
8
67
|
useAppKit(); // Use the hook for checks
|
|
9
68
|
|
|
@@ -11,9 +70,35 @@ export function useAccount() {
|
|
|
11
70
|
activeAddress: address,
|
|
12
71
|
activeNamespace,
|
|
13
72
|
connection,
|
|
73
|
+
connections,
|
|
14
74
|
networks
|
|
15
75
|
} = useSnapshot(ConnectionsController.state);
|
|
16
76
|
|
|
77
|
+
const allAccounts: Account[] = useMemo(() => {
|
|
78
|
+
return Array.from(connections.values()).flatMap(
|
|
79
|
+
_connection =>
|
|
80
|
+
_connection.accounts
|
|
81
|
+
.map(account => {
|
|
82
|
+
const [namespace, chainId, plainAddress] = account.split(':');
|
|
83
|
+
if (!plainAddress || !namespace || !chainId) {
|
|
84
|
+
LogController.sendError('Invalid account', 'useAccount.ts', 'useAccount', {
|
|
85
|
+
account
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
address: plainAddress,
|
|
93
|
+
namespace,
|
|
94
|
+
chainId,
|
|
95
|
+
type: _connection.type
|
|
96
|
+
};
|
|
97
|
+
})
|
|
98
|
+
.filter(account => account !== undefined) as Account[]
|
|
99
|
+
);
|
|
100
|
+
}, [connections]);
|
|
101
|
+
|
|
17
102
|
const activeChain = useMemo(
|
|
18
103
|
() =>
|
|
19
104
|
connection?.caipNetwork
|
|
@@ -23,10 +108,11 @@ export function useAccount() {
|
|
|
23
108
|
);
|
|
24
109
|
|
|
25
110
|
return {
|
|
111
|
+
allAccounts,
|
|
26
112
|
address: CoreHelperUtil.getPlainAddress(address),
|
|
27
113
|
isConnected: !!address,
|
|
28
|
-
chainId: activeChain?.id,
|
|
29
|
-
chain: activeChain,
|
|
114
|
+
chainId: activeChain?.id !== undefined ? String(activeChain.id) : undefined,
|
|
115
|
+
chain: activeChain as AppKitNetwork | undefined,
|
|
30
116
|
namespace: activeNamespace
|
|
31
117
|
};
|
|
32
118
|
}
|
package/src/hooks/useProvider.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable valtio/state-snapshot-rule */
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { useSnapshot } from 'valtio';
|
|
4
|
-
import { ConnectionsController } from '@reown/appkit-core-react-native';
|
|
4
|
+
import { ConnectionsController, LogController } from '@reown/appkit-core-react-native';
|
|
5
5
|
import type { Provider, ChainNamespace } from '@reown/appkit-common-react-native';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -40,12 +40,21 @@ export function useProvider(): ProviderResult {
|
|
|
40
40
|
const { connection } = useSnapshot(ConnectionsController.state);
|
|
41
41
|
|
|
42
42
|
const returnValue = useMemo(() => {
|
|
43
|
-
if (!connection)
|
|
43
|
+
if (!connection || !connection.adapter) {
|
|
44
|
+
return { provider: undefined, providerType: undefined };
|
|
45
|
+
}
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
try {
|
|
48
|
+
return {
|
|
49
|
+
provider: connection.adapter.getProvider(),
|
|
50
|
+
providerType: connection.adapter.getSupportedNamespace()
|
|
51
|
+
};
|
|
52
|
+
} catch (error) {
|
|
53
|
+
LogController.sendError(error, 'useProvider', 'useProvider');
|
|
54
|
+
|
|
55
|
+
// Provider not initialized yet during session restoration
|
|
56
|
+
return { provider: undefined, providerType: undefined };
|
|
57
|
+
}
|
|
49
58
|
}, [connection]);
|
|
50
59
|
|
|
51
60
|
return returnValue;
|
package/src/index.ts
CHANGED
|
@@ -31,7 +31,7 @@ export type { AppKitConfig } from './types';
|
|
|
31
31
|
/****** Hooks *******/
|
|
32
32
|
export { useAppKit } from './hooks/useAppKit';
|
|
33
33
|
export { useProvider } from './hooks/useProvider';
|
|
34
|
-
export { useAccount } from './hooks/useAccount';
|
|
34
|
+
export { useAccount, type Account as UseAccountReturn } from './hooks/useAccount';
|
|
35
35
|
export { useWalletInfo } from './hooks/useWalletInfo';
|
|
36
36
|
export { useAppKitEvents, useAppKitEventSubscription } from './hooks/useAppKitEvents';
|
|
37
37
|
export { useAppKitState } from './hooks/useAppKitState';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FlatList, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
|
|
1
|
+
import { FlatList, StyleSheet, type StyleProp, type ViewStyle, type ViewToken } from 'react-native';
|
|
2
2
|
import { WalletItem } from './WalletItem';
|
|
3
3
|
import {
|
|
4
4
|
CardSelectHeight,
|
|
@@ -7,8 +7,9 @@ import {
|
|
|
7
7
|
CardSelectLoader,
|
|
8
8
|
CardSelectWidth
|
|
9
9
|
} from '@reown/appkit-ui-react-native';
|
|
10
|
-
import { ApiController } from '@reown/appkit-core-react-native';
|
|
10
|
+
import { ApiController, EventsController } from '@reown/appkit-core-react-native';
|
|
11
11
|
import type { WcWallet } from '@reown/appkit-common-react-native';
|
|
12
|
+
import { useCallback, useRef } from 'react';
|
|
12
13
|
|
|
13
14
|
const imageHeaders = ApiController._getApiHeaders();
|
|
14
15
|
|
|
@@ -25,6 +26,7 @@ interface Props {
|
|
|
25
26
|
loadingItems?: number;
|
|
26
27
|
style?: StyleProp<ViewStyle>;
|
|
27
28
|
testIDKey?: string;
|
|
29
|
+
searchQuery?: string;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export function WalletList({
|
|
@@ -35,15 +37,77 @@ export function WalletList({
|
|
|
35
37
|
isLoading = false,
|
|
36
38
|
loadingItems = 20,
|
|
37
39
|
testIDKey,
|
|
38
|
-
style
|
|
40
|
+
style,
|
|
41
|
+
searchQuery
|
|
39
42
|
}: Props) {
|
|
40
43
|
const { padding, maxHeight } = useCustomDimensions();
|
|
44
|
+
const viewedWalletsRef = useRef<Set<string>>(new Set());
|
|
41
45
|
|
|
42
46
|
// Create loading data if isLoading is true
|
|
43
47
|
const displayData = isLoading
|
|
44
48
|
? Array.from({ length: loadingItems }, (_, index) => ({ id: `loading-${index}` }) as WcWallet)
|
|
45
49
|
: data;
|
|
46
50
|
|
|
51
|
+
const keyExtractor = useCallback(
|
|
52
|
+
(item: WcWallet, index: number) => item?.id ?? `item-${index}`,
|
|
53
|
+
[]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const getItemLayout = useCallback((_: any, index: number) => {
|
|
57
|
+
return {
|
|
58
|
+
length: ITEM_HEIGHT_WITH_GAP,
|
|
59
|
+
offset: ITEM_HEIGHT_WITH_GAP * index,
|
|
60
|
+
index
|
|
61
|
+
};
|
|
62
|
+
}, []);
|
|
63
|
+
|
|
64
|
+
const renderItem = useCallback(
|
|
65
|
+
({ item, index }: { item: WcWallet; index: number }) => {
|
|
66
|
+
if (isLoading) {
|
|
67
|
+
return <CardSelectLoader style={styles.itemContainer} />;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<WalletItem
|
|
72
|
+
item={item}
|
|
73
|
+
imageHeaders={imageHeaders}
|
|
74
|
+
displayIndex={index}
|
|
75
|
+
onItemPress={onItemPress}
|
|
76
|
+
style={styles.itemContainer}
|
|
77
|
+
testID={testIDKey ? `${testIDKey}-${item?.id}` : undefined}
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
[isLoading, onItemPress, testIDKey]
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const onViewableItemsChanged = useCallback(
|
|
85
|
+
({ viewableItems }: { viewableItems: ViewToken[] }) => {
|
|
86
|
+
if (isLoading) return;
|
|
87
|
+
|
|
88
|
+
viewableItems.forEach(({ item }, index) => {
|
|
89
|
+
const wallet = item as WcWallet;
|
|
90
|
+
if (wallet?.id && !viewedWalletsRef.current.has(wallet.id)) {
|
|
91
|
+
viewedWalletsRef.current.add(wallet.id);
|
|
92
|
+
const isInstalled = !!ApiController.state.installed.find(w => w?.id === item?.id);
|
|
93
|
+
EventsController.trackWalletImpression({
|
|
94
|
+
wallet,
|
|
95
|
+
view: 'AllWallets',
|
|
96
|
+
displayIndex: index,
|
|
97
|
+
query: searchQuery,
|
|
98
|
+
installed: isInstalled
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
[isLoading, searchQuery]
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const viewabilityConfig = useRef({
|
|
107
|
+
itemVisiblePercentThreshold: 50, // Item is considered visible when 50% is visible
|
|
108
|
+
minimumViewTime: 100 // Must be visible for at least 100ms
|
|
109
|
+
}).current;
|
|
110
|
+
|
|
47
111
|
return (
|
|
48
112
|
<FlatList
|
|
49
113
|
fadingEdgeLength={20}
|
|
@@ -52,34 +116,18 @@ export function WalletList({
|
|
|
52
116
|
data={displayData}
|
|
53
117
|
style={[styles.list, { height: maxHeight }, style]}
|
|
54
118
|
columnWrapperStyle={styles.columnWrapperStyle}
|
|
55
|
-
renderItem={
|
|
56
|
-
if (isLoading) {
|
|
57
|
-
return <CardSelectLoader style={styles.itemContainer} />;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<WalletItem
|
|
62
|
-
item={item}
|
|
63
|
-
imageHeaders={imageHeaders}
|
|
64
|
-
displayIndex={index}
|
|
65
|
-
onItemPress={onItemPress}
|
|
66
|
-
style={styles.itemContainer}
|
|
67
|
-
testID={testIDKey ? `${testIDKey}-${item?.id}` : undefined}
|
|
68
|
-
/>
|
|
69
|
-
);
|
|
70
|
-
}}
|
|
119
|
+
renderItem={renderItem}
|
|
71
120
|
contentContainerStyle={[styles.contentContainer, { paddingHorizontal: padding }]}
|
|
72
121
|
initialNumToRender={32}
|
|
73
122
|
maxToRenderPerBatch={12}
|
|
74
123
|
windowSize={10}
|
|
75
124
|
onEndReached={onEndReached}
|
|
76
125
|
onEndReachedThreshold={onEndReachedThreshold}
|
|
77
|
-
keyExtractor={
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
})}
|
|
126
|
+
keyExtractor={keyExtractor}
|
|
127
|
+
removeClippedSubviews={true}
|
|
128
|
+
getItemLayout={getItemLayout}
|
|
129
|
+
onViewableItemsChanged={onViewableItemsChanged}
|
|
130
|
+
viewabilityConfig={viewabilityConfig}
|
|
83
131
|
/>
|
|
84
132
|
);
|
|
85
133
|
}
|
|
@@ -84,5 +84,12 @@ export function AllWalletsSearch({ searchQuery, onItemPress }: AllWalletsSearchP
|
|
|
84
84
|
);
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
return
|
|
87
|
+
return (
|
|
88
|
+
<WalletList
|
|
89
|
+
onItemPress={onItemPress}
|
|
90
|
+
searchQuery={searchQuery}
|
|
91
|
+
data={results}
|
|
92
|
+
testIDKey="wallet-search-item"
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
88
95
|
}
|
|
@@ -20,6 +20,9 @@ import styles from './styles';
|
|
|
20
20
|
import { ReownButton } from './components/ReownButton';
|
|
21
21
|
import { useWindowDimensions } from 'react-native';
|
|
22
22
|
|
|
23
|
+
const LOGO_SIZE = 60;
|
|
24
|
+
const LOGO_BORDER_RADIUS = 20;
|
|
25
|
+
|
|
23
26
|
export function ConnectingQrCode() {
|
|
24
27
|
const { height, width } = useWindowDimensions();
|
|
25
28
|
const windowSize = Math.min(height, width);
|
|
@@ -65,7 +68,13 @@ export function ConnectingQrCode() {
|
|
|
65
68
|
flexDirection={isPortrait ? 'column' : 'row'}
|
|
66
69
|
padding={['xl', 'xl', 'xs', 'xl']}
|
|
67
70
|
>
|
|
68
|
-
<QrCode
|
|
71
|
+
<QrCode
|
|
72
|
+
size={qrSize}
|
|
73
|
+
uri={wcUri}
|
|
74
|
+
testID="qr-code"
|
|
75
|
+
logoBorderRadius={LOGO_BORDER_RADIUS}
|
|
76
|
+
logoSize={LOGO_SIZE}
|
|
77
|
+
/>
|
|
69
78
|
<FlexView alignItems="center" margin="m">
|
|
70
79
|
<Text variant="paragraph-500">Scan this QR code with your phone</Text>
|
|
71
80
|
{showCopy ? (
|
|
@@ -20,6 +20,7 @@ export interface SendInputTokenProps {
|
|
|
20
20
|
style?: StyleProp<ViewStyle>;
|
|
21
21
|
onTokenPress?: () => void;
|
|
22
22
|
loading?: boolean;
|
|
23
|
+
testID?: string;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export function SendInputToken({
|
|
@@ -27,7 +28,8 @@ export function SendInputToken({
|
|
|
27
28
|
sendTokenAmount,
|
|
28
29
|
style,
|
|
29
30
|
onTokenPress,
|
|
30
|
-
loading
|
|
31
|
+
loading,
|
|
32
|
+
testID
|
|
31
33
|
}: SendInputTokenProps) {
|
|
32
34
|
const Theme = useTheme();
|
|
33
35
|
const valueInputRef = useRef<TextInput | null>(null);
|
|
@@ -86,12 +88,14 @@ export function SendInputToken({
|
|
|
86
88
|
selectTextOnFocus={false}
|
|
87
89
|
numberOfLines={1}
|
|
88
90
|
autoFocus={!!token}
|
|
91
|
+
testID={testID}
|
|
89
92
|
/>
|
|
90
93
|
<TokenButton
|
|
91
94
|
imageUrl={token?.iconUrl}
|
|
92
95
|
text={token?.symbol}
|
|
93
96
|
onPress={onTokenPress}
|
|
94
97
|
chevron
|
|
98
|
+
testID={testID ? `${testID}-button` : undefined}
|
|
95
99
|
/>
|
|
96
100
|
</FlexView>
|
|
97
101
|
{token ? (
|
|
@@ -28,6 +28,7 @@ export interface SwapInputProps {
|
|
|
28
28
|
marketValue?: number;
|
|
29
29
|
editable?: boolean;
|
|
30
30
|
autoFocus?: boolean;
|
|
31
|
+
testID?: string;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const MINIMUM_USD_VALUE_TO_CONVERT = 0.00005;
|
|
@@ -43,7 +44,8 @@ export function SwapInput({
|
|
|
43
44
|
onChange,
|
|
44
45
|
marketValue,
|
|
45
46
|
editable,
|
|
46
|
-
autoFocus
|
|
47
|
+
autoFocus,
|
|
48
|
+
testID
|
|
47
49
|
}: SwapInputProps) {
|
|
48
50
|
const Theme = useTheme();
|
|
49
51
|
const valueInputRef = useRef<TextInput | null>(null);
|
|
@@ -118,6 +120,7 @@ export function SwapInput({
|
|
|
118
120
|
numberOfLines={1}
|
|
119
121
|
editable={editable}
|
|
120
122
|
autoFocus={autoFocus}
|
|
123
|
+
testID={testID}
|
|
121
124
|
/>
|
|
122
125
|
)}
|
|
123
126
|
<TokenButton
|
|
@@ -125,6 +128,7 @@ export function SwapInput({
|
|
|
125
128
|
imageUrl={token?.logoUri}
|
|
126
129
|
onPress={onTokenPress}
|
|
127
130
|
chevron
|
|
131
|
+
testID={testID ? `${testID}-button` : undefined}
|
|
128
132
|
/>
|
|
129
133
|
</FlexView>
|
|
130
134
|
{loadingValues ? (
|
|
@@ -186,7 +186,12 @@ export function AccountDefaultView() {
|
|
|
186
186
|
return (
|
|
187
187
|
<>
|
|
188
188
|
{showBack ? (
|
|
189
|
-
<IconLink
|
|
189
|
+
<IconLink
|
|
190
|
+
icon="chevronLeft"
|
|
191
|
+
style={styles.backIcon}
|
|
192
|
+
onPress={RouterController.goBack}
|
|
193
|
+
testID="header-back"
|
|
194
|
+
/>
|
|
190
195
|
) : null}
|
|
191
196
|
<IconLink
|
|
192
197
|
icon="close"
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ApiController,
|
|
5
5
|
AssetController,
|
|
6
6
|
AssetUtil,
|
|
7
|
+
EventsController,
|
|
7
8
|
OptionsController,
|
|
8
9
|
WcController,
|
|
9
10
|
type WcControllerState
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
import { type WcWallet } from '@reown/appkit-common-react-native';
|
|
12
13
|
import { ListItemLoader, ListWallet } from '@reown/appkit-ui-react-native';
|
|
13
14
|
import { UiUtil } from '../../../utils/UiUtil';
|
|
15
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
14
16
|
|
|
15
17
|
interface Props {
|
|
16
18
|
itemStyle: StyleProp<ViewStyle>;
|
|
@@ -24,18 +26,45 @@ export function AllWalletList({ itemStyle, onWalletPress }: Props) {
|
|
|
24
26
|
const { walletImages } = useSnapshot(AssetController.state);
|
|
25
27
|
const imageHeaders = ApiController._getApiHeaders();
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
...installed,
|
|
30
|
-
...featured,
|
|
31
|
-
...recommended,
|
|
32
|
-
...(customWallets ?? [])
|
|
33
|
-
];
|
|
29
|
+
// Track which wallets have been tracked to prevent duplicates
|
|
30
|
+
const trackedWalletsRef = useRef<Set<string>>(new Set());
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
const list = useMemo(() => {
|
|
33
|
+
const combinedWallets = [
|
|
34
|
+
...(recentWallets?.slice(0, 1) ?? []),
|
|
35
|
+
...installed,
|
|
36
|
+
...featured,
|
|
37
|
+
...recommended,
|
|
38
|
+
...(customWallets ?? [])
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// Deduplicate by wallet ID
|
|
42
|
+
return Array.from(new Map(combinedWallets.map(wallet => [wallet.id, wallet])).values()).slice(
|
|
43
|
+
0,
|
|
44
|
+
UiUtil.TOTAL_VISIBLE_WALLETS
|
|
45
|
+
);
|
|
46
|
+
}, [recentWallets, installed, featured, recommended, customWallets]);
|
|
47
|
+
|
|
48
|
+
// Track impressions once when the list stabilizes
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (!prefetchLoading && list.length > 0) {
|
|
51
|
+
list.forEach((wallet, index) => {
|
|
52
|
+
if (!trackedWalletsRef.current.has(wallet.id)) {
|
|
53
|
+
trackedWalletsRef.current.add(wallet.id);
|
|
54
|
+
const isInstalled = !!ApiController.state.installed.find(
|
|
55
|
+
installedWallet => installedWallet.id === wallet.id
|
|
56
|
+
);
|
|
57
|
+
EventsController.trackWalletImpression({
|
|
58
|
+
wallet,
|
|
59
|
+
view: 'Connect',
|
|
60
|
+
displayIndex: index,
|
|
61
|
+
// eslint-disable-next-line valtio/state-snapshot-rule
|
|
62
|
+
installed: isInstalled
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}, [prefetchLoading, list]);
|
|
39
68
|
|
|
40
69
|
if (!list?.length) {
|
|
41
70
|
return null;
|
|
@@ -90,6 +90,7 @@ export function OnRampSettingsView() {
|
|
|
90
90
|
chevron
|
|
91
91
|
style={styles.firstItem}
|
|
92
92
|
contentStyle={styles.listItem}
|
|
93
|
+
testID="button-select-country"
|
|
93
94
|
>
|
|
94
95
|
<FlexView
|
|
95
96
|
alignItems="center"
|
|
@@ -111,7 +112,12 @@ export function OnRampSettingsView() {
|
|
|
111
112
|
) : null}
|
|
112
113
|
</FlexView>
|
|
113
114
|
</ListItem>
|
|
114
|
-
<ListItem
|
|
115
|
+
<ListItem
|
|
116
|
+
onPress={onPaymentCurrencyPress}
|
|
117
|
+
chevron
|
|
118
|
+
contentStyle={styles.listItem}
|
|
119
|
+
testID="button-select-currency"
|
|
120
|
+
>
|
|
115
121
|
<FlexView
|
|
116
122
|
alignItems="center"
|
|
117
123
|
justifyContent="center"
|