thirdweb 5.75.0 → 5.76.0-nightly-8234dbae8fcf73ca83bbda31d929aa57ca521a53-20241208000407

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 (129) hide show
  1. package/dist/cjs/exports/react.js.map +1 -1
  2. package/dist/cjs/exports/utils.js +5 -1
  3. package/dist/cjs/exports/utils.js.map +1 -1
  4. package/dist/cjs/pay/convert/cryptoToFiat.js.map +1 -1
  5. package/dist/cjs/pay/convert/fiatToCrypto.js +1 -1
  6. package/dist/cjs/pay/convert/fiatToCrypto.js.map +1 -1
  7. package/dist/cjs/pay/convert/type.js +4 -0
  8. package/dist/cjs/pay/convert/type.js.map +1 -0
  9. package/dist/cjs/react/web/ui/ConnectWallet/Details.js +56 -16
  10. package/dist/cjs/react/web/ui/ConnectWallet/Details.js.map +1 -1
  11. package/dist/cjs/react/web/ui/ConnectWallet/screens/ReceiveFunds.js +1 -1
  12. package/dist/cjs/react/web/ui/ConnectWallet/screens/ReceiveFunds.js.map +1 -1
  13. package/dist/cjs/react/web/ui/ConnectWallet/screens/SendFunds.js +3 -2
  14. package/dist/cjs/react/web/ui/ConnectWallet/screens/SendFunds.js.map +1 -1
  15. package/dist/cjs/react/web/ui/components/CopyIcon.js +1 -1
  16. package/dist/cjs/react/web/ui/components/CopyIcon.js.map +1 -1
  17. package/dist/cjs/react/web/ui/components/Skeleton.js +1 -1
  18. package/dist/cjs/react/web/ui/components/Skeleton.js.map +1 -1
  19. package/dist/cjs/react/web/ui/prebuilt/Account/balance.js +114 -26
  20. package/dist/cjs/react/web/ui/prebuilt/Account/balance.js.map +1 -1
  21. package/dist/cjs/react/web/ui/prebuilt/Account/provider.js +3 -0
  22. package/dist/cjs/react/web/ui/prebuilt/Account/provider.js.map +1 -1
  23. package/dist/cjs/utils/formatNumber.js +7 -1
  24. package/dist/cjs/utils/formatNumber.js.map +1 -1
  25. package/dist/cjs/utils/shortenLargeNumber.js +47 -0
  26. package/dist/cjs/utils/shortenLargeNumber.js.map +1 -0
  27. package/dist/cjs/version.js +1 -1
  28. package/dist/cjs/version.js.map +1 -1
  29. package/dist/cjs/wallets/manager/index.js +35 -24
  30. package/dist/cjs/wallets/manager/index.js.map +1 -1
  31. package/dist/esm/exports/react.js.map +1 -1
  32. package/dist/esm/exports/utils.js +2 -0
  33. package/dist/esm/exports/utils.js.map +1 -1
  34. package/dist/esm/pay/convert/cryptoToFiat.js.map +1 -1
  35. package/dist/esm/pay/convert/fiatToCrypto.js +1 -1
  36. package/dist/esm/pay/convert/fiatToCrypto.js.map +1 -1
  37. package/dist/esm/pay/convert/type.js +3 -0
  38. package/dist/esm/pay/convert/type.js.map +1 -0
  39. package/dist/esm/react/web/ui/ConnectWallet/Details.js +57 -23
  40. package/dist/esm/react/web/ui/ConnectWallet/Details.js.map +1 -1
  41. package/dist/esm/react/web/ui/ConnectWallet/screens/ReceiveFunds.js +1 -1
  42. package/dist/esm/react/web/ui/ConnectWallet/screens/ReceiveFunds.js.map +1 -1
  43. package/dist/esm/react/web/ui/ConnectWallet/screens/SendFunds.js +3 -3
  44. package/dist/esm/react/web/ui/ConnectWallet/screens/SendFunds.js.map +1 -1
  45. package/dist/esm/react/web/ui/components/CopyIcon.js +1 -1
  46. package/dist/esm/react/web/ui/components/CopyIcon.js.map +1 -1
  47. package/dist/esm/react/web/ui/components/Skeleton.js +1 -1
  48. package/dist/esm/react/web/ui/components/Skeleton.js.map +1 -1
  49. package/dist/esm/react/web/ui/prebuilt/Account/balance.js +113 -28
  50. package/dist/esm/react/web/ui/prebuilt/Account/balance.js.map +1 -1
  51. package/dist/esm/react/web/ui/prebuilt/Account/provider.js +3 -0
  52. package/dist/esm/react/web/ui/prebuilt/Account/provider.js.map +1 -1
  53. package/dist/esm/utils/formatNumber.js +7 -1
  54. package/dist/esm/utils/formatNumber.js.map +1 -1
  55. package/dist/esm/utils/shortenLargeNumber.js +44 -0
  56. package/dist/esm/utils/shortenLargeNumber.js.map +1 -0
  57. package/dist/esm/version.js +1 -1
  58. package/dist/esm/version.js.map +1 -1
  59. package/dist/esm/wallets/manager/index.js +33 -24
  60. package/dist/esm/wallets/manager/index.js.map +1 -1
  61. package/dist/types/exports/react.d.ts +1 -1
  62. package/dist/types/exports/react.d.ts.map +1 -1
  63. package/dist/types/exports/utils.d.ts +2 -0
  64. package/dist/types/exports/utils.d.ts.map +1 -1
  65. package/dist/types/pay/convert/cryptoToFiat.d.ts +2 -1
  66. package/dist/types/pay/convert/cryptoToFiat.d.ts.map +1 -1
  67. package/dist/types/pay/convert/fiatToCrypto.d.ts +2 -1
  68. package/dist/types/pay/convert/fiatToCrypto.d.ts.map +1 -1
  69. package/dist/types/pay/convert/type.d.ts +7 -0
  70. package/dist/types/pay/convert/type.d.ts.map +1 -0
  71. package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts +11 -0
  72. package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts.map +1 -1
  73. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts +60 -0
  74. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts.map +1 -1
  75. package/dist/types/react/web/ui/ConnectWallet/screens/ReceiveFunds.d.ts.map +1 -1
  76. package/dist/types/react/web/ui/ConnectWallet/screens/SendFunds.d.ts +15 -0
  77. package/dist/types/react/web/ui/ConnectWallet/screens/SendFunds.d.ts.map +1 -1
  78. package/dist/types/react/web/ui/components/CopyIcon.d.ts.map +1 -1
  79. package/dist/types/react/web/ui/components/Skeleton.d.ts +1 -0
  80. package/dist/types/react/web/ui/components/Skeleton.d.ts.map +1 -1
  81. package/dist/types/react/web/ui/prebuilt/Account/balance.d.ts +58 -9
  82. package/dist/types/react/web/ui/prebuilt/Account/balance.d.ts.map +1 -1
  83. package/dist/types/react/web/ui/prebuilt/Account/provider.d.ts.map +1 -1
  84. package/dist/types/utils/formatNumber.d.ts +7 -1
  85. package/dist/types/utils/formatNumber.d.ts.map +1 -1
  86. package/dist/types/utils/shortenLargeNumber.d.ts +16 -0
  87. package/dist/types/utils/shortenLargeNumber.d.ts.map +1 -0
  88. package/dist/types/version.d.ts +1 -1
  89. package/dist/types/version.d.ts.map +1 -1
  90. package/dist/types/wallets/manager/index.d.ts +4 -0
  91. package/dist/types/wallets/manager/index.d.ts.map +1 -1
  92. package/dist/types/wallets/wallet-connect/types.d.ts +1 -1
  93. package/dist/types/wallets/wallet-connect/types.d.ts.map +1 -1
  94. package/dist/types/wallets/wallet-types.d.ts +1 -1
  95. package/package.json +7 -6
  96. package/src/exports/react.ts +1 -0
  97. package/src/exports/utils.ts +3 -0
  98. package/src/pay/convert/cryptoToFiat.test.ts +21 -1
  99. package/src/pay/convert/cryptoToFiat.ts +2 -1
  100. package/src/pay/convert/fiatToCrypto.test.ts +21 -1
  101. package/src/pay/convert/fiatToCrypto.ts +3 -2
  102. package/src/pay/convert/type.ts +5 -0
  103. package/src/react/core/hooks/connection/ConnectButtonProps.ts +13 -0
  104. package/src/react/web/ui/ConnectWallet/ConnectButton.test.tsx +15 -0
  105. package/src/react/web/ui/ConnectWallet/Details.test.tsx +587 -0
  106. package/src/react/web/ui/ConnectWallet/Details.tsx +174 -67
  107. package/src/react/web/ui/ConnectWallet/screens/PrivateKey.test.tsx +54 -0
  108. package/src/react/web/ui/ConnectWallet/screens/ReceiveFunds.test.tsx +37 -0
  109. package/src/react/web/ui/ConnectWallet/screens/ReceiveFunds.tsx +6 -1
  110. package/src/react/web/ui/ConnectWallet/screens/SendFunds.test.tsx +67 -0
  111. package/src/react/web/ui/ConnectWallet/screens/SendFunds.tsx +3 -2
  112. package/src/react/web/ui/ConnectWallet/screens/StartScreen.test.tsx +71 -0
  113. package/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.test.ts +60 -0
  114. package/src/react/web/ui/ConnectWallet/screens/nativeToken.test.ts +42 -0
  115. package/src/react/web/ui/components/CopyIcon.tsx +5 -1
  116. package/src/react/web/ui/components/Skeleton.tsx +2 -0
  117. package/src/react/web/ui/prebuilt/Account/balance.test.tsx +167 -36
  118. package/src/react/web/ui/prebuilt/Account/balance.tsx +168 -28
  119. package/src/react/web/ui/prebuilt/Account/provider.test.tsx +16 -0
  120. package/src/react/web/ui/prebuilt/Account/provider.tsx +5 -0
  121. package/src/utils/formatNumber.ts +7 -1
  122. package/src/utils/shortenLargeNumber.test.ts +30 -0
  123. package/src/utils/shortenLargeNumber.ts +48 -0
  124. package/src/version.ts +1 -1
  125. package/src/wallets/manager/connection-manager.test.ts +290 -3
  126. package/src/wallets/manager/index.ts +45 -32
  127. package/src/wallets/wallet-connect/receiver/receiver.test.ts +1 -1
  128. package/src/wallets/wallet-connect/types.ts +1 -1
  129. package/src/wallets/wallet-types.ts +1 -1
