@xswap-link/sdk 0.13.1 → 0.14.0
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/CHANGELOG.md +7 -0
- package/dist/index.d.mts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.global.js +85 -84
- package/dist/index.js +1553 -1458
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1542 -1444
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/assets/icons/AdjustmentsIcon.tsx +18 -0
- package/src/assets/icons/CaretDownIcon.tsx +12 -0
- package/src/assets/icons/CaretsUpDownIcon.tsx +13 -0
- package/src/assets/icons/ChainlinkMarkIcon.tsx +17 -0
- package/src/assets/icons/ClockIcon.tsx +18 -0
- package/src/assets/icons/WarningIcon.tsx +16 -0
- package/src/assets/icons/index.ts +6 -0
- package/src/components/Modal/index.tsx +2 -2
- package/src/components/PoweredBy/index.tsx +14 -5
- package/src/components/Swap/Header/Controls/index.tsx +50 -36
- package/src/components/Swap/Header/index.tsx +12 -5
- package/src/components/Swap/HistoryView/ActivityCard/index.tsx +212 -0
- package/src/components/Swap/HistoryView/index.tsx +24 -6
- package/src/components/Swap/ReorderButton/ReorderButton.tsx +5 -7
- package/src/components/Swap/SettingsView/Delivery/index.tsx +27 -28
- package/src/components/Swap/SettingsView/InfiniteApproval/index.tsx +27 -24
- package/src/components/Swap/SettingsView/Slippage/index.tsx +44 -43
- package/src/components/Swap/SettingsView/index.tsx +1 -1
- package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +9 -19
- package/src/components/Swap/SwapView/FeesPanel/Fee/index.tsx +4 -4
- package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +5 -9
- package/src/components/Swap/SwapView/FeesPanel/index.tsx +21 -22
- package/src/components/Swap/SwapView/SwapButton/index.tsx +25 -6
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +56 -12
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +42 -41
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx +157 -0
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +98 -55
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +160 -239
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +57 -31
- package/src/components/Swap/SwapView/SwapPanel/UsdValue/index.tsx +27 -0
- package/src/components/Swap/SwapView/SwapPanel/WalletPanel/index.tsx +60 -49
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +20 -25
- package/src/components/Swap/SwapView/WalletPicker/index.tsx +6 -1
- package/src/components/Swap/SwapView/index.tsx +2 -1
- package/src/components/Swap/index.tsx +4 -2
- package/src/components/ToggleButton/index.tsx +18 -15
- package/src/components/TxConfigForm/index.tsx +5 -5
- package/src/components/TxWidgetWC/index.tsx +4 -0
- package/src/components/TxWidgetWCWrapped/index.tsx +2 -0
- package/src/context/HistoryProvider.tsx +1 -0
- package/src/models/TransactionHistory.ts +1 -0
- package/src/models/payloads/ModalIntegrationPayload.ts +1 -0
- package/src/models/payloads/WidgetIntegrationPayload.ts +1 -0
- package/src/utils/index.ts +21 -0
- package/tailwind.config.js +2 -2
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +0 -97
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +0 -103
- package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +0 -65
- package/src/components/Swap/SwapView/SwapPanel/MaxPanel/index.tsx +0 -43
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +0 -37
|
@@ -4,7 +4,6 @@ import { CloseIcon, CopyIcon, SearchIcon } from "@src/assets/icons";
|
|
|
4
4
|
import {
|
|
5
5
|
Button,
|
|
6
6
|
Spinner,
|
|
7
|
-
TextInput,
|
|
8
7
|
TokenLogoWithChain,
|
|
9
8
|
UnknownTokenLogo,
|
|
10
9
|
} from "@src/components";
|
|
@@ -14,6 +13,7 @@ import { ERC20Abi } from "@src/contracts";
|
|
|
14
13
|
import { useEvmContractApi } from "@src/hooks";
|
|
15
14
|
import { Chain, Ecosystem, ImportedTokenData, TokenOption } from "@src/models";
|
|
16
15
|
import {
|
|
16
|
+
isChainConnectionSupported,
|
|
17
17
|
isETHAddressValid,
|
|
18
18
|
isServer,
|
|
19
19
|
isSolanaAddressValid,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
import { BigNumber, ethers } from "ethers";
|
|
23
23
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
24
24
|
import { GroupedVirtuoso } from "react-virtuoso";
|
|
25
|
-
import {
|
|
25
|
+
import { NetworkFilter } from "./NetworkFilter";
|
|
26
26
|
import { TokenItem } from "./TokenItem";
|
|
27
27
|
import { useAccount } from "wagmi";
|
|
28
28
|
import { Connection, PublicKey } from "@solana/web3.js";
|
|
@@ -55,13 +55,15 @@ export const TokenPicker = ({
|
|
|
55
55
|
const [loadingCustomTokenData, setLoadingCustomTokenData] = useState(false);
|
|
56
56
|
const [customTokenData, setCustomTokenData] =
|
|
57
57
|
useState<ImportedTokenData | null>(null);
|
|
58
|
-
const [
|
|
58
|
+
const [networkFilter, setNetworkFilter] = useState<Chain | undefined>(chain);
|
|
59
59
|
const currentRouteRequestNonce = useRef<number>(0);
|
|
60
60
|
const tokenSearchRef = useRef<HTMLInputElement | null>(null);
|
|
61
61
|
|
|
62
62
|
const {
|
|
63
63
|
bridgeUI,
|
|
64
64
|
supportedChains,
|
|
65
|
+
srcChain,
|
|
66
|
+
dstChain,
|
|
65
67
|
findTokenDataByAddressAndChain,
|
|
66
68
|
tokenPrices,
|
|
67
69
|
addTokenToChainIfNotExists,
|
|
@@ -295,40 +297,26 @@ export const TokenPicker = ({
|
|
|
295
297
|
|
|
296
298
|
useEffect(() => {
|
|
297
299
|
setSearchValue("");
|
|
300
|
+
setNetworkFilter(chain);
|
|
301
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
298
302
|
}, [isOpen]);
|
|
299
303
|
|
|
300
304
|
const isMatch = (value, searchValue) =>
|
|
301
305
|
value.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
|
302
306
|
|
|
303
|
-
const
|
|
304
|
-
()
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
otherTokens?.filter(
|
|
317
|
-
(token) =>
|
|
318
|
-
isMatch(token.symbol, searchValue) ||
|
|
319
|
-
isMatch(token.name, searchValue) ||
|
|
320
|
-
token.address.toLowerCase() === searchValue.toLowerCase(),
|
|
321
|
-
),
|
|
322
|
-
[searchValue, otherTokens],
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
useEffect(() => {
|
|
326
|
-
if (isOpen && tokenSearchRef.current) {
|
|
327
|
-
setTimeout(() => {
|
|
328
|
-
tokenSearchRef.current?.focus();
|
|
329
|
-
}, 10); // delay focus a tiny bit to ensure it works
|
|
330
|
-
}
|
|
331
|
-
}, [isOpen]);
|
|
307
|
+
const visibleTokens = useMemo(() => {
|
|
308
|
+
const all = [...(tokens || []), ...(otherTokens || [])];
|
|
309
|
+
return all.filter((token) => {
|
|
310
|
+
if (networkFilter && token.chainId !== networkFilter.chainId) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
return (
|
|
314
|
+
isMatch(token.symbol, searchValue) ||
|
|
315
|
+
isMatch(token.name, searchValue) ||
|
|
316
|
+
token.address.toLowerCase() === searchValue.toLowerCase()
|
|
317
|
+
);
|
|
318
|
+
});
|
|
319
|
+
}, [tokens, otherTokens, searchValue, networkFilter]);
|
|
332
320
|
|
|
333
321
|
const calculateTokenValue = useCallback(
|
|
334
322
|
(token: TokenOption) => {
|
|
@@ -342,119 +330,107 @@ export const TokenPicker = ({
|
|
|
342
330
|
[tokenPrices],
|
|
343
331
|
);
|
|
344
332
|
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
});
|
|
363
|
-
}, [filteredTokens, otherFilteredTokens, calculateTokenValue]);
|
|
333
|
+
const ownedTokens = useMemo(() => {
|
|
334
|
+
if (!address && !solanaAddress) {
|
|
335
|
+
return [];
|
|
336
|
+
}
|
|
337
|
+
return visibleTokens
|
|
338
|
+
.filter((token) => BigNumber.from(token?.balance || "0").gt(0))
|
|
339
|
+
.sort((tokenA, tokenB) => {
|
|
340
|
+
const valueA = calculateTokenValue(tokenA);
|
|
341
|
+
const valueB = calculateTokenValue(tokenB);
|
|
342
|
+
// First sort by USD value
|
|
343
|
+
if (valueB !== valueA) {
|
|
344
|
+
return valueB - valueA;
|
|
345
|
+
}
|
|
346
|
+
// If USD values are equal (or both 0), sort by priority
|
|
347
|
+
return tokenB.priority - tokenA.priority;
|
|
348
|
+
});
|
|
349
|
+
}, [visibleTokens, address, solanaAddress, calculateTokenValue]);
|
|
364
350
|
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
351
|
+
const recommendedTokens = useMemo(
|
|
352
|
+
() =>
|
|
353
|
+
visibleTokens
|
|
354
|
+
.filter(
|
|
355
|
+
(token) =>
|
|
356
|
+
!(address || solanaAddress) ||
|
|
357
|
+
BigNumber.from(token?.balance || "0").eq(0),
|
|
358
|
+
)
|
|
359
|
+
.sort(
|
|
360
|
+
(tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
|
|
361
|
+
),
|
|
362
|
+
[visibleTokens, address, solanaAddress],
|
|
363
|
+
);
|
|
376
364
|
|
|
377
|
-
|
|
378
|
-
|
|
365
|
+
const tokenGroups = useMemo(() => {
|
|
366
|
+
return ownedTokens.length
|
|
379
367
|
? [
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
: []),
|
|
383
|
-
currentChainTokens,
|
|
384
|
-
otherChainTokens,
|
|
368
|
+
{ label: "MY TOKENS.", tokens: ownedTokens },
|
|
369
|
+
{ label: "RECOMMENDED.", tokens: recommendedTokens },
|
|
385
370
|
]
|
|
386
|
-
: [
|
|
387
|
-
|
|
388
|
-
? [ownedFilteredTokens]
|
|
389
|
-
: []),
|
|
390
|
-
[...currentChainTokens, ...otherChainTokens],
|
|
391
|
-
];
|
|
392
|
-
|
|
393
|
-
return groups.flat();
|
|
394
|
-
}, [
|
|
395
|
-
filteredTokens,
|
|
396
|
-
otherFilteredTokens,
|
|
397
|
-
ownedFilteredTokens,
|
|
398
|
-
chain,
|
|
399
|
-
address,
|
|
400
|
-
solanaAddress,
|
|
401
|
-
]);
|
|
371
|
+
: [{ label: "RECOMMENDED.", tokens: recommendedTokens }];
|
|
372
|
+
}, [ownedTokens, recommendedTokens]);
|
|
402
373
|
|
|
403
|
-
const
|
|
404
|
-
() =>
|
|
405
|
-
[
|
|
374
|
+
const allTokens = useMemo(
|
|
375
|
+
() => tokenGroups.flatMap((group) => group.tokens),
|
|
376
|
+
[tokenGroups],
|
|
406
377
|
);
|
|
407
378
|
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
379
|
+
const getResetWarning = useCallback(
|
|
380
|
+
(token: TokenOption): SwapPanelType | null => {
|
|
381
|
+
if (type === "destination") {
|
|
382
|
+
if (
|
|
383
|
+
srcChain &&
|
|
384
|
+
!isChainConnectionSupported(srcChain, token.chainId, bridgeUI)
|
|
385
|
+
) {
|
|
386
|
+
return "source";
|
|
387
|
+
}
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
const tokenChain = supportedChains.find(
|
|
391
|
+
({ chainId }) => chainId === token.chainId,
|
|
418
392
|
);
|
|
393
|
+
if (
|
|
394
|
+
dstChain &&
|
|
395
|
+
tokenChain &&
|
|
396
|
+
!isChainConnectionSupported(tokenChain, dstChain.chainId, bridgeUI)
|
|
397
|
+
) {
|
|
398
|
+
return "destination";
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
},
|
|
402
|
+
[type, srcChain, dstChain, bridgeUI, supportedChains],
|
|
403
|
+
);
|
|
419
404
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
]
|
|
428
|
-
: [
|
|
429
|
-
...(!!(address || solanaAddress) && ownedFilteredTokens.length
|
|
430
|
-
? [ownedFilteredTokens]
|
|
431
|
-
: []),
|
|
432
|
-
[...currentChainTokens, ...otherChainTokens],
|
|
433
|
-
];
|
|
434
|
-
}, [
|
|
435
|
-
chain,
|
|
436
|
-
address,
|
|
437
|
-
solanaAddress,
|
|
438
|
-
filteredTokens,
|
|
439
|
-
otherFilteredTokens,
|
|
440
|
-
ownedFilteredTokens,
|
|
441
|
-
]);
|
|
405
|
+
useEffect(() => {
|
|
406
|
+
if (isOpen && tokenSearchRef.current) {
|
|
407
|
+
setTimeout(() => {
|
|
408
|
+
tokenSearchRef.current?.focus();
|
|
409
|
+
}, 10); // delay focus a tiny bit to ensure it works
|
|
410
|
+
}
|
|
411
|
+
}, [isOpen]);
|
|
442
412
|
|
|
443
413
|
return showImportWarning ? (
|
|
444
414
|
<>
|
|
445
|
-
<div className="flex justify-between">
|
|
446
|
-
<div className="text-
|
|
447
|
-
|
|
448
|
-
|
|
415
|
+
<div className="flex justify-between items-center mb-6">
|
|
416
|
+
<div className="text-2xl leading-8 tracking-[0.01em]">
|
|
417
|
+
Import token
|
|
418
|
+
</div>
|
|
419
|
+
<button
|
|
420
|
+
type="button"
|
|
421
|
+
aria-label="Close"
|
|
422
|
+
className="flex items-center justify-center w-8 h-8 rounded-md bg-t_bg_tertiary bg-opacity-5 hover:bg-opacity-10 transition-colors"
|
|
449
423
|
onClick={() => setModalOpen(false)}
|
|
450
424
|
>
|
|
451
|
-
<
|
|
452
|
-
|
|
425
|
+
<div className="w-4 h-4 opacity-50 fill-t_text_primary flex items-center justify-center">
|
|
426
|
+
<CloseIcon />
|
|
427
|
+
</div>
|
|
428
|
+
</button>
|
|
453
429
|
</div>
|
|
454
430
|
<div className="flex flex-col h-full gap-2">
|
|
455
431
|
{customTokenData && (
|
|
456
432
|
<div
|
|
457
|
-
className={`
|
|
433
|
+
className={`flex gap-3 py-3 px-4 items-center grow-0 bg-t_bg_tertiary bg-opacity-[0.03] border border-solid border-t_text_primary border-opacity-10 rounded-xl`}
|
|
458
434
|
>
|
|
459
435
|
<UnknownTokenLogo
|
|
460
436
|
tokenName={customTokenData.name}
|
|
@@ -464,7 +440,7 @@ export const TokenPicker = ({
|
|
|
464
440
|
<div className="overflow-hidden whitespace-nowrap text-ellipsis text-sm font-medium">
|
|
465
441
|
{customTokenData.name}
|
|
466
442
|
</div>
|
|
467
|
-
<div className="
|
|
443
|
+
<div className="text-sm text-t_text_primary text-opacity-50">
|
|
468
444
|
{customTokenData.symbol}
|
|
469
445
|
</div>
|
|
470
446
|
</div>
|
|
@@ -478,19 +454,19 @@ export const TokenPicker = ({
|
|
|
478
454
|
)
|
|
479
455
|
}
|
|
480
456
|
aria-label={`Copy ${customTokenData.symbol} token address`}
|
|
481
|
-
className="flex items-center p-2 fill-
|
|
457
|
+
className="flex items-center p-2 fill-t_text_primary cursor-pointer hover:fill-t_main_accent_light"
|
|
482
458
|
>
|
|
483
459
|
<CopyIcon className="w-5 h-5" />
|
|
484
460
|
</button>
|
|
485
461
|
</div>
|
|
486
462
|
</div>
|
|
487
463
|
)}
|
|
488
|
-
<div className="px-
|
|
464
|
+
<div className="px-4 py-4 rounded-xl border border-solid border-t_warning_dark text-sm text-t_text_primary text-opacity-80">
|
|
489
465
|
Ensure that you have verified the token address and confirmed its
|
|
490
466
|
correctness
|
|
491
467
|
</div>
|
|
492
|
-
<div className="bg-
|
|
493
|
-
<div className="text-sm mb-2">
|
|
468
|
+
<div className="bg-t_bg_tertiary bg-opacity-[0.03] border border-solid border-t_text_primary border-opacity-10 rounded-xl p-4">
|
|
469
|
+
<div className="text-sm mb-2 text-t_text_primary text-opacity-80">
|
|
494
470
|
Be mindful that anyone can create tokens, even counterfeit versions
|
|
495
471
|
of existing ones. Certain tokens and their technical specifications
|
|
496
472
|
might not be compatible with XSwap services. By importing such
|
|
@@ -501,21 +477,21 @@ export const TokenPicker = ({
|
|
|
501
477
|
onClick={() => setAcceptRisks((state) => !state)}
|
|
502
478
|
className="flex items-center"
|
|
503
479
|
>
|
|
504
|
-
<div className="flex justify-center items-center p-1 w-6 h-6 border-2 border-
|
|
480
|
+
<div className="flex justify-center items-center p-1 w-6 h-6 border-2 border-solid border-t_text_primary border-opacity-50 rounded-md mr-2">
|
|
505
481
|
{acceptRisks && (
|
|
506
482
|
<FontAwesomeIcon icon={faCheck} className="w-4 h-4" />
|
|
507
483
|
)}
|
|
508
484
|
</div>
|
|
509
485
|
|
|
510
|
-
<div className="font-
|
|
486
|
+
<div className="font-medium">Accept</div>
|
|
511
487
|
</button>
|
|
512
488
|
</div>
|
|
513
489
|
<div className="flex grow items-end justify-center">
|
|
514
490
|
<Button
|
|
515
491
|
type="button"
|
|
516
492
|
disabled={!acceptRisks}
|
|
517
|
-
className={`
|
|
518
|
-
!acceptRisks ? "!cursor-not-allowed" : ""
|
|
493
|
+
className={`w-full !rounded-[10px] !py-3 !text-sm !font-medium bg-gradient-to-br from-t_main_accent_light to-t_main_accent_dark !text-t_button_pr_text ${
|
|
494
|
+
!acceptRisks ? "!cursor-not-allowed opacity-50" : ""
|
|
519
495
|
}`}
|
|
520
496
|
onClick={importCustomToken}
|
|
521
497
|
>
|
|
@@ -526,49 +502,43 @@ export const TokenPicker = ({
|
|
|
526
502
|
</>
|
|
527
503
|
) : (
|
|
528
504
|
<>
|
|
529
|
-
<div className="flex justify-between">
|
|
530
|
-
<div className="text-
|
|
531
|
-
|
|
532
|
-
|
|
505
|
+
<div className="flex justify-between items-center mb-6">
|
|
506
|
+
<div className="text-2xl leading-8 tracking-[0.01em] text-t_text_primary">
|
|
507
|
+
Select Token
|
|
508
|
+
</div>
|
|
509
|
+
<button
|
|
510
|
+
type="button"
|
|
511
|
+
aria-label="Close"
|
|
512
|
+
className="flex items-center justify-center w-8 h-8 rounded-md bg-t_bg_tertiary bg-opacity-5 hover:bg-opacity-10 transition-colors"
|
|
533
513
|
onClick={() => setModalOpen(false)}
|
|
534
514
|
>
|
|
535
|
-
<
|
|
536
|
-
|
|
515
|
+
<div className="w-4 h-4 opacity-50 fill-t_text_primary flex items-center justify-center">
|
|
516
|
+
<CloseIcon />
|
|
517
|
+
</div>
|
|
518
|
+
</button>
|
|
537
519
|
</div>
|
|
538
520
|
|
|
539
|
-
<
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
<div className="fill-t_text_primary">
|
|
521
|
+
<div className="flex items-center justify-between gap-2 h-14 pl-4 pr-1 rounded-xl bg-t_bg_tertiary bg-opacity-[0.03] border border-solid border-t_text_primary border-opacity-5 mb-6">
|
|
522
|
+
<div className="flex items-center gap-2 flex-1 min-w-0">
|
|
523
|
+
<div className="fill-t_text_primary opacity-50 [&_svg]:w-4 [&_svg]:h-4 flex items-center shrink-0">
|
|
543
524
|
<SearchIcon />
|
|
544
525
|
</div>
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
.filter((token) => token?.quickPick)
|
|
559
|
-
.map((token) => (
|
|
560
|
-
<QuickPickTokenItem
|
|
561
|
-
key={token.address}
|
|
562
|
-
token={token}
|
|
563
|
-
selectedTokenAddress={selectedTokenAddress}
|
|
564
|
-
onClick={() => {
|
|
565
|
-
onSelect(token);
|
|
566
|
-
setModalOpen(false);
|
|
567
|
-
}}
|
|
568
|
-
/>
|
|
569
|
-
))}
|
|
526
|
+
<input
|
|
527
|
+
ref={tokenSearchRef}
|
|
528
|
+
value={searchValue}
|
|
529
|
+
onChange={(e) => setSearchValue(e.target.value)}
|
|
530
|
+
placeholder="Search name or paste address"
|
|
531
|
+
className="bg-transparent border-none outline-none w-full text-sm leading-6 text-t_text_primary placeholder:text-t_text_primary placeholder:text-opacity-40"
|
|
532
|
+
/>
|
|
533
|
+
</div>
|
|
534
|
+
<NetworkFilter
|
|
535
|
+
type={type}
|
|
536
|
+
selectedChain={networkFilter}
|
|
537
|
+
onSelect={setNetworkFilter}
|
|
538
|
+
/>
|
|
570
539
|
</div>
|
|
571
|
-
|
|
540
|
+
|
|
541
|
+
<div className="flex flex-col mx-0 h-full min-h-0 flex-1">
|
|
572
542
|
{loadingCustomTokenData ? (
|
|
573
543
|
<div className="flex justify-center w-full py-4 px-0">
|
|
574
544
|
<Spinner className="w-9 h-9" />
|
|
@@ -576,7 +546,7 @@ export const TokenPicker = ({
|
|
|
576
546
|
) : (
|
|
577
547
|
<>
|
|
578
548
|
{customTokenData ? (
|
|
579
|
-
<div className=
|
|
549
|
+
<div className="flex gap-3 py-3 px-4 items-center rounded-xl bg-t_bg_tertiary bg-opacity-[0.03]">
|
|
580
550
|
<TokenLogoWithChain
|
|
581
551
|
token={customTokenData}
|
|
582
552
|
chain={chain}
|
|
@@ -593,14 +563,14 @@ export const TokenPicker = ({
|
|
|
593
563
|
{chain?.displayName}
|
|
594
564
|
</div>
|
|
595
565
|
</div>
|
|
596
|
-
<div className="
|
|
566
|
+
<div className="text-sm text-t_text_primary text-opacity-50">
|
|
597
567
|
{customTokenData.symbol}
|
|
598
568
|
</div>
|
|
599
569
|
</div>
|
|
600
570
|
<div>
|
|
601
571
|
<Button
|
|
602
572
|
type="button"
|
|
603
|
-
className="h-8 py-0 px-4
|
|
573
|
+
className="h-8 py-0 px-4 leading-[14px] rounded-lg bg-gradient-to-br from-t_main_accent_light to-t_main_accent_dark !text-t_button_pr_text"
|
|
604
574
|
onClick={() => setShowImportWarning(true)}
|
|
605
575
|
>
|
|
606
576
|
Import
|
|
@@ -608,83 +578,34 @@ export const TokenPicker = ({
|
|
|
608
578
|
</div>
|
|
609
579
|
</div>
|
|
610
580
|
) : (
|
|
611
|
-
<div className="flex flex-col h-full
|
|
581
|
+
<div className="flex flex-col h-full">
|
|
612
582
|
<GroupedVirtuoso
|
|
613
583
|
style={{ maxHeight: "700px", height: "100%" }}
|
|
614
|
-
groupCounts={tokenGroups.map((group) => group
|
|
615
|
-
scrollerRef={(ref) => {
|
|
616
|
-
if (ref) {
|
|
617
|
-
ref.addEventListener("scroll", (e) => {
|
|
618
|
-
const target = e.target as HTMLDivElement;
|
|
619
|
-
setShowQuickPicks(target.scrollTop < 10);
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
}}
|
|
584
|
+
groupCounts={tokenGroups.map((group) => group.tokens.length)}
|
|
623
585
|
groupContent={(index) => (
|
|
624
|
-
<div className="
|
|
625
|
-
<
|
|
626
|
-
{
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
return `${chain.displayName} network`;
|
|
633
|
-
}
|
|
634
|
-
return ownedTokens.length
|
|
635
|
-
? "My tokens"
|
|
636
|
-
: `${chain.displayName} network`;
|
|
637
|
-
}
|
|
638
|
-
case 1: {
|
|
639
|
-
if (!address && !solanaAddress) {
|
|
640
|
-
return "Other networks";
|
|
641
|
-
}
|
|
642
|
-
return `${chain.displayName} network`;
|
|
643
|
-
}
|
|
644
|
-
case 2: {
|
|
645
|
-
return "Other networks";
|
|
646
|
-
}
|
|
647
|
-
default: {
|
|
648
|
-
return "Undefined group";
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
} else {
|
|
652
|
-
// chain is not selected
|
|
653
|
-
switch (index) {
|
|
654
|
-
case 0: {
|
|
655
|
-
if (!address) {
|
|
656
|
-
return "All networks";
|
|
657
|
-
}
|
|
658
|
-
return ownedTokens.length
|
|
659
|
-
? "My tokens"
|
|
660
|
-
: "All networks";
|
|
661
|
-
}
|
|
662
|
-
case 1: {
|
|
663
|
-
return "All networks";
|
|
664
|
-
}
|
|
665
|
-
default: {
|
|
666
|
-
return "Undefined group";
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
})()}
|
|
671
|
-
</div>
|
|
672
|
-
<div className="horizontal-separator" />
|
|
673
|
-
{!tokenGroups[index]?.length && (
|
|
674
|
-
<div className="text-center py-1">No token found</div>
|
|
586
|
+
<div className="pb-3 bg-t_bg_primary">
|
|
587
|
+
<p className="text-[10px] font-medium leading-4 tracking-[0.015em] text-t_text_primary text-opacity-30 text-left">
|
|
588
|
+
{tokenGroups[index]?.label}
|
|
589
|
+
</p>
|
|
590
|
+
{!tokenGroups[index]?.tokens.length && (
|
|
591
|
+
<div className="text-center py-1 text-sm text-t_text_primary text-opacity-50">
|
|
592
|
+
No token found
|
|
593
|
+
</div>
|
|
675
594
|
)}
|
|
676
595
|
</div>
|
|
677
596
|
)}
|
|
678
597
|
itemContent={(index) => {
|
|
598
|
+
const token = allTokens[index];
|
|
679
599
|
return (
|
|
680
|
-
|
|
600
|
+
token && (
|
|
681
601
|
<TokenItem
|
|
682
602
|
panelType={type}
|
|
683
|
-
token={
|
|
603
|
+
token={token}
|
|
684
604
|
selectedChainId={chain?.chainId}
|
|
685
605
|
selectedTokenAddress={selectedTokenAddress}
|
|
606
|
+
resetWarning={getResetWarning(token)}
|
|
686
607
|
onClick={() => {
|
|
687
|
-
onSelect(
|
|
608
|
+
onSelect(token);
|
|
688
609
|
setModalOpen(false);
|
|
689
610
|
}}
|
|
690
611
|
/>
|