@reown/appkit-react-native 0.0.0-feat-multichain-20251002190808 → 0.0.0-feat-multichain-20251006182725

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.
Files changed (40) hide show
  1. package/lib/commonjs/AppKit.js +12 -6
  2. package/lib/commonjs/AppKit.js.map +1 -1
  3. package/lib/commonjs/hooks/useProvider.js +20 -8
  4. package/lib/commonjs/hooks/useProvider.js.map +1 -1
  5. package/lib/commonjs/partials/w3m-all-wallets-list/components/WalletList.js +62 -25
  6. package/lib/commonjs/partials/w3m-all-wallets-list/components/WalletList.js.map +1 -1
  7. package/lib/commonjs/partials/w3m-all-wallets-list/index.js +1 -1
  8. package/lib/commonjs/partials/w3m-all-wallets-list/index.js.map +1 -1
  9. package/lib/commonjs/partials/w3m-all-wallets-search/index.js +1 -0
  10. package/lib/commonjs/partials/w3m-all-wallets-search/index.js.map +1 -1
  11. package/lib/commonjs/views/w3m-connect-view/components/all-wallet-list.js +28 -3
  12. package/lib/commonjs/views/w3m-connect-view/components/all-wallet-list.js.map +1 -1
  13. package/lib/module/AppKit.js +12 -6
  14. package/lib/module/AppKit.js.map +1 -1
  15. package/lib/module/hooks/useProvider.js +21 -9
  16. package/lib/module/hooks/useProvider.js.map +1 -1
  17. package/lib/module/partials/w3m-all-wallets-list/components/WalletList.js +63 -26
  18. package/lib/module/partials/w3m-all-wallets-list/components/WalletList.js.map +1 -1
  19. package/lib/module/partials/w3m-all-wallets-list/index.js +1 -1
  20. package/lib/module/partials/w3m-all-wallets-list/index.js.map +1 -1
  21. package/lib/module/partials/w3m-all-wallets-search/index.js +1 -0
  22. package/lib/module/partials/w3m-all-wallets-search/index.js.map +1 -1
  23. package/lib/module/views/w3m-connect-view/components/all-wallet-list.js +29 -4
  24. package/lib/module/views/w3m-connect-view/components/all-wallet-list.js.map +1 -1
  25. package/lib/typescript/AppKit.d.ts +1 -1
  26. package/lib/typescript/AppKit.d.ts.map +1 -1
  27. package/lib/typescript/hooks/useAppKitEvents.d.ts +13 -0
  28. package/lib/typescript/hooks/useAppKitEvents.d.ts.map +1 -1
  29. package/lib/typescript/hooks/useProvider.d.ts.map +1 -1
  30. package/lib/typescript/partials/w3m-all-wallets-list/components/WalletList.d.ts +2 -1
  31. package/lib/typescript/partials/w3m-all-wallets-list/components/WalletList.d.ts.map +1 -1
  32. package/lib/typescript/partials/w3m-all-wallets-search/index.d.ts.map +1 -1
  33. package/lib/typescript/views/w3m-connect-view/components/all-wallet-list.d.ts.map +1 -1
  34. package/package.json +4 -4
  35. package/src/AppKit.ts +13 -5
  36. package/src/hooks/useProvider.ts +15 -6
  37. package/src/partials/w3m-all-wallets-list/components/WalletList.tsx +73 -25
  38. package/src/partials/w3m-all-wallets-list/index.tsx +1 -1
  39. package/src/partials/w3m-all-wallets-search/index.tsx +8 -1
  40. package/src/views/w3m-connect-view/components/all-wallet-list.tsx +40 -11
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,7 +256,15 @@ export class AppKit {
255
256
  );
256
257
  if (!connection || !connection.adapter || !connection.adapter.connector) return null;
257
258
 
258
- return connection.adapter.connector.getProvider() as T;
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() {
@@ -308,6 +317,7 @@ export class AppKit {
308
317
 
309
318
  RouterUtil.checkOnRampBack();
310
319
  RouterUtil.checkSocialLoginBack();
320
+ EventsController.sendWalletImpressions();
311
321
  }
312
322
 
313
323
  back() {
@@ -686,10 +696,8 @@ export class AppKit {
686
696
  this.setCustomWallets(options);
687
697
  OptionsController.setFeaturedWalletIds(options.featuredWalletIds);
688
698
  OptionsController.setEnableAnalytics(options.enableAnalytics);
689
- OptionsController.setDebug(options.debug && __DEV__);
699
+ OptionsController.setDebug(options.debug);
690
700
 
691
- // Initialize LogController after debug option is set
692
- LogController.initialize();
693
701
  LogController.sendInfo('AppKit initialization started', 'AppKit.ts', 'initControllers', {
694
702
  projectId: options.projectId,
695
703
  adapters: this.adapters.map(a => a.constructor.name),
@@ -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) return { provider: undefined, providerType: undefined };
43
+ if (!connection || !connection.adapter) {
44
+ return { provider: undefined, providerType: undefined };
45
+ }
44
46
 
45
- return {
46
- provider: connection.adapter.getProvider(),
47
- providerType: connection.adapter.getSupportedNamespace()
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;
@@ -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={({ item, index }) => {
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={(item, index) => item?.id ?? `item-${index}`}
78
- getItemLayout={(_, index) => ({
79
- length: ITEM_HEIGHT_WITH_GAP,
80
- offset: ITEM_HEIGHT_WITH_GAP * index,
81
- index
82
- })}
126
+ keyExtractor={keyExtractor}
127
+ removeClippedSubviews={true}
128
+ getItemLayout={getItemLayout}
129
+ onViewableItemsChanged={onViewableItemsChanged}
130
+ viewabilityConfig={viewabilityConfig}
83
131
  />
84
132
  );
85
133
  }
@@ -116,7 +116,7 @@ export function AllWalletsList({ onItemPress }: AllWalletsListProps) {
116
116
  <WalletList
117
117
  data={walletList}
118
118
  onEndReached={fetchNextPage}
119
- onEndReachedThreshold={2}
119
+ onEndReachedThreshold={0.5}
120
120
  onItemPress={onItemPress}
121
121
  />
122
122
  );
@@ -84,5 +84,12 @@ export function AllWalletsSearch({ searchQuery, onItemPress }: AllWalletsSearchP
84
84
  );
85
85
  }
86
86
 
87
- return <WalletList onItemPress={onItemPress} data={results} testIDKey="wallet-search-item" />;
87
+ return (
88
+ <WalletList
89
+ onItemPress={onItemPress}
90
+ searchQuery={searchQuery}
91
+ data={results}
92
+ testIDKey="wallet-search-item"
93
+ />
94
+ );
88
95
  }
@@ -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
- const combinedWallets = [
28
- ...(recentWallets?.slice(0, 1) ?? []),
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
- // Deduplicate by wallet ID
36
- const list = Array.from(
37
- new Map(combinedWallets.map(wallet => [wallet.id, wallet])).values()
38
- ).slice(0, UiUtil.TOTAL_VISIBLE_WALLETS);
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;