@xswap-link/sdk 0.14.0 → 0.15.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 +21 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.global.js +92 -92
- package/dist/index.js +3208 -2862
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3083 -2740
- package/dist/index.mjs.map +1 -1
- package/localTheme.ts +6 -4
- package/package.json +1 -1
- package/src/assets/icons/AdjustmentsIcon.tsx +5 -7
- package/src/assets/icons/ChainlinkMarkIcon.tsx +4 -5
- package/src/assets/icons/CheckCircleThinIcon.tsx +22 -0
- package/src/assets/icons/ChevronDownThinIcon.tsx +39 -0
- package/src/assets/icons/ChevronDownWideThinIcon.tsx +18 -0
- package/src/assets/icons/ChevronsUpDownThinIcon.tsx +21 -0
- package/src/assets/icons/ClockIcon.tsx +3 -7
- package/src/assets/icons/CloseIcon.tsx +9 -4
- package/src/assets/icons/ErrorCircleThinIcon.tsx +22 -0
- package/src/assets/icons/LinkExternalThinIcon.tsx +19 -0
- package/src/assets/icons/LoadingRingIcon.tsx +22 -0
- package/src/assets/icons/ProgressRingThinIcon.tsx +29 -0
- package/src/assets/icons/SearchThinIcon.tsx +15 -0
- package/src/assets/icons/SignThinIcon.tsx +15 -0
- package/src/assets/icons/WalletCheckThinIcon.tsx +24 -0
- package/src/assets/icons/WarningIcon.tsx +8 -5
- package/src/assets/icons/index.ts +11 -0
- package/src/components/Modal/index.tsx +14 -9
- package/src/components/PoweredBy/index.tsx +6 -8
- package/src/components/Swap/Header/index.tsx +2 -4
- package/src/components/Swap/HistoryView/ActivityCard/index.tsx +110 -115
- package/src/components/Swap/HistoryView/index.tsx +10 -7
- package/src/components/Swap/PickerView/index.tsx +151 -0
- package/src/components/Swap/ReorderButton/ReorderButton.tsx +4 -4
- package/src/components/Swap/SettingsView/Delivery/index.tsx +19 -17
- package/src/components/Swap/SettingsView/InfiniteApproval/index.tsx +19 -17
- package/src/components/Swap/SettingsView/Slippage/index.tsx +55 -49
- package/src/components/Swap/SwapView/ConfirmationView/TokenTiles/index.tsx +69 -0
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Header/index.tsx +13 -25
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Steps/index.tsx +65 -113
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +68 -26
- package/src/components/Swap/SwapView/ConfirmationView/TxResult/index.tsx +51 -74
- package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +1 -1
- package/src/components/Swap/SwapView/FeesPanel/index.tsx +5 -5
- package/src/components/Swap/SwapView/SwapButton/index.tsx +2 -31
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +2 -2
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +2 -2
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/ChainPicker/index.tsx +143 -0
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx +19 -16
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +11 -4
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +185 -105
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +54 -120
- package/src/components/Swap/SwapView/SwapPanel/UsdValue/index.tsx +2 -2
- package/src/components/Swap/SwapView/SwapPanel/WalletPanel/index.tsx +10 -16
- package/src/components/Swap/SwapView/SwapPanel/index.tsx +4 -4
- package/src/components/Swap/SwapView/WalletPicker/index.tsx +131 -139
- package/src/components/Swap/SwapView/index.tsx +11 -7
- package/src/components/Swap/WalletPickerView/index.tsx +65 -0
- package/src/components/Swap/index.tsx +39 -8
- package/src/components/ToggleButton/index.tsx +5 -7
- package/src/components/TokenLogo/index.tsx +1 -1
- package/src/components/TxConfigForm/index.tsx +2 -2
- package/src/components/TxModal/index.tsx +14 -4
- package/src/components/global.css +18 -1
- package/src/constants/index.ts +4 -0
- package/src/context/HistoryProvider.tsx +1 -1
- package/src/context/SwapProvider.tsx +193 -81
- package/src/context/TxUIWrapper.tsx +3 -3
- package/src/hooks/useEvmContractApi.ts +28 -4
- package/src/models/payloads/GetBalancesPayload.ts +1 -0
- package/src/services/api.ts +37 -0
- package/src/utils/index.ts +27 -1
- package/src/utils/tokens.ts +20 -1
- package/src/utils/validation.ts +9 -4
- package/tailwind.config.js +4 -1
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +0 -13
- package/src/components/Swap/SwapView/ConfirmationView/TxOverview/SwapPanel/index.tsx +0 -72
- package/src/components/Swap/SwapView/ConfirmationView/TxResult/TokenItem/index.tsx +0 -25
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
LinkExternalIcon,
|
|
6
|
-
SuccessModalStatusIcon,
|
|
2
|
+
CheckCircleThinIcon,
|
|
3
|
+
ErrorCircleThinIcon,
|
|
4
|
+
LinkExternalThinIcon,
|
|
7
5
|
} from "@src/assets/icons";
|
|
8
6
|
import { useSwapContext, useTxUIWrapper } from "@src/context";
|
|
9
|
-
import {
|
|
10
|
-
import { useMemo } from "react";
|
|
11
|
-
import { Ecosystem } from "@src/models";
|
|
7
|
+
import { TokenTiles } from "../TokenTiles";
|
|
12
8
|
|
|
13
9
|
type Props = {
|
|
14
10
|
onCloseClick: () => void;
|
|
@@ -16,79 +12,60 @@ type Props = {
|
|
|
16
12
|
|
|
17
13
|
export const TxResult = ({ onCloseClick }: Props) => {
|
|
18
14
|
const { txError, txExplorerUrl, txMsg } = useTxUIWrapper();
|
|
19
|
-
const {
|
|
20
|
-
isExpressDeliveryActive,
|
|
21
|
-
srcChain,
|
|
22
|
-
srcToken,
|
|
23
|
-
dstChain,
|
|
24
|
-
dstToken,
|
|
25
|
-
srcValue,
|
|
26
|
-
dstValue,
|
|
27
|
-
bridgeUI,
|
|
28
|
-
} = useSwapContext();
|
|
29
|
-
|
|
30
|
-
const value = useMemo(() => {
|
|
31
|
-
if (bridgeUI && srcChain?.ecosystem === Ecosystem.SOLANA) {
|
|
32
|
-
return srcValue;
|
|
33
|
-
}
|
|
34
|
-
return dstValue;
|
|
35
|
-
}, [bridgeUI, srcChain?.ecosystem, srcValue, dstValue]);
|
|
15
|
+
const { isExpressDeliveryActive, srcChain, dstChain } = useSwapContext();
|
|
36
16
|
|
|
37
17
|
return (
|
|
38
|
-
<div className="flex flex-col gap-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<div
|
|
42
|
-
|
|
43
|
-
onClick={onCloseClick}
|
|
44
|
-
>
|
|
45
|
-
<CloseIcon className="w-3.5 h-3.5" />
|
|
46
|
-
</div>
|
|
47
|
-
<ErrorModalStatusIcon />
|
|
48
|
-
<div className="text-2xl font-bold">Transaction failed</div>
|
|
49
|
-
<div className="text-center">{txError}</div>
|
|
50
|
-
</>
|
|
51
|
-
) : (
|
|
52
|
-
<>
|
|
53
|
-
<div
|
|
54
|
-
className="flex justify-end fill-t_text_primary cursor-pointer w-full"
|
|
55
|
-
onClick={onCloseClick}
|
|
56
|
-
>
|
|
57
|
-
<CloseIcon className="w-3.5 h-3.5" />
|
|
18
|
+
<div className="flex flex-col gap-8 text-t_text_primary">
|
|
19
|
+
<div className="flex flex-col gap-2">
|
|
20
|
+
<div className="flex items-center gap-3">
|
|
21
|
+
<div className="text-2xl leading-8 tracking-[0.01em]">
|
|
22
|
+
{txError ? "Transaction Error" : "Transaction Success"}
|
|
58
23
|
</div>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)}
|
|
24
|
+
{txError ? (
|
|
25
|
+
<ErrorCircleThinIcon className="w-6 h-6 shrink-0 text-[#F44336]" />
|
|
26
|
+
) : (
|
|
27
|
+
<CheckCircleThinIcon className="w-6 h-6 shrink-0 text-[#6AE89B]" />
|
|
28
|
+
)}
|
|
29
|
+
</div>
|
|
30
|
+
{txError ? (
|
|
31
|
+
<div className="text-sm leading-5 tracking-[0.01em] text-t_text_primary text-opacity-50">
|
|
32
|
+
{txError}
|
|
69
33
|
</div>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
34
|
+
) : (
|
|
35
|
+
!txMsg &&
|
|
36
|
+
srcChain !== dstChain && (
|
|
37
|
+
<div className="text-sm leading-5 tracking-[0.01em] text-t_text_primary text-opacity-50">
|
|
38
|
+
{`Approximated time of delivery: ${
|
|
39
|
+
isExpressDeliveryActive ? "30 sec" : "30 min"
|
|
40
|
+
}`}
|
|
77
41
|
</div>
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<
|
|
42
|
+
)
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
{!txMsg && (
|
|
46
|
+
<div className="flex flex-col gap-4">
|
|
47
|
+
<TokenTiles />
|
|
48
|
+
{!txError && (
|
|
49
|
+
<a
|
|
50
|
+
href={txExplorerUrl}
|
|
51
|
+
target="_blank"
|
|
52
|
+
rel="noreferrer"
|
|
53
|
+
className="flex items-center gap-2 self-start text-sm leading-5 tracking-[0.01em] text-t_text_primary text-opacity-50 hover:text-opacity-80 transition-colors"
|
|
54
|
+
>
|
|
86
55
|
View details on Explorer
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
56
|
+
<LinkExternalThinIcon className="w-3 h-3" />
|
|
57
|
+
</a>
|
|
58
|
+
)}
|
|
59
|
+
</div>
|
|
91
60
|
)}
|
|
61
|
+
<div className="h-px w-full gradient-sections-separator-container" />
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
onClick={onCloseClick}
|
|
65
|
+
className="w-full px-6 py-3 rounded-lg border-none cursor-pointer bg-t_bg_tertiary bg-opacity-5 text-sm font-medium leading-6 tracking-[0.01em] text-t_text_primary text-opacity-80 hover:bg-opacity-10 transition-colors"
|
|
66
|
+
>
|
|
67
|
+
Continue
|
|
68
|
+
</button>
|
|
92
69
|
</div>
|
|
93
70
|
);
|
|
94
71
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChevronDownThinIcon } from "@src/assets/icons";
|
|
2
2
|
import { Skeleton } from "@src/components";
|
|
3
3
|
import { useSwapContext } from "@src/context";
|
|
4
4
|
import { safeBigNumberFrom, weiToHumanReadable } from "@src/utils";
|
|
@@ -176,7 +176,7 @@ export const FeesPanel = () => {
|
|
|
176
176
|
isFetchingSolanaFee);
|
|
177
177
|
|
|
178
178
|
return (
|
|
179
|
-
<div className="flex flex-col rounded-xl py-
|
|
179
|
+
<div className="flex flex-col rounded-xl py-3 px-4 sm:px-6 bg-gradient-to-r from-t_bg_tertiary/[0.02] to-t_bg_tertiary/0">
|
|
180
180
|
<button
|
|
181
181
|
aria-label={`${expanded ? "Collapse" : "Expand"} fees panel`}
|
|
182
182
|
type="button"
|
|
@@ -195,17 +195,17 @@ export const FeesPanel = () => {
|
|
|
195
195
|
)}
|
|
196
196
|
{route && !isLoading && srcChain?.chainId !== dstChain?.chainId && (
|
|
197
197
|
<>
|
|
198
|
-
<
|
|
198
|
+
<span className="text-t_text_primary opacity-50">/</span>
|
|
199
199
|
<DeliveryInfo />
|
|
200
200
|
</>
|
|
201
201
|
)}
|
|
202
202
|
</div>
|
|
203
203
|
<div
|
|
204
|
-
className={`flex items-center justify-center w-6 h-6
|
|
204
|
+
className={`flex items-center justify-center w-6 h-6 text-t_text_primary opacity-50 transition-transform ${
|
|
205
205
|
expanded ? "rotate-180" : ""
|
|
206
206
|
}`}
|
|
207
207
|
>
|
|
208
|
-
<
|
|
208
|
+
<ChevronDownThinIcon />
|
|
209
209
|
</div>
|
|
210
210
|
</div>
|
|
211
211
|
{expanded && <Fees solanaBridgeFee={solanaBridgeFee} />}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Modal } from "@src/components/Modal";
|
|
2
1
|
import { useSwapContext, useTxUIWrapper } from "@src/context";
|
|
3
2
|
import { useWallet } from "@src/context/WalletProvider";
|
|
4
3
|
import { ADDRESSES } from "@src/contracts";
|
|
@@ -10,7 +9,6 @@ import { safeBigNumberFrom } from "@src/utils";
|
|
|
10
9
|
import { BigNumber } from "ethers";
|
|
11
10
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
12
11
|
import { useAccount, useSwitchChain } from "wagmi";
|
|
13
|
-
import { WalletPicker } from "../WalletPicker";
|
|
14
12
|
|
|
15
13
|
type Button = {
|
|
16
14
|
text: string;
|
|
@@ -53,11 +51,8 @@ export const SwapButton = () => {
|
|
|
53
51
|
} = useNetworks();
|
|
54
52
|
|
|
55
53
|
const {
|
|
56
|
-
openEVMWalletModal,
|
|
57
54
|
setOpenEVMWalletModal,
|
|
58
|
-
openSolanaWalletModal,
|
|
59
55
|
setOpenSolanaWalletModal,
|
|
60
|
-
openSuiWalletModal,
|
|
61
56
|
setOpenSuiWalletModal,
|
|
62
57
|
solana,
|
|
63
58
|
sui,
|
|
@@ -314,38 +309,14 @@ export const SwapButton = () => {
|
|
|
314
309
|
|
|
315
310
|
return (
|
|
316
311
|
<>
|
|
317
|
-
{openEVMWalletModal && (
|
|
318
|
-
<Modal onClose={() => setOpenEVMWalletModal(false)}>
|
|
319
|
-
<WalletPicker
|
|
320
|
-
ecosystem={Ecosystem.EVM}
|
|
321
|
-
onClose={() => setOpenEVMWalletModal(false)}
|
|
322
|
-
/>
|
|
323
|
-
</Modal>
|
|
324
|
-
)}
|
|
325
|
-
{openSolanaWalletModal && (
|
|
326
|
-
<Modal onClose={() => setOpenSolanaWalletModal(false)}>
|
|
327
|
-
<WalletPicker
|
|
328
|
-
ecosystem={Ecosystem.SOLANA}
|
|
329
|
-
onClose={() => setOpenSolanaWalletModal(false)}
|
|
330
|
-
/>
|
|
331
|
-
</Modal>
|
|
332
|
-
)}
|
|
333
|
-
{openSuiWalletModal && (
|
|
334
|
-
<Modal onClose={() => setOpenSuiWalletModal(false)}>
|
|
335
|
-
<WalletPicker
|
|
336
|
-
ecosystem={Ecosystem.SUI}
|
|
337
|
-
onClose={() => setOpenSuiWalletModal(false)}
|
|
338
|
-
/>
|
|
339
|
-
</Modal>
|
|
340
|
-
)}
|
|
341
312
|
<button
|
|
342
313
|
type="button"
|
|
343
314
|
disabled={button.disabled}
|
|
344
315
|
onClick={button.fn}
|
|
345
|
-
className={`text-
|
|
316
|
+
className={`text-base font-medium leading-6 tracking-[0.01em] w-full px-6 py-3 cursor-pointer disabled:cursor-not-allowed rounded-lg border-none transition-[filter] ${
|
|
346
317
|
button.disabled
|
|
347
318
|
? "bg-t_button_pr_off_bg text-t_button_pr_off_text"
|
|
348
|
-
: "bg-gradient-to-
|
|
319
|
+
: "bg-gradient-to-b from-t_main_accent_light from-50% to-t_main_accent_dark text-t_button_pr_text hover:brightness-105"
|
|
349
320
|
}`}
|
|
350
321
|
>
|
|
351
322
|
{button.text}
|
|
@@ -55,9 +55,9 @@ export const Balance = ({ type }: Props) => {
|
|
|
55
55
|
) : (
|
|
56
56
|
<p className="text-[10px] leading-4 text-right whitespace-nowrap">
|
|
57
57
|
<span className="text-t_text_primary text-opacity-50">
|
|
58
|
-
{`Balance `}
|
|
58
|
+
{`Balance. `}
|
|
59
59
|
</span>
|
|
60
|
-
<span className="text-t_text_primary text-opacity-75">
|
|
60
|
+
<span className="text-t_text_primary text-opacity-75 tracking-[0.032em]">
|
|
61
61
|
{`${balanceInfo} ${token.symbol}`}
|
|
62
62
|
</span>
|
|
63
63
|
</p>
|
|
@@ -25,7 +25,7 @@ export const AmountPanel = ({ type }: Props) => {
|
|
|
25
25
|
} = useSwapContext();
|
|
26
26
|
|
|
27
27
|
const onMaxClick = () => {
|
|
28
|
-
if (!srcTokenBalanceWei) {
|
|
28
|
+
if (!srcToken || !srcTokenBalanceWei) {
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
setSrcValue(
|
|
@@ -69,7 +69,7 @@ export const AmountPanel = ({ type }: Props) => {
|
|
|
69
69
|
value={srcValue}
|
|
70
70
|
onChange={(value) => setSrcValue(value)}
|
|
71
71
|
/>
|
|
72
|
-
{!!srcTokenBalanceWei && (
|
|
72
|
+
{!!srcToken && !!srcTokenBalanceWei && (
|
|
73
73
|
<button
|
|
74
74
|
type="button"
|
|
75
75
|
onClick={onMaxClick}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { CloseIcon, SearchThinIcon, WarningIcon } from "@src/assets/icons";
|
|
2
|
+
import { Chain } from "@src/models";
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { Virtuoso } from "react-virtuoso";
|
|
5
|
+
|
|
6
|
+
type ChainOption = Chain & {
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
chains: ChainOption[];
|
|
12
|
+
selectedChainId?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Chain occupied by the other side of the bridge — picking it requires
|
|
15
|
+
* resetting the source, same as picking an unreachable chain.
|
|
16
|
+
*/
|
|
17
|
+
sameChainId?: string;
|
|
18
|
+
onSelect: (chain: ChainOption) => void;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Network picker used in bridge mode, where the destination token is
|
|
24
|
+
* derived from the source token and only the chain gets picked by the user.
|
|
25
|
+
*/
|
|
26
|
+
export const ChainPicker = ({
|
|
27
|
+
chains,
|
|
28
|
+
selectedChainId,
|
|
29
|
+
sameChainId,
|
|
30
|
+
onSelect,
|
|
31
|
+
onClose,
|
|
32
|
+
}: Props) => {
|
|
33
|
+
const [searchValue, setSearchValue] = useState("");
|
|
34
|
+
const chainSearchRef = useRef<HTMLInputElement | null>(null);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
chainSearchRef.current?.focus();
|
|
39
|
+
}, 10); // delay focus a tiny bit to ensure it works
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
const filteredChains = useMemo(() => {
|
|
43
|
+
if (!searchValue) return chains;
|
|
44
|
+
const searchLower = searchValue.toLowerCase();
|
|
45
|
+
return chains.filter(
|
|
46
|
+
(chain) =>
|
|
47
|
+
chain.displayName.toLowerCase().includes(searchLower) ||
|
|
48
|
+
chain.chainId.toLowerCase().includes(searchLower),
|
|
49
|
+
);
|
|
50
|
+
}, [chains, searchValue]);
|
|
51
|
+
|
|
52
|
+
// The current source cannot reach this chain — picking it resets the source.
|
|
53
|
+
const requiresSourceReset = (chain: ChainOption) =>
|
|
54
|
+
!!chain.disabled || chain.chainId === sameChainId;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
<div className="flex justify-between items-center mb-6">
|
|
59
|
+
<div className="text-2xl leading-8 tracking-[0.01em] text-t_text_primary">
|
|
60
|
+
Select Network
|
|
61
|
+
</div>
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
aria-label="Close"
|
|
65
|
+
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"
|
|
66
|
+
onClick={onClose}
|
|
67
|
+
>
|
|
68
|
+
<div className="w-4 h-4 opacity-50 fill-t_text_primary flex items-center justify-center">
|
|
69
|
+
<CloseIcon />
|
|
70
|
+
</div>
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div className="flex items-center gap-2 h-14 px-4 rounded-xl bg-t_bg_tertiary bg-opacity-[0.03] border border-solid border-t_text_primary border-opacity-5 mb-6">
|
|
75
|
+
<div className="text-t_text_primary opacity-60 flex items-center shrink-0">
|
|
76
|
+
<SearchThinIcon />
|
|
77
|
+
</div>
|
|
78
|
+
<input
|
|
79
|
+
ref={chainSearchRef}
|
|
80
|
+
value={searchValue}
|
|
81
|
+
onChange={(e) => setSearchValue(e.target.value)}
|
|
82
|
+
placeholder="Search network name"
|
|
83
|
+
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"
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div className="flex flex-col mx-0 h-full min-h-0 flex-1">
|
|
88
|
+
{filteredChains.length ? (
|
|
89
|
+
<Virtuoso
|
|
90
|
+
style={{ maxHeight: "700px", height: "100%" }}
|
|
91
|
+
data={filteredChains}
|
|
92
|
+
itemContent={(_, chain) => {
|
|
93
|
+
const resetWarning = requiresSourceReset(chain);
|
|
94
|
+
const isSelected = chain.chainId === selectedChainId;
|
|
95
|
+
return (
|
|
96
|
+
<div className="pb-2">
|
|
97
|
+
<div
|
|
98
|
+
onClick={() => onSelect(chain)}
|
|
99
|
+
className={`flex gap-3 items-center p-3 sm:p-4 rounded-xl cursor-pointer bg-gradient-to-r from-t_bg_tertiary/[0.02] to-t_bg_tertiary/[0.02] bg-[rgba(40,40,40,0.15)] hover:bg-t_bg_tertiary hover:bg-opacity-10 transition-colors ${
|
|
100
|
+
isSelected ? "!bg-t_bg_tertiary !bg-opacity-10" : ""
|
|
101
|
+
}`}
|
|
102
|
+
>
|
|
103
|
+
<img
|
|
104
|
+
src={chain.image}
|
|
105
|
+
alt={chain.displayName}
|
|
106
|
+
className={`w-10 h-10 rounded-full shrink-0 ${
|
|
107
|
+
resetWarning ? "opacity-40" : ""
|
|
108
|
+
}`}
|
|
109
|
+
/>
|
|
110
|
+
<div className="flex justify-between items-center gap-2 w-full min-w-0">
|
|
111
|
+
<p
|
|
112
|
+
className={`text-sm font-medium leading-5 tracking-[0.01em] text-t_text_primary ${
|
|
113
|
+
resetWarning ? "opacity-40" : ""
|
|
114
|
+
}`}
|
|
115
|
+
>
|
|
116
|
+
{chain.displayName}
|
|
117
|
+
</p>
|
|
118
|
+
{resetWarning && (
|
|
119
|
+
<div className="flex items-center justify-end gap-1.5 text-[#D77F02]">
|
|
120
|
+
<WarningIcon className="w-3.5 h-3.5 shrink-0" />
|
|
121
|
+
<span className="text-xs leading-[18px] tracking-[0.01em] whitespace-nowrap">
|
|
122
|
+
<span className="sm:hidden">Source will reset.</span>
|
|
123
|
+
<span className="hidden sm:inline">
|
|
124
|
+
Source will reset after selection.
|
|
125
|
+
</span>
|
|
126
|
+
</span>
|
|
127
|
+
</div>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
) : (
|
|
136
|
+
<div className="text-center py-1 text-sm text-t_text_primary text-opacity-50">
|
|
137
|
+
No network found
|
|
138
|
+
</div>
|
|
139
|
+
)}
|
|
140
|
+
</div>
|
|
141
|
+
</>
|
|
142
|
+
);
|
|
143
|
+
};
|
package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChevronDownThinIcon, SearchThinIcon } from "@src/assets/icons";
|
|
2
2
|
import { useSwapContext } from "@src/context";
|
|
3
3
|
import { SwapPanelType } from "@src/components/Swap/SwapView";
|
|
4
4
|
import { Chain } from "@src/models";
|
|
@@ -56,14 +56,15 @@ export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
|
56
56
|
return () => document.removeEventListener("mousedown", onPointerDown);
|
|
57
57
|
}, []);
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
// 2x2 icon cluster shown when no network is picked
|
|
60
|
+
const clusterChains = chains.slice(0, 4);
|
|
60
61
|
|
|
61
62
|
return (
|
|
62
63
|
<div className="relative" ref={containerRef}>
|
|
63
64
|
<button
|
|
64
65
|
type="button"
|
|
65
66
|
onClick={() => setOpen((state) => !state)}
|
|
66
|
-
className="flex items-center gap-2 h-12 px-3 py-2 rounded-lg bg-t_bg_tertiary bg-opacity-[0.04] hover:bg-opacity-10 transition-colors"
|
|
67
|
+
className="flex items-center gap-2.5 h-12 px-3 py-2 rounded-lg bg-t_bg_tertiary bg-opacity-[0.04] hover:bg-opacity-10 transition-colors"
|
|
67
68
|
>
|
|
68
69
|
{selectedChain ? (
|
|
69
70
|
<img
|
|
@@ -72,8 +73,8 @@ export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
|
72
73
|
className="w-5 h-5 rounded-full"
|
|
73
74
|
/>
|
|
74
75
|
) : (
|
|
75
|
-
<div className="grid grid-cols-2 gap-0.5
|
|
76
|
-
{
|
|
76
|
+
<div className="grid grid-cols-2 gap-0.5 shrink-0">
|
|
77
|
+
{clusterChains.map((chain) => (
|
|
77
78
|
<img
|
|
78
79
|
key={chain.chainId}
|
|
79
80
|
src={chain.image}
|
|
@@ -84,22 +85,24 @@ export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
|
84
85
|
</div>
|
|
85
86
|
)}
|
|
86
87
|
<p className="text-sm leading-6 tracking-[0.01em] text-t_text_primary whitespace-nowrap max-w-[120px] truncate">
|
|
87
|
-
{selectedChain
|
|
88
|
+
{selectedChain
|
|
89
|
+
? selectedChain.displayName
|
|
90
|
+
: `${chains.length} Networks`}
|
|
88
91
|
</p>
|
|
89
92
|
<div
|
|
90
|
-
className={`flex items-center justify-center w-6 h-6
|
|
93
|
+
className={`flex items-center justify-center w-6 h-6 text-t_text_primary opacity-50 transition-transform ${
|
|
91
94
|
open ? "rotate-180" : ""
|
|
92
95
|
}`}
|
|
93
96
|
>
|
|
94
|
-
<
|
|
97
|
+
<ChevronDownThinIcon />
|
|
95
98
|
</div>
|
|
96
99
|
</button>
|
|
97
100
|
|
|
98
101
|
{open && (
|
|
99
102
|
<div className="absolute right-0 top-[calc(100%+8px)] z-20 flex flex-col w-[220px] max-h-[280px] rounded-xl bg-t_bg_primary border border-solid border-t_text_primary border-opacity-10 backdrop-blur-[24px] overflow-hidden shadow-lg">
|
|
100
103
|
<div className="flex items-center gap-2 px-4 py-3 border-b border-solid border-t_text_primary border-opacity-10">
|
|
101
|
-
<div className="
|
|
102
|
-
<
|
|
104
|
+
<div className="text-t_text_primary opacity-60 [&_svg]:w-3.5 [&_svg]:h-3.5 flex items-center">
|
|
105
|
+
<SearchThinIcon />
|
|
103
106
|
</div>
|
|
104
107
|
<input
|
|
105
108
|
value={searchValue}
|
|
@@ -132,13 +135,13 @@ export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
|
132
135
|
className="w-5 h-5 rounded-full"
|
|
133
136
|
/>
|
|
134
137
|
) : (
|
|
135
|
-
<div className="grid grid-cols-2 gap-
|
|
136
|
-
{
|
|
138
|
+
<div className="grid grid-cols-2 gap-0.5 shrink-0">
|
|
139
|
+
{clusterChains.map((clusterChain) => (
|
|
137
140
|
<img
|
|
138
|
-
key={
|
|
139
|
-
src={
|
|
140
|
-
alt={
|
|
141
|
-
className="w-[
|
|
141
|
+
key={clusterChain.chainId}
|
|
142
|
+
src={clusterChain.image}
|
|
143
|
+
alt={clusterChain.displayName}
|
|
144
|
+
className="w-[11px] h-[11px] rounded-full"
|
|
142
145
|
/>
|
|
143
146
|
))}
|
|
144
147
|
</div>
|
|
@@ -69,7 +69,7 @@ export const TokenItem = ({
|
|
|
69
69
|
return (
|
|
70
70
|
<div className="pb-2">
|
|
71
71
|
<div
|
|
72
|
-
className={`flex gap-3 items-center p-3 sm:p-4 rounded-xl cursor-pointer bg-gradient-to-r from-t_bg_tertiary/[0.02] to-t_bg_tertiary/[0.02] bg-
|
|
72
|
+
className={`flex gap-3 items-center p-3 sm:p-4 rounded-xl cursor-pointer bg-gradient-to-r from-t_bg_tertiary/[0.02] to-t_bg_tertiary/[0.02] bg-[rgba(40,40,40,0.15)] hover:bg-t_bg_tertiary hover:bg-opacity-10 transition-colors ${
|
|
73
73
|
isSelected ? "!bg-t_bg_tertiary !bg-opacity-10" : ""
|
|
74
74
|
}`}
|
|
75
75
|
onClick={onClick}
|
|
@@ -142,9 +142,16 @@ export const TokenItem = ({
|
|
|
142
142
|
<div className="flex items-center justify-end gap-1.5 text-[#D77F02]">
|
|
143
143
|
<WarningIcon className="w-3.5 h-3.5 shrink-0" />
|
|
144
144
|
<span className="text-xs leading-[18px] tracking-[0.01em] whitespace-nowrap">
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
<span className="sm:hidden">
|
|
146
|
+
{resetWarning === "source"
|
|
147
|
+
? "Source will reset."
|
|
148
|
+
: "Destination will reset."}
|
|
149
|
+
</span>
|
|
150
|
+
<span className="hidden sm:inline">
|
|
151
|
+
{resetWarning === "source"
|
|
152
|
+
? "Source will reset after selection."
|
|
153
|
+
: "Destination will reset after selection."}
|
|
154
|
+
</span>
|
|
148
155
|
</span>
|
|
149
156
|
</div>
|
|
150
157
|
) : (
|