@@ -9,15 +9,15 @@ import {
9
9
  TextAlignJustifyIcon,
10
10
  } from "@radix-ui/react-icons";
11
11
  import { useQuery } from "@tanstack/react-query";
12
- import { type JSX, useContext, useEffect, useState } from "react";
12
+ import { type JSX, useCallback, useContext, useEffect, useState } from "react";
13
13
  import { trackPayEvent } from "../../../../analytics/track/pay.js";
14
14
  import type { Chain } from "../../../../chains/types.js";
15
15
  import type { ThirdwebClient } from "../../../../client/client.js";
16
16
  import { getContract } from "../../../../contract/contract.js";
17
+ import type { SupportedFiatCurrency } from "../../../../pay/convert/type.js";
17
18
  import { getLastAuthProvider } from "../../../../react/core/utils/storage.js";
18
19
  import { shortenAddress } from "../../../../utils/address.js";
19
20
  import { isContractDeployed } from "../../../../utils/bytecode/is-contract-deployed.js";
20
- import { formatNumber } from "../../../../utils/formatNumber.js";
21
21
  import { webLocalStorage } from "../../../../utils/storage/webStorage.js";
22
22
  import { isEcosystemWallet } from "../../../../wallets/ecosystem/is-ecosystem-wallet.js";
