thirdweb 5.32.0 → 5.32.1

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 (252) hide show
  1. package/dist/cjs/chains/utils.js +9 -7
  2. package/dist/cjs/chains/utils.js.map +1 -1
  3. package/dist/cjs/exports/react.js +3 -0
  4. package/dist/cjs/exports/react.js.map +1 -1
  5. package/dist/cjs/exports/wallets/smart.js +3 -1
  6. package/dist/cjs/exports/wallets/smart.js.map +1 -1
  7. package/dist/cjs/react/core/hooks/others/useChainQuery.js +104 -33
  8. package/dist/cjs/react/core/hooks/others/useChainQuery.js.map +1 -1
  9. package/dist/cjs/react/native/ui/components/ChainIcon.js +2 -3
  10. package/dist/cjs/react/native/ui/components/ChainIcon.js.map +1 -1
  11. package/dist/cjs/react/native/ui/connect/ConnectedModal.js +2 -2
  12. package/dist/cjs/react/native/ui/connect/ConnectedModal.js.map +1 -1
  13. package/dist/cjs/react/native/ui/connect/SendScreen.js +2 -2
  14. package/dist/cjs/react/native/ui/connect/SendScreen.js.map +1 -1
  15. package/dist/cjs/react/web/ui/ConnectWallet/Details.js +6 -5
  16. package/dist/cjs/react/web/ui/ConnectWallet/Details.js.map +1 -1
  17. package/dist/cjs/react/web/ui/ConnectWallet/NetworkSelector.js +217 -188
  18. package/dist/cjs/react/web/ui/ConnectWallet/NetworkSelector.js.map +1 -1
  19. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +2 -4
  20. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  21. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.js +12 -10
  22. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.js.map +1 -1
  23. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.js +2 -2
  24. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.js.map +1 -1
  25. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js +2 -2
  26. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js.map +1 -1
  27. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +2 -2
  28. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js.map +1 -1
  29. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.js +2 -2
  30. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.js.map +1 -1
  31. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistory.js +2 -2
  32. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistory.js.map +1 -1
  33. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/SwapDetailsScreen.js +8 -6
  34. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/SwapDetailsScreen.js.map +1 -1
  35. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.js +2 -2
  36. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.js.map +1 -1
  37. package/dist/cjs/react/web/ui/ConnectWallet/screens/TokenSelector.js +3 -2
  38. package/dist/cjs/react/web/ui/ConnectWallet/screens/TokenSelector.js.map +1 -1
  39. package/dist/cjs/react/web/ui/components/ChainIcon.js +1 -1
  40. package/dist/cjs/react/web/ui/components/ChainIcon.js.map +1 -1
  41. package/dist/cjs/react/web/ui/components/ChainName.js +3 -5
  42. package/dist/cjs/react/web/ui/components/ChainName.js.map +1 -1
  43. package/dist/cjs/react/web/ui/components/TokenIcon.js +3 -3
  44. package/dist/cjs/react/web/ui/components/TokenIcon.js.map +1 -1
  45. package/dist/cjs/react/web/ui/components/token/TokenSymbol.js +3 -3
  46. package/dist/cjs/react/web/ui/components/token/TokenSymbol.js.map +1 -1
  47. package/dist/cjs/react/web/wallets/ecosystem/EcosystemWalletFormUI.js +1 -1
  48. package/dist/cjs/react/web/wallets/ecosystem/EcosystemWalletFormUI.js.map +1 -1
  49. package/dist/cjs/utils/extensions/drops/get-claim-params.js +3 -2
  50. package/dist/cjs/utils/extensions/drops/get-claim-params.js.map +1 -1
  51. package/dist/cjs/version.js +1 -1
  52. package/dist/cjs/wallets/in-app/web/ecosystem.js +3 -14
  53. package/dist/cjs/wallets/in-app/web/ecosystem.js.map +1 -1
  54. package/dist/cjs/wallets/smart/index.js +3 -17
  55. package/dist/cjs/wallets/smart/index.js.map +1 -1
  56. package/dist/cjs/wallets/smart/lib/bundler.js +1 -1
  57. package/dist/cjs/wallets/smart/lib/bundler.js.map +1 -1
  58. package/dist/cjs/wallets/smart/lib/userop.js +63 -8
  59. package/dist/cjs/wallets/smart/lib/userop.js.map +1 -1
  60. package/dist/esm/chains/utils.js +9 -7
  61. package/dist/esm/chains/utils.js.map +1 -1
  62. package/dist/esm/exports/react.js +1 -0
  63. package/dist/esm/exports/react.js.map +1 -1
  64. package/dist/esm/exports/wallets/smart.js +1 -0
  65. package/dist/esm/exports/wallets/smart.js.map +1 -1
  66. package/dist/esm/react/core/hooks/others/useChainQuery.js +101 -33
  67. package/dist/esm/react/core/hooks/others/useChainQuery.js.map +1 -1
  68. package/dist/esm/react/native/ui/components/ChainIcon.js +3 -4
  69. package/dist/esm/react/native/ui/components/ChainIcon.js.map +1 -1
  70. package/dist/esm/react/native/ui/connect/ConnectedModal.js +3 -3
  71. package/dist/esm/react/native/ui/connect/ConnectedModal.js.map +1 -1
  72. package/dist/esm/react/native/ui/connect/SendScreen.js +3 -3
  73. package/dist/esm/react/native/ui/connect/SendScreen.js.map +1 -1
  74. package/dist/esm/react/web/ui/ConnectWallet/Details.js +7 -6
  75. package/dist/esm/react/web/ui/ConnectWallet/Details.js.map +1 -1
  76. package/dist/esm/react/web/ui/ConnectWallet/NetworkSelector.js +219 -191
  77. package/dist/esm/react/web/ui/ConnectWallet/NetworkSelector.js.map +1 -1
  78. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +3 -5
  79. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  80. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.js +13 -11
  81. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.js.map +1 -1
  82. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.js +3 -3
  83. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.js.map +1 -1
  84. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js +3 -3
  85. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js.map +1 -1
  86. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +3 -3
  87. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js.map +1 -1
  88. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.js +3 -3
  89. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.js.map +1 -1
  90. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistory.js +3 -3
  91. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistory.js.map +1 -1
  92. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/SwapDetailsScreen.js +9 -7
  93. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/SwapDetailsScreen.js.map +1 -1
  94. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.js +3 -3
  95. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.js.map +1 -1
  96. package/dist/esm/react/web/ui/ConnectWallet/screens/TokenSelector.js +4 -3
  97. package/dist/esm/react/web/ui/ConnectWallet/screens/TokenSelector.js.map +1 -1
  98. package/dist/esm/react/web/ui/components/ChainIcon.js +1 -1
  99. package/dist/esm/react/web/ui/components/ChainIcon.js.map +1 -1
  100. package/dist/esm/react/web/ui/components/ChainName.js +4 -6
  101. package/dist/esm/react/web/ui/components/ChainName.js.map +1 -1
  102. package/dist/esm/react/web/ui/components/TokenIcon.js +4 -4
  103. package/dist/esm/react/web/ui/components/TokenIcon.js.map +1 -1
  104. package/dist/esm/react/web/ui/components/token/TokenSymbol.js +4 -4
  105. package/dist/esm/react/web/ui/components/token/TokenSymbol.js.map +1 -1
  106. package/dist/esm/react/web/wallets/ecosystem/EcosystemWalletFormUI.js +2 -2
  107. package/dist/esm/react/web/wallets/ecosystem/EcosystemWalletFormUI.js.map +1 -1
  108. package/dist/esm/utils/extensions/drops/get-claim-params.js +3 -2
  109. package/dist/esm/utils/extensions/drops/get-claim-params.js.map +1 -1
  110. package/dist/esm/version.js +1 -1
  111. package/dist/esm/wallets/in-app/web/ecosystem.js +3 -14
  112. package/dist/esm/wallets/in-app/web/ecosystem.js.map +1 -1
  113. package/dist/esm/wallets/smart/index.js +4 -18
  114. package/dist/esm/wallets/smart/index.js.map +1 -1
  115. package/dist/esm/wallets/smart/lib/bundler.js +1 -1
  116. package/dist/esm/wallets/smart/lib/bundler.js.map +1 -1
  117. package/dist/esm/wallets/smart/lib/userop.js +63 -9
  118. package/dist/esm/wallets/smart/lib/userop.js.map +1 -1
  119. package/dist/types/chains/chain-definitions/anvil.d.ts +1 -0
  120. package/dist/types/chains/chain-definitions/anvil.d.ts.map +1 -1
  121. package/dist/types/chains/chain-definitions/arbitrum-nova.d.ts +1 -0
  122. package/dist/types/chains/chain-definitions/arbitrum-nova.d.ts.map +1 -1
  123. package/dist/types/chains/chain-definitions/arbitrum-sepolia.d.ts +1 -0
  124. package/dist/types/chains/chain-definitions/arbitrum-sepolia.d.ts.map +1 -1
  125. package/dist/types/chains/chain-definitions/arbitrum.d.ts +1 -0
  126. package/dist/types/chains/chain-definitions/arbitrum.d.ts.map +1 -1
  127. package/dist/types/chains/chain-definitions/avalanche-fuji.d.ts +1 -0
  128. package/dist/types/chains/chain-definitions/avalanche-fuji.d.ts.map +1 -1
  129. package/dist/types/chains/chain-definitions/avalanche.d.ts +1 -0
  130. package/dist/types/chains/chain-definitions/avalanche.d.ts.map +1 -1
  131. package/dist/types/chains/chain-definitions/base-sepolia.d.ts +1 -0
  132. package/dist/types/chains/chain-definitions/base-sepolia.d.ts.map +1 -1
  133. package/dist/types/chains/chain-definitions/base.d.ts +1 -0
  134. package/dist/types/chains/chain-definitions/base.d.ts.map +1 -1
  135. package/dist/types/chains/chain-definitions/bsc-testnet.d.ts +1 -0
  136. package/dist/types/chains/chain-definitions/bsc-testnet.d.ts.map +1 -1
  137. package/dist/types/chains/chain-definitions/bsc.d.ts +1 -0
  138. package/dist/types/chains/chain-definitions/bsc.d.ts.map +1 -1
  139. package/dist/types/chains/chain-definitions/ethereum.d.ts +2 -0
  140. package/dist/types/chains/chain-definitions/ethereum.d.ts.map +1 -1
  141. package/dist/types/chains/chain-definitions/hardhat.d.ts +1 -0
  142. package/dist/types/chains/chain-definitions/hardhat.d.ts.map +1 -1
  143. package/dist/types/chains/chain-definitions/linea-sepolia.d.ts +1 -0
  144. package/dist/types/chains/chain-definitions/linea-sepolia.d.ts.map +1 -1
  145. package/dist/types/chains/chain-definitions/linea.d.ts +1 -0
  146. package/dist/types/chains/chain-definitions/linea.d.ts.map +1 -1
  147. package/dist/types/chains/chain-definitions/optimism-sepolia.d.ts +1 -0
  148. package/dist/types/chains/chain-definitions/optimism-sepolia.d.ts.map +1 -1
  149. package/dist/types/chains/chain-definitions/optimism.d.ts +1 -0
  150. package/dist/types/chains/chain-definitions/optimism.d.ts.map +1 -1
  151. package/dist/types/chains/chain-definitions/polygon-amoy.d.ts +1 -0
  152. package/dist/types/chains/chain-definitions/polygon-amoy.d.ts.map +1 -1
  153. package/dist/types/chains/chain-definitions/polygon-mumbai.d.ts +2 -0
  154. package/dist/types/chains/chain-definitions/polygon-mumbai.d.ts.map +1 -1
  155. package/dist/types/chains/chain-definitions/polygon.d.ts +1 -0
  156. package/dist/types/chains/chain-definitions/polygon.d.ts.map +1 -1
  157. package/dist/types/chains/chain-definitions/sepolia.d.ts +1 -0
  158. package/dist/types/chains/chain-definitions/sepolia.d.ts.map +1 -1
  159. package/dist/types/chains/chain-definitions/zksync-sepolia.d.ts +1 -0
  160. package/dist/types/chains/chain-definitions/zksync-sepolia.d.ts.map +1 -1
  161. package/dist/types/chains/chain-definitions/zksync.d.ts +1 -0
  162. package/dist/types/chains/chain-definitions/zksync.d.ts.map +1 -1
  163. package/dist/types/chains/chain-definitions/zora-sepolia.d.ts +1 -0
  164. package/dist/types/chains/chain-definitions/zora-sepolia.d.ts.map +1 -1
  165. package/dist/types/chains/chain-definitions/zora.d.ts +1 -0
  166. package/dist/types/chains/chain-definitions/zora.d.ts.map +1 -1
  167. package/dist/types/chains/types.d.ts +1 -0
  168. package/dist/types/chains/types.d.ts.map +1 -1
  169. package/dist/types/chains/utils.d.ts +1 -0
  170. package/dist/types/chains/utils.d.ts.map +1 -1
  171. package/dist/types/exports/react.d.ts +1 -0
  172. package/dist/types/exports/react.d.ts.map +1 -1
  173. package/dist/types/exports/wallets/smart.d.ts +1 -0
  174. package/dist/types/exports/wallets/smart.d.ts.map +1 -1
  175. package/dist/types/react/core/connectionManager.d.ts +1 -0
  176. package/dist/types/react/core/connectionManager.d.ts.map +1 -1
  177. package/dist/types/react/core/hooks/others/useChainQuery.d.ts +24 -10
  178. package/dist/types/react/core/hooks/others/useChainQuery.d.ts.map +1 -1
  179. package/dist/types/react/core/hooks/wallets/useActiveWalletChain.d.ts +1 -0
  180. package/dist/types/react/core/hooks/wallets/useActiveWalletChain.d.ts.map +1 -1
  181. package/dist/types/react/native/hooks/wallets/useActiveWalletChain.d.ts +1 -0
  182. package/dist/types/react/native/hooks/wallets/useActiveWalletChain.d.ts.map +1 -1
  183. package/dist/types/react/native/index.d.ts +1 -0
  184. package/dist/types/react/native/index.d.ts.map +1 -1
  185. package/dist/types/react/native/ui/components/ChainIcon.d.ts.map +1 -1
  186. package/dist/types/react/web/hooks/wallets/useActiveWalletChain.d.ts +1 -0
  187. package/dist/types/react/web/hooks/wallets/useActiveWalletChain.d.ts.map +1 -1
  188. package/dist/types/react/web/index.d.ts +1 -0
  189. package/dist/types/react/web/index.d.ts.map +1 -1
  190. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts.map +1 -1
  191. package/dist/types/react/web/ui/ConnectWallet/NetworkSelector.d.ts +142 -0
  192. package/dist/types/react/web/ui/ConnectWallet/NetworkSelector.d.ts.map +1 -1
  193. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.d.ts.map +1 -1
  194. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.d.ts.map +1 -1
  195. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.d.ts.map +1 -1
  196. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.d.ts +4 -0
  197. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.d.ts.map +1 -1
  198. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.d.ts +1 -0
  199. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.d.ts.map +1 -1
  200. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/tx-history/SwapDetailsScreen.d.ts.map +1 -1
  201. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.d.ts.map +1 -1
  202. package/dist/types/react/web/ui/ConnectWallet/screens/TokenSelector.d.ts.map +1 -1
  203. package/dist/types/react/web/ui/components/ChainIcon.d.ts +1 -2
  204. package/dist/types/react/web/ui/components/ChainIcon.d.ts.map +1 -1
  205. package/dist/types/react/web/ui/components/ChainName.d.ts.map +1 -1
  206. package/dist/types/react/web/wallets/ecosystem/EcosystemWalletFormUI.d.ts.map +1 -1
  207. package/dist/types/utils/extensions/drops/get-claim-params.d.ts.map +1 -1
  208. package/dist/types/version.d.ts +1 -1
  209. package/dist/types/wallets/in-app/web/ecosystem.d.ts +3 -14
  210. package/dist/types/wallets/in-app/web/ecosystem.d.ts.map +1 -1
  211. package/dist/types/wallets/manager/index.d.ts +1 -0
  212. package/dist/types/wallets/manager/index.d.ts.map +1 -1
  213. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  214. package/dist/types/wallets/smart/lib/bundler.d.ts +1 -2
  215. package/dist/types/wallets/smart/lib/bundler.d.ts.map +1 -1
  216. package/dist/types/wallets/smart/lib/userop.d.ts +53 -8
  217. package/dist/types/wallets/smart/lib/userop.d.ts.map +1 -1
  218. package/package.json +1 -1
  219. package/src/chains/types.ts +1 -1
  220. package/src/chains/utils.ts +9 -7
  221. package/src/exports/react.ts +5 -0
  222. package/src/exports/wallets/smart.ts +2 -0
  223. package/src/extensions/erc1155/drop1155.test.ts +7 -0
  224. package/src/extensions/erc20/drop20.test.ts +55 -0
  225. package/src/extensions/erc721/drop721.test.ts +28 -0
  226. package/src/react/core/hooks/others/useChainQuery.ts +116 -35
  227. package/src/react/native/ui/components/ChainIcon.tsx +3 -4
  228. package/src/react/native/ui/connect/ConnectedModal.tsx +4 -4
  229. package/src/react/native/ui/connect/SendScreen.tsx +3 -3
  230. package/src/react/web/ui/ConnectWallet/Details.tsx +13 -12
  231. package/src/react/web/ui/ConnectWallet/NetworkSelector.tsx +421 -323
  232. package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +4 -10
  233. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.tsx +17 -15
  234. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.tsx +6 -4
  235. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.tsx +4 -4
  236. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.tsx +4 -4
  237. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.tsx +4 -4
  238. package/src/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistory.tsx +3 -3
  239. package/src/react/web/ui/ConnectWallet/screens/Buy/tx-history/SwapDetailsScreen.tsx +14 -9
  240. package/src/react/web/ui/ConnectWallet/screens/Buy/tx-history/TokenInfoRow.tsx +3 -4
  241. package/src/react/web/ui/ConnectWallet/screens/TokenSelector.tsx +10 -6
  242. package/src/react/web/ui/components/ChainIcon.tsx +2 -3
  243. package/src/react/web/ui/components/ChainName.tsx +4 -6
  244. package/src/react/web/ui/components/TokenIcon.tsx +4 -4
  245. package/src/react/web/ui/components/token/TokenSymbol.tsx +4 -4
  246. package/src/react/web/wallets/ecosystem/EcosystemWalletFormUI.tsx +6 -10
  247. package/src/utils/extensions/drops/get-claim-params.ts +4 -2
  248. package/src/version.ts +1 -1
  249. package/src/wallets/in-app/web/ecosystem.ts +3 -14
  250. package/src/wallets/smart/index.ts +7 -24
  251. package/src/wallets/smart/lib/bundler.ts +6 -5
  252. package/src/wallets/smart/lib/userop.ts +81 -11