23
23
  import type { Ecosystem } from "../../../../wallets/in-app/core/wallet/types.js";
@@ -86,7 +86,12 @@ import { fadeInAnimation } from "../design-system/animations.js";
86
86
  import { StyledButton } from "../design-system/elements.js";
87
87
  import { AccountAddress } from "../prebuilt/Account/address.js";
88
88
  import { AccountAvatar } from "../prebuilt/Account/avatar.js";
89
- import { AccountBalance } from "../prebuilt/Account/balance.js";
89
+ import {
90
+ AccountBalance,
91
+ type AccountBalanceInfo,
92
+ formatAccountFiatBalance,
93
+ formatAccountTokenBalance,
94
+ } from "../prebuilt/Account/balance.js";
90
95
  import { AccountBlobbie } from "../prebuilt/Account/blobbie.js";
91
96
  import { AccountName } from "../prebuilt/Account/name.js";
92
97
  import { AccountProvider } from "../prebuilt/Account/provider.js";
@@ -144,7 +149,6 @@ export const ConnectedWalletDetails: React.FC<{
144
149
  }> = (props) => {
145
150
  const { connectLocale: locale, client } = props;
146
151
  const setRootEl = useContext(SetRootElementContext);
147
- const activeAccount = useActiveAccount();
148
152
  const walletChain = useActiveWalletChain();
149
153
 
150
154
  function closeModal() {
@@ -196,6 +200,9 @@ export const ConnectedWalletDetails: React.FC<{
196
200
 
197
201
  const combinedClassName = `${TW_CONNECTED_WALLET} ${props.detailsButton?.className || ""}`;
198
202
 
203
+ const tokenAddress =
204
+ props.detailsButton?.displayBalanceToken?.[Number(walletChain?.id)];
205
+
199
206
  return (
200
207
  <WalletInfoButton
201
208
  type="button"
@@ -223,16 +230,30 @@ export const ConnectedWalletDetails: React.FC<{
223
230
  }}
224
231
  />
225
232
  ) : (
226
- activeAccount && (
227
- <AccountAvatar
228
- loadingComponent={<AccountBlobbie size={35} />}
229
- fallbackComponent={<AccountBlobbie size={35} />}
230
- queryOptions={{
231
- refetchOnWindowFocus: false,
232
- refetchOnMount: false,
233
- }}
234
- />
235
- )
233
+ <AccountAvatar
234
+ className={`${TW_CONNECTED_WALLET}__account_avatar`}
235
+ loadingComponent={
236
+ <AccountBlobbie
237
+ size={35}
238
+ className={`${TW_CONNECTED_WALLET}__account_avatar`}
239
+ />
240
+ }
241
+ fallbackComponent={
242
+ <AccountBlobbie
243
+ size={35}
244
+ className={`${TW_CONNECTED_WALLET}__account_avatar`}
245
+ />
246
+ }
247
+ queryOptions={{
248
+ refetchOnWindowFocus: false,
249
+ refetchOnMount: false,
250
+ }}
251
+ style={{
252
+ height: "100%",
253
+ width: "100%",
254
+ objectFit: "cover",
255
+ }}
256
+ />
236
257
  )}
237
258
  </Container>
238
259
  <Container
@@ -273,25 +294,71 @@ export const ConnectedWalletDetails: React.FC<{
273
294
  size="xs"
274
295
  color="secondaryText"
275
296
  weight={400}
297
+ style={{
298
+ display: "flex",
299
+ gap: "2px",
300
+ alignItems: "center",
301
+ }}
276
302
  >
277
- <AccountBalance
278
- chain={walletChain}
279
- loadingComponent={<Skeleton height={fontSize.xs} width="70px" />}
280
- fallbackComponent={<Skeleton height={fontSize.xs} width="70px" />}
281
- formatFn={formatBalanceOnButton}
282
- tokenAddress={
283
- props.detailsButton?.displayBalanceToken?.[
284
- Number(walletChain?.id)
285
- ]
286
- }
287
- />
303
+ {props.detailsButton?.showBalanceInFiat ? (
304
+ <>
305
+ <AccountBalance
306
+ chain={walletChain}
307
+ loadingComponent={
308
+ <Skeleton height={fontSize.xs} width="50px" />
309
+ }
310
+ fallbackComponent={
311
+ <Skeleton height={fontSize.xs} width="50px" />
312
+ }
313
+ tokenAddress={tokenAddress}
314
+ />
315
+ <AccountBalance
316
+ chain={walletChain}
317
+ tokenAddress={tokenAddress}
318
+ showBalanceInFiat="USD"
319
+ formatFn={detailsBtn_formatFiatBalanceForButton}
320
+ loadingComponent={
321
+ <Skeleton height={fontSize.xs} width="20px" />
322
+ }
323
+ />
324
+ </>
325
+ ) : (
326
+ <AccountBalance
327
+ chain={walletChain}
328
+ loadingComponent={<Skeleton height={fontSize.xs} width="70px" />}
329
+ fallbackComponent={<Skeleton height={fontSize.xs} width="70px" />}
330
+ formatFn={detailsBtn_formatTokenBalanceForButton}
331
+ tokenAddress={tokenAddress}
332
+ />
333
+ )}
288
334
  </Text>
289
335
  </Container>
290
336
  </WalletInfoButton>
291
337
  );
292
338
  };
293
339
 
294
- function DetailsModal(props: {
340
+ /**
341
+ * @internal Exported for tests
342
+ */
343
+ export function detailsBtn_formatFiatBalanceForButton(
344
+ props: AccountBalanceInfo,
345
+ ) {
346
+ return ` (${formatAccountFiatBalance({ ...props, decimals: 0 })})`;
347
+ }
348
+
349
+ /**
350
+ * @internal Exported for test
351
+ */
352
+ export function detailsBtn_formatTokenBalanceForButton(
353
+ props: AccountBalanceInfo,
354
+ ) {
355
+ return `${formatAccountTokenBalance({ ...props, decimals: props.balance < 1 ? 5 : 4 })}`;
356
+ }
357
+
358
+ /**
359
+ * @internal Exported for tests only
360
+ */
361
+ export function DetailsModal(props: {
295
362
  client: ThirdwebClient;
296
363
  locale: ConnectLocale;
297
364
  detailsModal?: ConnectButton_detailsModalOptions;
@@ -307,6 +374,7 @@ function DetailsModal(props: {
307
374
  displayBalanceToken?: Record<number, string>;
308
375
  connectOptions: DetailsModalConnectOptions | undefined;
309
376
  assetTabs?: AssetTabs[];
377
+ showBalanceInFiat?: SupportedFiatCurrency;
310
378
  }) {
311
379
  const [screen, setScreen] = useState<WalletDetailsModalScreen>("main");
312
380
  const { disconnect } = useDisconnect();
@@ -330,12 +398,12 @@ function DetailsModal(props: {
330
398
  wallets: activeWallet ? [activeWallet] : [],
331
399
  });
332
400
 
333
- function closeModal() {
401
+ const closeModal = useCallback(() => {
334
402
  setIsOpen(false);
335
403
  onModalUnmount(() => {
336
404
  props.closeModal();
337
405
  });
338
- }
406
+ }, [props.closeModal]);
339
407
 
340
408
  function handleDisconnect(info: { wallet: Wallet; account: Account }) {
341
409
  setIsOpen(false);
@@ -343,6 +411,12 @@ function DetailsModal(props: {
343
411
  props.onDisconnect(info);
344
412
  }
345
413
 
414
+ useEffect(() => {
415
+ if (!activeAccount) {
416
+ closeModal();
417
+ }
418
+ }, [activeAccount, closeModal]);
419
+
346
420
  const networkSwitcherButton = (
347
421
  <MenuButton
348
422
  type="button"
@@ -377,15 +451,44 @@ function DetailsModal(props: {
377
451
  <Text color="primaryText" size="md" multiline>
378
452
  {chainNameQuery.name || `Unknown chain #${walletChain?.id}`}
379
453
  <Text color="secondaryText" size="xs">
380
- <AccountBalance
381
- fallbackComponent={<Skeleton height="1em" width="100px" />}
382
- loadingComponent={<Skeleton height="1em" width="100px" />}
383
- formatFn={(num: number) => formatNumber(num, 9)}
384
- chain={walletChain}
385
- tokenAddress={
386
- props.displayBalanceToken?.[Number(walletChain?.id)]
387
- }
388
- />
454
+ {props.showBalanceInFiat ? (
455
+ <>
456
+ <AccountBalance
457
+ fallbackComponent={<Skeleton height="1em" width="70px" />}
458
+ loadingComponent={<Skeleton height="1em" width="70px" />}
459
+ chain={walletChain}
460
+ tokenAddress={
461
+ props.displayBalanceToken?.[Number(walletChain?.id)]
462
+ }
463
+ formatFn={(props: AccountBalanceInfo) =>
464
+ formatAccountTokenBalance({ ...props, decimals: 7 })
465
+ }
466
+ />{" "}
467
+ <AccountBalance
468
+ loadingComponent={<Skeleton height="1em" width="30px" />}
469
+ chain={walletChain}
470
+ tokenAddress={
471
+ props.displayBalanceToken?.[Number(walletChain?.id)]
472
+ }
473
+ formatFn={(props: AccountBalanceInfo) =>
474
+ ` (${formatAccountFiatBalance({ ...props, decimals: 3 })})`
475
+ }
476
+ showBalanceInFiat="USD"
477
+ />
478
+ </>
479
+ ) : (
480
+ <AccountBalance
481
+ fallbackComponent={<Skeleton height="1em" width="100px" />}
482
+ loadingComponent={<Skeleton height="1em" width="100px" />}
483
+ formatFn={(props: AccountBalanceInfo) =>
484
+ formatAccountTokenBalance({ ...props, decimals: 7 })
485
+ }
486
+ chain={walletChain}
487
+ tokenAddress={
488
+ props.displayBalanceToken?.[Number(walletChain?.id)]
489
+ }
490
+ />
491
+ )}
389
492
  </Text>
390
493
  </Text>
391
494
  )}
@@ -437,6 +540,11 @@ function DetailsModal(props: {
437
540
  <AccountAvatar
438
541
  loadingComponent={<AccountBlobbie size={Number(iconSize.xxl)} />}
439
542
  fallbackComponent={<AccountBlobbie size={Number(iconSize.xxl)} />}
543
+ style={{
544
+ height: "100%",
545
+ width: "100%",
546
+ objectFit: "cover",
547
+ }}
440
548
  />
441
549
  )
442
550
  )}
@@ -470,7 +578,7 @@ function DetailsModal(props: {
470
578
  );
471
579
 
472
580
  let content = (
473
- <div>
581
+ <div className={`${TW_CONNECTED_WALLET}__default_modal_screen`}>
474
582
  <Spacer y="xs" />
475
583
  <Container
476
584
  px="lg"
@@ -691,20 +799,6 @@ function DetailsModal(props: {
691
799
  <Text color="primaryText">{props.locale.manageWallet.title}</Text>
692
800
  </MenuButton>
693
801
 
694
- {/* Switch to Personal Wallet */}
695
- {/* {personalWallet &&
696
- !props.detailsModal?.hideSwitchToPersonalWallet && (
697
- <AccountSwitcher
698
- wallet={personalWallet}
699
- name={locale.personalWallet}
700
- />
701
- )} */}
702
-
703
- {/* Switch to Smart Wallet */}
704
- {/* {smartWallet && (
705
- <AccountSwitcher name={locale.smartWallet} wallet={smartWallet} />
706
- )} */}
707
-
708
802
  {/* Request Testnet funds */}
709
803
  {(props.detailsModal?.showTestnetFaucet ?? false) &&
710
804
  (chainFaucetsQuery.faucets.length > 0 ||
@@ -993,12 +1087,11 @@ function DetailsModal(props: {
993
1087
  }
994
1088
  }}
995
1089
  >
996
- <AccountProvider
997
- address={activeAccount?.address || ""}
998
- client={client}
999
- >
1000
- {content}
1001
- </AccountProvider>
1090
+ {activeAccount?.address && (
1091
+ <AccountProvider address={activeAccount.address} client={client}>
1092
+ {content}
1093
+ </AccountProvider>
1094
+ )}
1002
1095
  </Modal>
1003
1096
  </ScreenSetupContext.Provider>
1004
1097
  </WalletUIStatesProvider>
@@ -1006,10 +1099,6 @@ function DetailsModal(props: {
1006
1099
  );
1007
1100
  }
1008
1101
 
1009
- function formatBalanceOnButton(num: number) {
1010
- return formatNumber(num, num < 1 ? 5 : 4);
1011
- }
1012
-
1013
1102
  const WalletInfoButton = /* @__PURE__ */ StyledButton((_) => {
1014
1103
  const theme = useCustomTheme();
1015
1104
  return {
@@ -1045,7 +1134,10 @@ const StyledChevronRightIcon = /* @__PURE__ */ styled(
1045
1134
  };
1046
1135
  });
1047
1136
 
1048
- function ConnectedToSmartWallet(props: {
1137
+ /**
1138
+ * @internal Exported for test
1139
+ */
1140
+ export function ConnectedToSmartWallet(props: {
1049
1141
  client: ThirdwebClient;
1050
1142
  connectLocale: ConnectLocale;
1051
1143
  }) {
@@ -1104,7 +1196,10 @@ function ConnectedToSmartWallet(props: {
1104
1196
  return null;
1105
1197
  }
1106
1198
 
1107
- function InAppWalletUserInfo(props: {
1199
+ /**
1200
+ * @internal Exported for tests
1201
+ */
1202
+ export function InAppWalletUserInfo(props: {
1108
1203
  client: ThirdwebClient;
1109
1204
  locale: ConnectLocale;
1110
1205
  }) {
@@ -1191,13 +1286,19 @@ function InAppWalletUserInfo(props: {
1191
1286
  );
1192
1287
  }
1193
1288
 
1194
- return <Skeleton width="50px" height="10px" />;
1289
+ return (
1290
+ <Skeleton
1291
+ width="50px"
1292
+ height="10px"
1293
+ className="InAppWalletUserInfo__skeleton"
1294
+ />
1295
+ );
1195
1296
  }
1196
1297
 
1197
1298
  /**
1198
- * @internal
1299
+ * @internal Exported for tests
1199
1300
  */
1200
- function SwitchNetworkButton(props: {
1301
+ export function SwitchNetworkButton(props: {
1201
1302
  style?: React.CSSProperties;
1202
1303
  className?: string;
1203
1304
  switchNetworkBtnTitle?: string;
@@ -1507,6 +1608,12 @@ export type UseWalletDetailsModalOptions = {
1507
1608
  * Note: If an empty array is passed, the [View Funds] button will be hidden
1508
1609
  */
1509
1610
  assetTabs?: AssetTabs[];
1611
+
1612
+ /**
1613
+ * Show the token balance's value in fiat.
1614
+ * Note: Not all tokens are resolvable to a fiat value. In that case, nothing will be shown.
1615
+ */
1616
+ showBalanceInFiat?: SupportedFiatCurrency;
1510
1617
  };
1511
1618
 
1512
1619
  /**
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { render } from "~test/react-render.js";
3
+ import { TEST_CLIENT } from "~test/test-clients.js";
4
+ import { createWallet } from "../../../../../wallets/create-wallet.js";
5
+ import en from "../locale/en.js";
6
+ import { PrivateKey } from "./PrivateKey.js";
7
+
8
+ const client = TEST_CLIENT;
9
+
10
+ describe("PrivateKey screen", () => {
11
+ it("should render the iframe", () => {
12
+ const { container } = render(
13
+ <PrivateKey
14
+ onBack={() => {}}
15
+ client={client}
16
+ connectLocale={en}
17
+ theme="dark"
18
+ wallet={createWallet("io.metamask")}
19
+ />,
20
+ );
21
+
22
+ const iframe = container.querySelector("iframe");
23
+ expect(iframe).not.toBe(null);
24
+ });
25
+
26
+ it("should throw an error if no wallet is specified", () => {
27
+ expect(() =>
28
+ render(
29
+ <PrivateKey
30
+ onBack={() => {}}
31
+ client={client}
32
+ connectLocale={en}
33
+ theme="dark"
34
+ />,
35
+ ),
36
+ ).toThrowError("[PrivateKey] No wallet found");
37
+ });
38
+
39
+ it("should render the modal title", () => {
40
+ const { container } = render(
41
+ <PrivateKey
42
+ onBack={() => {}}
43
+ client={client}
44
+ connectLocale={en}
45
+ theme="dark"
46
+ wallet={createWallet("io.metamask")}
47
+ />,
48
+ );
49
+
50
+ const element = container.querySelector("h2");
51
+ expect(element).not.toBe(null);
52
+ expect(element?.innerHTML).toBe(en.manageWallet.exportPrivateKey);
53
+ });
54
+ });
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { render } from "~test/react-render.js";
3
+ import { TEST_CLIENT } from "~test/test-clients.js";
4
+ import en from "../locale/en.js";
5
+ import { ReceiveFunds } from "./ReceiveFunds.js";
6
+
7
+ const client = TEST_CLIENT;
8
+
9
+ describe("ReceiveFunds screen", () => {
10
+ it("should render a title with locale.title", () => {
11
+ const { container } = render(
12
+ <ReceiveFunds onBack={() => {}} client={client} connectLocale={en} />,
13
+ );
14
+ const element = container.querySelector("h2");
15
+ expect(element).not.toBe(null);
16
+ expect(element?.innerHTML).toBe(en.receiveFundsScreen.title);
17
+ });
18
+
19
+ it("should render a span with locale.instruction", () => {
20
+ const { container } = render(
21
+ <ReceiveFunds onBack={() => {}} client={client} connectLocale={en} />,
22
+ );
23
+ const element = container.querySelector(
24
+ "span.receive_fund_screen_instruction",
25
+ );
26
+ expect(element).not.toBe(null);
27
+ expect(element?.innerHTML).toBe(en.receiveFundsScreen.instruction);
28
+ });
29
+
30
+ it("should render the CopyIcon", () => {
31
+ const { container } = render(
32
+ <ReceiveFunds onBack={() => {}} client={client} connectLocale={en} />,
33
+ );
34
+ const element = container.querySelector("svg.tw-copy-icon");
35
+ expect(element).not.toBe(null);
36
+ });
37
+ });
@@ -70,7 +70,12 @@ export function ReceiveFunds(props: {
70
70
 
71
71
  <Spacer y="lg" />
72
72
 
73
- <Text multiline center balance>
73
+ <Text
74
+ multiline
75
+ center
76
+ balance
77
+ className="receive_fund_screen_instruction"
78
+ >
74
79
  {locale.instruction}
75
80
  </Text>
76
81
  </Container>
@@ -0,0 +1,67 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { render } from "~test/react-render.js";
3
+ import { TEST_CLIENT } from "~test/test-clients.js";
4
+ import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
5
+ import { base } from "../../../../../chains/chain-definitions/base.js";
6
+ import { useActiveWalletChain } from "../../../../../react/core/hooks/wallets/useActiveWalletChain.js";
7
+ import en from "../locale/en.js";
8
+ import { SendFundsForm } from "./SendFunds.js";
9
+
10
+ const client = TEST_CLIENT;
11
+
12
+ describe("SendFunds screen", () => {
13
+ it("should render a title with locale.title", () => {
14
+ vi.mock(
15
+ "../../../../../react/core/hooks/wallets/useActiveWalletChain.js",
16
+ () => ({
17
+ useActiveWalletChain: vi.fn(),
18
+ }),
19
+ );
20
+ vi.mocked(useActiveWalletChain).mockReturnValue(base);
21
+ const { container } = render(
22
+ <SendFundsForm
23
+ token={{ nativeToken: true }}
24
+ onTokenSelect={() => {}}
25
+ receiverAddress={TEST_ACCOUNT_A.address}
26
+ setReceiverAddress={() => {}}
27
+ amount={"1"}
28
+ setAmount={() => {}}
29
+ onBack={() => {}}
30
+ client={client}
31
+ connectLocale={en}
32
+ />,
33
+ );
34
+ const element = container.querySelector("h2");
35
+ expect(element).not.toBe(null);
36
+ expect(element?.innerHTML).toBe(en.sendFundsScreen.title);
37
+ vi.resetAllMocks();
38
+ });
39
+
40
+ it("SendFundsForm should render the send button", () => {
41
+ vi.mock(
42
+ "../../../../../react/core/hooks/wallets/useActiveWalletChain.js",
43
+ () => ({
44
+ useActiveWalletChain: vi.fn(),
45
+ }),
46
+ );
47
+ vi.mocked(useActiveWalletChain).mockReturnValue(base);
48
+ const { container } = render(
49
+ <SendFundsForm
50
+ token={{ nativeToken: true }}
51
+ onTokenSelect={() => {}}
52
+ receiverAddress={TEST_ACCOUNT_A.address}
53
+ setReceiverAddress={() => {}}
54
+ amount={"1"}
55
+ setAmount={() => {}}
56
+ onBack={() => {}}
57
+ client={client}
58
+ connectLocale={en}
59
+ />,
60
+ );
61
+ const element = container.querySelector(
62
+ "button.tw-sendfunds-screen-send-button",
63
+ );
64
+ expect(element?.innerHTML).toBe(en.sendFundsScreen.submitButton);
65
+ vi.resetAllMocks();
66
+ });
67
+ });
@@ -107,9 +107,9 @@ export function SendFunds(props: {
107
107
  }
108
108
 
109
109
  /**
110
- * @internal
110
+ * @internal Exported for tests
111
111
  */
112
- function SendFundsForm(props: {
112
+ export function SendFundsForm(props: {
113
113
  onTokenSelect: () => void;
114
114
  token: ERC20OrNativeToken;
115
115
  receiverAddress: string;
@@ -321,6 +321,7 @@ function SendFundsForm(props: {
321
321
  fullWidth
322
322
  variant="accent"
323
323
  type="submit"
324
+ className="tw-sendfunds-screen-send-button"
324
325
  onClick={async () => {
325
326
  if (!receiverAddress || !amount) {
326
327
  return;
@@ -0,0 +1,71 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { render } from "~test/react-render.js";
3
+ import { TEST_CLIENT } from "~test/test-clients.js";
4
+ import en from "../locale/en.js";
5
+ import { StartScreen } from "./StartScreen.js";
6
+
7
+ const client = TEST_CLIENT;
8
+
9
+ describe("StartScreen", () => {
10
+ it("should render an image for the welcome screen", () => {
11
+ const { container } = render(
12
+ <StartScreen
13
+ connectLocale={en}
14
+ client={client}
15
+ welcomeScreen={{
16
+ img: {
17
+ src: "https://cat.png",
18
+ width: 100,
19
+ height: 100,
20
+ },
21
+ }}
22
+ meta={{
23
+ showThirdwebBranding: false,
24
+ termsOfServiceUrl: "https://cat.com",
25
+ privacyPolicyUrl: "https://privacy.com",
26
+ }}
27
+ />,
28
+ );
29
+
30
+ const img = container.querySelector("img");
31
+ expect(img).not.toBe(null);
32
+ expect(img?.src).toBe("https://cat.png/");
33
+ expect(img?.width).toBe(100);
34
+ });
35
+
36
+ it("should render new-to-wallet link", () => {
37
+ const { container } = render(
38
+ <StartScreen
39
+ connectLocale={en}
40
+ client={client}
41
+ welcomeScreen={undefined}
42
+ meta={{
43
+ showThirdwebBranding: false,
44
+ termsOfServiceUrl: "https://cat.com",
45
+ privacyPolicyUrl: "https://privacy.com",
46
+ }}
47
+ />,
48
+ );
49
+
50
+ const a = container.querySelector("a");
51
+ expect(a).not.toBe(null);
52
+ expect(a?.href).toBe("https://blog.thirdweb.com/web3-wallet/");
53
+ });
54
+
55
+ it("should render an svg icon if a custom image is not passed", () => {
56
+ const { container } = render(
57
+ <StartScreen
58
+ connectLocale={en}
59
+ client={client}
60
+ welcomeScreen={undefined}
61
+ meta={{
62
+ showThirdwebBranding: false,
63
+ termsOfServiceUrl: "https://cat.com",
64
+ privacyPolicyUrl: "https://privacy.com",
65
+ }}
66
+ />,
67
+ );
68
+ const svg = container.querySelector("svg");
69
+ expect(svg).not.toBe(null);
70
+ });
71
+ });