@@ -2,13 +2,24 @@
2
2
  import styled from "@emotion/styled";
3
3
  import { CrossCircledIcon, MagnifyingGlassIcon } from "@radix-ui/react-icons";
4
4
  import Fuse from "fuse.js";
5
- import { memo, useCallback, useEffect, useMemo, useState } from "react";
5
+ import {
6
+ Fragment,
7
+ memo,
8
+ useCallback,
9
+ useContext,
10
+ useEffect,
11
+ useMemo,
12
+ useState,
13
+ } from "react";
6
14
  import type React from "react";
7
- import type { Chain, ChainMetadata } from "../../../../chains/types.js";
8
- import { convertApiChainToChain } from "../../../../chains/utils.js";
15
+ import type { Chain } from "../../../../chains/types.js";
9
16
  import type { ThirdwebClient } from "../../../../client/client.js";
10
- import { useCustomTheme } from "../../../core/design-system/CustomThemeProvider.js";
11
17
  import {
18
+ CustomThemeProvider,
19
+ useCustomTheme,
20
+ } from "../../../core/design-system/CustomThemeProvider.js";
21
+ import {
22
+ type Theme,
12
23
  fontSize,
13
24
  iconSize,
14
25
  media,
@@ -16,12 +27,14 @@ import {
16
27
  spacing,
17
28
  } from "../../../core/design-system/index.js";
18
29
  import {
19
- useChainQuery,
20
- useChainsQuery,
30
+ useChainIconUrl,
31
+ useChainName,
21
32
  } from "../../../core/hooks/others/useChainQuery.js";
33
+ import { SetRootElementContext } from "../../../core/providers/RootElementContext.js";
22
34
  import { useActiveWalletChain } from "../../hooks/wallets/useActiveWalletChain.js";
23
35
  import { useSwitchActiveWalletChain } from "../../hooks/wallets/useSwitchActiveWalletChain.js";
24
36
  import { ChainIcon } from "../components/ChainIcon.js";
37
+ import { Modal } from "../components/Modal.js";
25
38
  import { Skeleton } from "../components/Skeleton.js";
26
39
  import { Spacer } from "../components/Spacer.js";
27
40
  import { Spinner } from "../components/Spinner.js";
@@ -33,10 +46,10 @@ import { Text } from "../components/text.js";
33
46
  import { StyledButton, StyledP, StyledUl } from "../design-system/elements.js";
34
47
  import { useDebouncedValue } from "../hooks/useDebouncedValue.js";
35
48
  import { useShowMore } from "../hooks/useShowMore.js";
49
+ import type { LocaleId } from "../types.js";
50
+ import { getConnectLocale } from "./locale/getConnectLocale.js";
36
51
  import type { ConnectLocale } from "./locale/types.js";
37
52
 
38
- // Note: Must not use useConnectUI here, because this component is also used outside of Connect UI context
39
-
40
53
  type NetworkSelectorChainProps = {
41
54
  /**
42
55
  * `Chain` object to be displayed
@@ -60,20 +73,47 @@ type NetworkSelectorChainProps = {
60
73
  close?: () => void;
61
74
  };
62
75
 
76
+ type ChainSection = {
77
+ label: string;
78
+ chains: Chain[];
79
+ };
80
+
63
81
  /**
64
82
  * @connectWallet
65
83
  */
66
84
  export type NetworkSelectorProps = {
67
85
  /**
68
86
  * Chains to be displayed as "Popular"
87
+ * @deprecated Use `sections` prop instead
88
+ *
89
+ * If `sections` prop is provided, this prop will be ignored
69
90
  */
70
91
  popularChainIds?: number[];
71
92
 
72
93
  /**
73
94
  * Chains to be displayed as "Recent"
95
+ * @deprecated Use `sections` prop instead
96
+ *
97
+ * If `sections` prop is provided, this prop will be ignored
74
98
  */
75
99
  recentChainIds?: number[];
76
100
 
101
+ /**
102
+ * Specify sections of chains to be displayed in the Network Selector Modal
103
+ *
104
+ * @example
105
+ * To display "Polygon", "Avalanche" chains under "Recently used" section and "Ethereum", "Arbitrum" chains under "Popular" section, you can set the prop with the following value
106
+ * ```ts
107
+ * import { arbitrum, base, ethereum, polygon } from "thirdweb/chains";
108
+ *
109
+ * const sections = [
110
+ * { label: 'Recently used', chains: [arbitrum, polygon] },
111
+ * { label: 'Popular', chains: [base, ethereum] },
112
+ * ]
113
+ * ```
114
+ */
115
+ sections?: Array<ChainSection>;
116
+
77
117
  /**
78
118
  * Override how the chain button is rendered in the Modal
79
119
  */
@@ -93,121 +133,6 @@ export type NetworkSelectorProps = {
93
133
  onCustomClick?: () => void;
94
134
  };
95
135
 
96
- let fuseInstances:
97
- | {
98
- all: Fuse<ChainMetadata>;
99
- popular: Fuse<ChainMetadata>;
100
- recent: Fuse<ChainMetadata>;
101
- }
102
- | undefined = undefined;
103
-
104
- let fuseInitializationStarted = false;
105
-
106
- // initialize fuse instances if not already initialized
107
- function initializeFuseInstances() {
108
- if (fuseInitializationStarted) {
109
- return;
110
- }
111
-
112
- fuseInitializationStarted = true;
113
-
114
- const fuseConfig = {
115
- threshold: 0.4,
116
- keys: [
117
- {
118
- name: "name",
119
- weight: 1,
120
- },
121
- {
122
- name: "chainId",
123
- weight: 1,
124
- },
125
- ],
126
- };
127
-
128
- fuseInstances = {
129
- all: new Fuse([], fuseConfig),
130
- popular: new Fuse([], fuseConfig),
131
- recent: new Fuse([], fuseConfig),
132
- };
133
- }
134
-
135
- type ChainData = {
136
- allChains: ChainMetadata[];
137
- popularChains: ChainMetadata[];
138
- recentChains: ChainMetadata[];
139
- isLoading: boolean;
140
- };
141
-
142
- function useLoadChains(
143
- allChainsInput: Chain[],
144
- popularChainIds: number[],
145
- recentChainIds: number[],
146
- ): ChainData {
147
- // load all chains with react query
148
- const chainsQueries = useChainsQuery(allChainsInput, 50);
149
-
150
- const isLoading = chainsQueries.some((q) => q.isLoading);
151
-
152
- const { allChains, chainsMap } = useMemo(() => {
153
- const _chains: ChainMetadata[] = [];
154
- const _chainsMap = new Map<number, ChainMetadata>();
155
-
156
- if (isLoading) {
157
- return { allChains: [], chainsMap: _chainsMap };
158
- }
159
-
160
- for (const chainQuery of chainsQueries) {
161
- if (chainQuery.data) {
162
- _chains.push({
163
- ...chainQuery.data,
164
- } as ChainMetadata);
165
- }
166
- }
167
-
168
- for (const chain of _chains) {
169
- _chainsMap.set(chain.chainId, chain);
170
- }
171
-
172
- return { allChains: _chains, chainsMap: _chainsMap, isLoading: false };
173
- }, [chainsQueries, isLoading]);
174
-
175
- const recentChains = useMemo(() => {
176
- if (!recentChainIds) {
177
- return [];
178
- }
179
- const _recentChains: ChainMetadata[] = [];
180
- for (const chainId of recentChainIds) {
181
- const _chain = chainsMap.get(chainId);
182
- if (_chain) {
183
- _recentChains.push(_chain);
184
- }
185
- }
186
- return _recentChains;
187
- }, [recentChainIds, chainsMap]);
188
-
189
- const popularChains = useMemo(() => {
190
- if (!popularChainIds) {
191
- return [];
192
- }
193
- const _popularChains: ChainMetadata[] = [];
194
- for (const chainId of popularChainIds) {
195
- const _chain = chainsMap.get(chainId);
196
- if (_chain) {
197
- _popularChains.push(_chain);
198
- }
199
- }
200
- return _popularChains;
201
- }, [popularChainIds, chainsMap]);
202
-
203
- return {
204
- allChains,
205
- popularChains,
206
- recentChains,
207
- isLoading,
208
- };
209
- }
210
-
211
136
  type NetworkSelectorContentProps = {
212
137
  onBack?: () => void;
213
138
  closeModal: () => void;
@@ -221,36 +146,9 @@ type NetworkSelectorContentProps = {
221
146
  /**
222
147
  * @internal
223
148
  */
224
- export function NetworkSelectorContent(props: NetworkSelectorContentProps) {
225
- const chainsData = useLoadChains(
226
- props.chains,
227
- props.networkSelector?.popularChainIds || [],
228
- props.networkSelector?.recentChainIds || [],
229
- );
230
149
 
231
- initializeFuseInstances();
232
-
233
- return <NetworkSelectorContentInner {...props} chainsData={chainsData} />;
234
- }
235
-
236
- function NetworkSelectorContentInner(
237
- props: NetworkSelectorContentProps & {
238
- chainsData: ChainData;
239
- connectLocale: ConnectLocale;
240
- client: ThirdwebClient;
241
- },
242
- ) {
243
- const { chainsData, connectLocale } = props;
244
-
245
- const chainMap = useMemo(() => {
246
- const _chainMap = new Map<number, Chain>();
247
- for (const chain of props.chains) {
248
- _chainMap.set(chain.id, chain);
249
- }
250
- return _chainMap;
251
- }, [props.chains]);
252
-
253
- const locale = connectLocale.networkSelector;
150
+ export function NetworkSelectorContent(props: NetworkSelectorContentProps) {
151
+ const locale = props.connectLocale.networkSelector;
254
152
  const [searchTerm, setSearchTerm] = useState("");
255
153
  const [selectedTab, setSelectedTab] = useState<"all" | "mainnet" | "testnet">(
256
154
  "all",
@@ -259,57 +157,182 @@ function NetworkSelectorContentInner(
259
157
 
260
158
  const { onSwitch, onCustomClick } = props.networkSelector || {};
261
159
 
262
- const allChainsTab = useMemo(() => {
263
- return filterChainByType(chainsData.allChains, selectedTab);
264
- }, [chainsData.allChains, selectedTab]);
265
-
266
- const popularChainsTab = useMemo(() => {
267
- return filterChainByType(chainsData.popularChains, selectedTab);
268
- }, [chainsData.popularChains, selectedTab]);
160
+ // labels
161
+ const othersLabel = locale.categoryLabel.others;
162
+ const popularLabel = locale.categoryLabel.popular;
163
+ const recentLabel = locale.categoryLabel.recentlyUsed;
269
164
 
270
- const recentChainsTab = useMemo(() => {
271
- return filterChainByType(chainsData.recentChains, selectedTab);
272
- }, [chainsData.recentChains, selectedTab]);
165
+ // create sections, chainToSectionMap and allChains
166
+ const { chainSections, allChains, allChainsToSectionMap } = useMemo(() => {
167
+ const chainSectionsValue: ChainSection[] = [];
168
+ const allChainsValue: Chain[] = [];
169
+ const allChainsToSectionMapValue: Map<number, string> = new Map();
273
170
 
274
- // chains filtered by search term + type
275
- const allChainsFiltered = useMemo(() => {
276
- if (!fuseInstances) {
277
- return allChainsTab;
171
+ function addChain(c: Chain, section: string) {
172
+ allChainsToSectionMapValue.set(c.id, section);
173
+ allChainsValue.push(c);
278
174
  }
279
175
 
280
- if (deferredSearchTerm === "") {
281
- return allChainsTab;
176
+ // if new API is used
177
+ if (props.networkSelector?.sections) {
178
+ for (const s of props.networkSelector.sections) {
179
+ const chainsToAdd = s.chains.filter(
180
+ (c) => !allChainsToSectionMapValue.has(c.id),
181
+ );
182
+ if (chainsToAdd.length > 0) {
183
+ chainSectionsValue.push({
184
+ label: s.label,
185
+ chains: chainsToAdd,
186
+ });
187
+ for (const c of chainsToAdd) {
188
+ addChain(c, s.label);
189
+ }
190
+ }
191
+ }
282
192
  }
283
193
 
284
- fuseInstances.all.setCollection(allChainsTab);
285
- return fuseInstances.all.search(deferredSearchTerm).map((r) => r.item);
286
- }, [allChainsTab, deferredSearchTerm]);
194
+ // if old API is used
195
+ else {
196
+ const allChainsMap = new Map(props.chains.map((c) => [c.id, c]));
197
+ // add all recent chains
198
+ if (
199
+ props.networkSelector?.recentChainIds &&
200
+ props.networkSelector?.recentChainIds.length > 0
201
+ ) {
202
+ const recentChains = props.networkSelector.recentChainIds
203
+ .map((id) => allChainsMap.get(id))
204
+ .filter((c) => c !== undefined);
205
+
206
+ chainSectionsValue.push({
207
+ label: recentLabel,
208
+ chains: recentChains,
209
+ });
210
+ for (const c of recentChains) {
211
+ addChain(c, recentLabel);
212
+ }
213
+ }
287
214
 
288
- const popularChainsFiltered = useMemo(() => {
289
- if (!fuseInstances) {
290
- return popularChainsTab;
215
+ // then add all popular chains ( exclude already added chains )
216
+ if (
217
+ props.networkSelector?.popularChainIds &&
218
+ props.networkSelector.popularChainIds.length > 0
219
+ ) {
220
+ const popularChains = props.networkSelector.popularChainIds
221
+ .map((id) => allChainsMap.get(id))
222
+ .filter((c) => c !== undefined);
223
+
224
+ const chainsToAdd = popularChains.filter(
225
+ (c) => !allChainsToSectionMapValue.has(c.id),
226
+ );
227
+ if (chainsToAdd.length > 0) {
228
+ chainSectionsValue.push({
229
+ label: popularLabel,
230
+ chains: chainsToAdd,
231
+ });
232
+ for (const c of chainsToAdd) {
233
+ addChain(c, popularLabel);
234
+ }
235
+ }
236
+ }
291
237
  }
292
238
 
293
- if (deferredSearchTerm === "") {
294
- return popularChainsTab;
239
+ // add all other chains ( exclude already added chains )
240
+ const otherChainsToAdd = props.chains.filter(
241
+ (c) => !allChainsToSectionMapValue.has(c.id),
242
+ );
243
+ if (otherChainsToAdd.length > 0) {
244
+ chainSectionsValue.push({
245
+ label: othersLabel,
246
+ chains: otherChainsToAdd,
247
+ });
248
+ for (const c of otherChainsToAdd) {
249
+ addChain(c, othersLabel);
250
+ }
295
251
  }
296
252
 
297
- fuseInstances.popular.setCollection(popularChainsTab);
298
- return fuseInstances.popular.search(deferredSearchTerm).map((r) => r.item);
299
- }, [deferredSearchTerm, popularChainsTab]);
253
+ return {
254
+ chainSections: chainSectionsValue,
255
+ allChains: allChainsValue,
256
+ allChainsToSectionMap: allChainsToSectionMapValue,
257
+ };
258
+ }, [
259
+ props.networkSelector?.sections,
260
+ props.networkSelector?.recentChainIds,
261
+ props.networkSelector?.popularChainIds,
262
+ props.chains,
263
+ recentLabel,
264
+ popularLabel,
265
+ othersLabel,
266
+ ]);
300
267
 
301
- const recentChainsFiltered = useMemo(() => {
302
- if (!fuseInstances) {
303
- return recentChainsTab;
304
- }
268
+ // fuse instance for searching
269
+ const fuse = useMemo(() => {
270
+ return new Fuse(allChains, {
271
+ threshold: 0.4,
272
+ keys: [
273
+ {
274
+ name: "name",
275
+ weight: 1,
276
+ },
277
+ {
278
+ name: "chainId",
279
+ weight: 1,
280
+ },
281
+ ],
282
+ });
283
+ }, [allChains]);
284
+
285
+ // chains filtered by search term
286
+ const searchedChainSections =
287
+ useMemo(() => {
288
+ if (deferredSearchTerm === "") {
289
+ return undefined;
290
+ }
291
+
292
+ const filteredChainSectionsValue: ChainSection[] = [];
293
+
294
+ const filteredAllChains = fuse
295
+ .search(deferredSearchTerm)
296
+ .map((r) => r.item);
297
+
298
+ for (const c of filteredAllChains) {
299
+ const label = allChainsToSectionMap.get(c.id);
300
+ if (!label) {
301
+ return; // just a type guard, this never happens
302
+ }
303
+
304
+ const section = filteredChainSectionsValue.find(
305
+ (s) => s.label === label,
306
+ );
307
+ if (section) {
308
+ section.chains.push(c);
309
+ } else {
310
+ filteredChainSectionsValue.push({
311
+ label,
312
+ chains: [c],
313
+ });
314
+ }
315
+
316
+ return filteredChainSectionsValue;
317
+ }
305
318
 
306
- if (deferredSearchTerm === "") {
307
- return recentChainsTab;
319
+ return filteredChainSectionsValue;
320
+ }, [deferredSearchTerm, fuse, allChainsToSectionMap]) || chainSections;
321
+
322
+ const filteredChainSections = useMemo(() => {
323
+ if (selectedTab === "all") {
324
+ return searchedChainSections;
308
325
  }
309
326
 
310
- fuseInstances.recent.setCollection(recentChainsTab);
311
- return fuseInstances.recent.search(deferredSearchTerm).map((r) => r.item);
312
- }, [deferredSearchTerm, recentChainsTab]);
327
+ return searchedChainSections.map((section) => ({
328
+ label: section.label,
329
+ chains: section.chains.filter(
330
+ (c) =>
331
+ (selectedTab === "mainnet" && !c.testnet) ||
332
+ (selectedTab === "testnet" && c.testnet),
333
+ ),
334
+ }));
335
+ }, [searchedChainSections, selectedTab]);
313
336
 
314
337
  const handleSwitch = useCallback(
315
338
  (chain: Chain) => {
@@ -321,45 +344,6 @@ function NetworkSelectorContentInner(
321
344
  [onSwitch, props],
322
345
  );
323
346
 
324
- const allChainsToShow = useMemo(() => {
325
- if (chainsData.isLoading) {
326
- return props.chains;
327
- }
328
- return allChainsFiltered.map(convertApiChainToChain);
329
- }, [allChainsFiltered, chainsData.isLoading, props.chains]);
330
-
331
- const popularChainsToShow = useMemo(() => {
332
- if (chainsData.isLoading) {
333
- return (
334
- props.networkSelector?.popularChainIds?.map(
335
- (id) => chainMap.get(id) as Chain,
336
- ) || []
337
- );
338
- }
339
- return popularChainsFiltered.map(convertApiChainToChain);
340
- }, [
341
- chainMap,
342
- chainsData.isLoading,
343
- popularChainsFiltered,
344
- props.networkSelector?.popularChainIds,
345
- ]);
346
-
347
- const recentChainsToShow = useMemo(() => {
348
- if (chainsData.isLoading) {
349
- return (
350
- props.networkSelector?.recentChainIds?.map(
351
- (id) => chainMap.get(id) as Chain,
352
- ) || []
353
- );
354
- }
355
- return recentChainsFiltered.map(convertApiChainToChain);
356
- }, [
357
- chainMap,
358
- chainsData.isLoading,
359
- props.networkSelector?.recentChainIds,
360
- recentChainsFiltered,
361
- ]);
362
-
363
347
  return (
364
348
  <Container>
365
349
  <Container p="lg">
@@ -418,19 +402,14 @@ function NetworkSelectorContentInner(
418
402
  }}
419
403
  tabIndex={-1}
420
404
  variant="outline"
421
- disabled={chainsData.isLoading}
422
- placeholder={
423
- chainsData.isLoading
424
- ? "Loading chains..."
425
- : locale.inputPlaceholder
426
- }
405
+ placeholder={locale.inputPlaceholder}
427
406
  value={searchTerm}
428
407
  onChange={(e) => {
429
408
  setSearchTerm(e.target.value);
430
409
  }}
431
410
  />
432
411
  {/* Searching Spinner */}
433
- {(deferredSearchTerm !== searchTerm || chainsData.isLoading) && (
412
+ {deferredSearchTerm !== searchTerm && (
434
413
  <div
435
414
  style={{
436
415
  position: "absolute",
@@ -445,12 +424,10 @@ function NetworkSelectorContentInner(
445
424
  <Spacer y="lg" />
446
425
  <Container px="md">
447
426
  <NetworkTabContent
448
- allChainIds={allChainsToShow}
449
- popularChainIds={popularChainsToShow}
450
- recentChainIds={recentChainsToShow}
427
+ chainSections={filteredChainSections}
451
428
  onSwitch={handleSwitch}
452
429
  renderChain={props.networkSelector?.renderChain}
453
- connectLocale={connectLocale}
430
+ connectLocale={props.connectLocale}
454
431
  client={props.client}
455
432
  close={props.closeModal}
456
433
  />
@@ -480,47 +457,23 @@ function NetworkSelectorContentInner(
480
457
  );
481
458
  }
482
459
 
483
- /**
484
- *
485
- * @internal
486
- */
487
- const filterChainByType = (
488
- chains: ChainMetadata[],
489
- type: "testnet" | "mainnet" | "all",
490
- ) => {
491
- if (type === "all") {
492
- return chains;
493
- }
494
-
495
- if (type === "testnet") {
496
- return chains.filter((c) => c.testnet);
497
- }
498
-
499
- return chains.filter((c) => !c.testnet);
500
- };
501
-
502
460
  /**
503
461
  *
504
462
  * @internal
505
463
  */
506
464
  const NetworkTabContent = (props: {
507
- allChainIds: Chain[];
508
- recentChainIds?: Chain[];
509
- popularChainIds?: Chain[];
465
+ chainSections: Array<ChainSection>;
510
466
  onSwitch: (chain: Chain) => void;
511
467
  renderChain?: React.FC<NetworkSelectorChainProps>;
512
468
  close?: () => void;
513
469
  connectLocale: ConnectLocale;
514
470
  client: ThirdwebClient;
515
471
  }) => {
516
- const locale = props.connectLocale.networkSelector.categoryLabel;
517
-
518
- const { recentChainIds, popularChainIds, allChainIds } = props;
472
+ const { chainSections } = props;
519
473
 
520
- const noChainsToShow =
521
- recentChainIds?.length === 0 &&
522
- popularChainIds?.length === 0 &&
523
- allChainIds.length === 0;
474
+ const noChainsToShow = chainSections.every(
475
+ (section) => section.chains.length === 0,
476
+ );
524
477
 
525
478
  return (
526
479
  <Container
@@ -531,62 +484,34 @@ const NetworkTabContent = (props: {
531
484
  paddingBottom: spacing.lg,
532
485
  }}
533
486
  >
534
- {recentChainIds && recentChainIds.length > 0 && (
535
- <div>
536
- <SectionLabel>{locale.recentlyUsed}</SectionLabel>
537
- <Spacer y="sm" />
538
- <NetworkList
539
- chains={recentChainIds}
540
- onSwitch={props.onSwitch}
541
- renderChain={props.renderChain}
542
- close={props.close}
543
- client={props.client}
544
- connectLocale={props.connectLocale}
545
- />
546
- <Spacer y="lg" />
547
- </div>
548
- )}
549
-
550
- {popularChainIds && popularChainIds.length > 0 && (
551
- <div>
552
- <SectionLabel>{locale.popular}</SectionLabel>
553
- <Spacer y="sm" />
554
- <NetworkList
555
- chains={popularChainIds}
556
- onSwitch={props.onSwitch}
557
- renderChain={props.renderChain}
558
- close={props.close}
559
- client={props.client}
560
- connectLocale={props.connectLocale}
561
- />
562
- <Spacer y="lg" />
563
- </div>
564
- )}
565
-
566
- {/* separator */}
567
- {((popularChainIds && popularChainIds.length > 0) ||
568
- (recentChainIds && recentChainIds.length > 0)) && (
569
- <>
570
- <SectionLabel>{locale.others}</SectionLabel>
571
- <Spacer y="sm" />
572
- </>
573
- )}
574
-
575
- <NetworkList
576
- chains={allChainIds}
577
- onSwitch={props.onSwitch}
578
- renderChain={props.renderChain}
579
- close={props.close}
580
- client={props.client}
581
- connectLocale={props.connectLocale}
582
- />
583
-
584
- {noChainsToShow && (
487
+ {/* empty state */}
488
+ {noChainsToShow ? (
585
489
  <Container flex="column" gap="md" center="both" color="secondaryText">
586
490
  <Spacer y="xl" />
587
491
  <CrossCircledIcon width={iconSize.xl} height={iconSize.xl} />
588
492
  <Text> No Results </Text>
589
493
  </Container>
494
+ ) : (
495
+ chainSections.map((section, idx) => {
496
+ if (section.chains.length === 0) {
497
+ return null;
498
+ }
499
+ return (
500
+ <Fragment key={section.label}>
501
+ {idx !== 0 && <Spacer y="lg" />}
502
+ <SectionLabel>{section.label}</SectionLabel>
503
+ <Spacer y="xs" />
504
+ <NetworkList
505
+ chains={section.chains}
506
+ onSwitch={props.onSwitch}
507
+ renderChain={props.renderChain}
508
+ close={props.close}
509
+ client={props.client}
510
+ connectLocale={props.connectLocale}
511
+ />
512
+ </Fragment>
513
+ );
514
+ })
590
515
  )}
591
516
  </Container>
592
517
  );
@@ -691,11 +616,13 @@ export const ChainButton = /* @__PURE__ */ memo(function ChainButton(props: {
691
616
  const { chain, confirming, switchingFailed } = props;
692
617
 
693
618
  const activeChain = useActiveWalletChain();
694
- const { data: fetchedChain } = useChainQuery(chain);
619
+
620
+ const chainNameQuery = useChainName(chain);
621
+ const chainIconQuery = useChainIconUrl(chain);
695
622
 
696
623
  let chainName: React.ReactNode;
697
- if (fetchedChain) {
698
- chainName = <span>{fetchedChain.name} </span>;
624
+ if (chainNameQuery.name) {
625
+ chainName = <span>{chainNameQuery.name} </span>;
699
626
  } else {
700
627
  chainName = <Skeleton width="150px" height="20px" />;
701
628
  }
@@ -705,9 +632,9 @@ export const ChainButton = /* @__PURE__ */ memo(function ChainButton(props: {
705
632
  data-active={activeChain?.id === chain.id}
706
633
  onClick={props.onClick}
707
634
  >
708
- {fetchedChain ? (
635
+ {!chainIconQuery.isLoading ? (
709
636
  <ChainIcon
710
- chainIcon={fetchedChain.icon}
637
+ chainIconUrl={chainIconQuery.url}
711
638
  size={iconSize.lg}
712
639
  active={activeChain?.id === chain.id}
713
640
  loading="lazy"
@@ -830,3 +757,174 @@ const StyledMagnifyingGlassIcon = /* @__PURE__ */ styled(MagnifyingGlassIcon)(
830
757
  };
831
758
  },
832
759
  );
760
+
761
+ /**
762
+ * Options for the `useNetworkSwitcherModal` hook's returned `open` function
763
+ * @connectWallet
764
+ */
765
+ export type UseNetworkSwitcherModalOptions = {
766
+ /**
767
+ * Set the theme for the `NetworkSwitcher` Modal. By default it is set to `"dark"`
768
+ *
769
+ * theme can be set to either `"dark"`, `"light"` or a custom theme object.
770
+ *
771
+ * You can also import [`lightTheme`](https://portal.thirdweb.com/references/typescript/v5/lightTheme)
772
+ * or [`darkTheme`](https://portal.thirdweb.com/references/typescript/v5/darkTheme)
773
+ * functions from `thirdweb/react` to use the default themes as base and overrides parts of it.
774
+ * @example
775
+ * ```ts
776
+ * import { lightTheme } from "thirdweb/react";
777
+ *
778
+ * const customTheme = lightTheme({
779
+ * colors: {
780
+ * modalBg: 'red'
781
+ * }
782
+ * })
783
+ * ```
784
+ */
785
+ theme?: Theme | "dark" | "light";
786
+
787
+ /**
788
+ * Specify sections of chains to be displayed in the Network Selector Modal
789
+ *
790
+ * @example
791
+ * To display "Polygon", "Avalanche" chains under "Recently used" section and "Ethereum", "Arbitrum" chains under "Popular" section, you can set the prop with the following value
792
+ * ```ts
793
+ * import { arbitrum, base, ethereum, polygon } from "thirdweb/chains";
794
+ *
795
+ * const sections = [
796
+ * { label: 'Recently used', chains: [arbitrum, polygon] },
797
+ * { label: 'Popular', chains: [base, ethereum] },
798
+ * ]
799
+ * ```
800
+ */
801
+ sections?: Array<ChainSection>;
802
+
803
+ /**
804
+ * Override how the chain button is rendered in the Modal
805
+ */
806
+ renderChain?: React.FC<NetworkSelectorChainProps>;
807
+
808
+ /**
809
+ * Callback to be called when a chain is successfully switched
810
+ * @param chain - The `Chain` of the chain that was switched to
811
+ */
812
+ onSwitch?: (chain: Chain) => void;
813
+
814
+ /**
815
+ * Callback to be called when the "Add Custom Network" button is clicked
816
+ *
817
+ * The "Add Custom Network" button is displayed at the bottom of the modal - only if this prop is provided
818
+ */
819
+ onCustomClick?: () => void;
820
+
821
+ /**
822
+ * A client is the entry point to the thirdweb SDK.
823
+ * It is required for all other actions.
824
+ * You can create a client using the `createThirdwebClient` function. Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
825
+ *
826
+ * You must provide a `clientId` or `secretKey` in order to initialize a client. Pass `clientId` if you want for client-side usage and `secretKey` for server-side usage.
827
+ *
828
+ * ```tsx
829
+ * import { createThirdwebClient } from "thirdweb";
830
+ *
831
+ * const client = createThirdwebClient({
832
+ * clientId: "<your_client_id>",
833
+ * })
834
+ * ```
835
+ */
836
+ client: ThirdwebClient;
837
+
838
+ /**
839
+ * By default - NetworkSwitcher UI uses the `en-US` locale for english language users.
840
+ *
841
+ * You can customize the language used in the ConnectButton UI by setting the `locale` prop.
842
+ *
843
+ * Refer to the [`LocaleId`](https://portal.thirdweb.com/references/typescript/v5/LocaleId) type for supported locales.
844
+ */
845
+ locale?: LocaleId;
846
+ };
847
+
848
+ /**
849
+ * Hook to open the Wallet Network Switcher Modal that shows allows users to switch to different network.
850
+ *
851
+ * @example
852
+ * ```tsx
853
+ * import { createThirdwebClient } from "thirdweb";
854
+ * import { useNetworkSwitcherModal } from "thirdweb/react";
855
+ * import { base, ethereum, polygon, sepolia, arbitrum } from "thirdweb/chains";
856
+ *
857
+ * const client = createThirdwebClient({
858
+ * clientId: "<your_client_id>",
859
+ * });
860
+ *
861
+ * function Example() {
862
+ * const networkSwitcher = useNetworkSwitcherModal();
863
+ *
864
+ * function handleClick() {
865
+ * networkSwitcher.open({
866
+ * client,
867
+ * theme: 'light'
868
+ * sections: [
869
+ * { label: 'Recently used', chains: [arbitrum, polygon] },
870
+ * { label: 'Popular', chains: [base, ethereum, sepolia] },
871
+ * ]
872
+ * });
873
+ * }
874
+ *
875
+ * return <button onClick={handleClick}> Switch Network </button>
876
+ * }
877
+ * ```
878
+ */
879
+ export function useNetworkSwitcherModal() {
880
+ const activeChain = useActiveWalletChain();
881
+ const setRootEl = useContext(SetRootElementContext);
882
+
883
+ const closeModal = useCallback(() => {
884
+ setRootEl(null);
885
+ }, [setRootEl]);
886
+
887
+ const openNetworkSwitcher = useCallback(
888
+ async (props: UseNetworkSwitcherModalOptions) => {
889
+ if (!activeChain) {
890
+ throw new Error("No active wallet found");
891
+ }
892
+ const locale = await getConnectLocale(props.locale || "en_US");
893
+ setRootEl(
894
+ <CustomThemeProvider theme={props.theme}>
895
+ <Modal
896
+ size={"compact"}
897
+ open={true}
898
+ setOpen={(value) => {
899
+ if (!value) {
900
+ closeModal();
901
+ }
902
+ }}
903
+ style={{
904
+ paddingBottom: props.onCustomClick ? spacing.md : "0px",
905
+ }}
906
+ >
907
+ <NetworkSelectorContent
908
+ client={props.client}
909
+ closeModal={closeModal}
910
+ chains={[activeChain]}
911
+ connectLocale={locale}
912
+ networkSelector={{
913
+ onCustomClick: props.onCustomClick,
914
+ onSwitch: props.onSwitch,
915
+ renderChain: props.renderChain,
916
+ sections: props.sections,
917
+ }}
918
+ />
919
+ </Modal>
920
+ </CustomThemeProvider>,
921
+ );
922
+ },
923
+ [setRootEl, closeModal, activeChain],
924
+ );
925
+
926
+ return {
927
+ open: openNetworkSwitcher,
928
+ close: closeModal,
929
+ };
930
+ }