@xswap-link/sdk 0.14.1 → 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 +6 -0
- package/dist/index.global.js +92 -92
- package/dist/index.js +1799 -1725
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1752 -1681
- package/dist/index.mjs.map +1 -1
- package/localTheme.ts +1 -1
- package/package.json +1 -1
- 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/CloseIcon.tsx +3 -2
- 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/index.ts +11 -0
- package/src/components/PoweredBy/index.tsx +1 -1
- 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/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 +19 -23
- package/src/components/Swap/SwapView/ConfirmationView/TxResult/index.tsx +51 -74
- package/src/components/Swap/SwapView/FeesPanel/index.tsx +4 -4
- package/src/components/Swap/SwapView/SwapButton/index.tsx +0 -29
- package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +2 -2
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/ChainPicker/index.tsx +3 -3
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx +17 -16
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +91 -40
- package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +4 -4
- 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 +3 -3
- 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 +23 -6
- package/src/components/ToggleButton/index.tsx +5 -7
- package/src/components/TokenLogo/index.tsx +1 -1
- 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/SwapProvider.tsx +106 -19
- package/src/utils/validation.ts +9 -4
- 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
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,13 +73,13 @@ export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
|
72
73
|
className="w-5 h-5 rounded-full"
|
|
73
74
|
/>
|
|
74
75
|
) : (
|
|
75
|
-
<div className="
|
|
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}
|
|
80
81
|
alt={chain.displayName}
|
|
81
|
-
className="w-
|
|
82
|
+
className="w-[11px] h-[11px] rounded-full"
|
|
82
83
|
/>
|
|
83
84
|
))}
|
|
84
85
|
</div>
|
|
@@ -89,19 +90,19 @@ export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
|
89
90
|
: `${chains.length} Networks`}
|
|
90
91
|
</p>
|
|
91
92
|
<div
|
|
92
|
-
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 ${
|
|
93
94
|
open ? "rotate-180" : ""
|
|
94
95
|
}`}
|
|
95
96
|
>
|
|
96
|
-
<
|
|
97
|
+
<ChevronDownThinIcon />
|
|
97
98
|
</div>
|
|
98
99
|
</button>
|
|
99
100
|
|
|
100
101
|
{open && (
|
|
101
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">
|
|
102
103
|
<div className="flex items-center gap-2 px-4 py-3 border-b border-solid border-t_text_primary border-opacity-10">
|
|
103
|
-
<div className="
|
|
104
|
-
<
|
|
104
|
+
<div className="text-t_text_primary opacity-60 [&_svg]:w-3.5 [&_svg]:h-3.5 flex items-center">
|
|
105
|
+
<SearchThinIcon />
|
|
105
106
|
</div>
|
|
106
107
|
<input
|
|
107
108
|
value={searchValue}
|
|
@@ -134,13 +135,13 @@ export const NetworkFilter = ({ type, selectedChain, onSelect }: Props) => {
|
|
|
134
135
|
className="w-5 h-5 rounded-full"
|
|
135
136
|
/>
|
|
136
137
|
) : (
|
|
137
|
-
<div className="
|
|
138
|
-
{
|
|
138
|
+
<div className="grid grid-cols-2 gap-0.5 shrink-0">
|
|
139
|
+
{clusterChains.map((clusterChain) => (
|
|
139
140
|
<img
|
|
140
|
-
key={
|
|
141
|
-
src={
|
|
142
|
-
alt={
|
|
143
|
-
className="w-
|
|
141
|
+
key={clusterChain.chainId}
|
|
142
|
+
src={clusterChain.image}
|
|
143
|
+
alt={clusterChain.displayName}
|
|
144
|
+
className="w-[11px] h-[11px] rounded-full"
|
|
144
145
|
/>
|
|
145
146
|
))}
|
|
146
147
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { faCheck } from "@fortawesome/free-solid-svg-icons";
|
|
2
2
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
3
|
-
import { CloseIcon, CopyIcon,
|
|
3
|
+
import { CloseIcon, CopyIcon, SearchThinIcon } from "@src/assets/icons";
|
|
4
4
|
import {
|
|
5
5
|
Button,
|
|
6
6
|
Spinner,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "@src/utils";
|
|
21
21
|
import { BigNumber, ethers } from "ethers";
|
|
22
22
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
23
|
-
import {
|
|
23
|
+
import { Virtuoso } from "react-virtuoso";
|
|
24
24
|
import { NetworkFilter } from "./NetworkFilter";
|
|
25
25
|
import { TokenItem } from "./TokenItem";
|
|
26
26
|
import { useAccount } from "wagmi";
|
|
@@ -55,7 +55,11 @@ export const TokenPicker = ({
|
|
|
55
55
|
const [loadingCustomTokenData, setLoadingCustomTokenData] = useState(false);
|
|
56
56
|
const [customTokenData, setCustomTokenData] =
|
|
57
57
|
useState<ImportedTokenData | null>(null);
|
|
58
|
-
|
|
58
|
+
// Always opens on "All Networks" — the cross-chain token list is the
|
|
59
|
+
// default view even when a chain is already set on the swap panel.
|
|
60
|
+
const [networkFilter, setNetworkFilter] = useState<Chain | undefined>(
|
|
61
|
+
undefined,
|
|
62
|
+
);
|
|
59
63
|
const currentRouteRequestNonce = useRef<number>(0);
|
|
60
64
|
const tokenSearchRef = useRef<HTMLInputElement | null>(null);
|
|
61
65
|
|
|
@@ -295,8 +299,7 @@ export const TokenPicker = ({
|
|
|
295
299
|
|
|
296
300
|
useEffect(() => {
|
|
297
301
|
setSearchValue("");
|
|
298
|
-
setNetworkFilter(
|
|
299
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
302
|
+
setNetworkFilter(undefined);
|
|
300
303
|
}, [isOpen]);
|
|
301
304
|
|
|
302
305
|
const isMatch = (value, searchValue) =>
|
|
@@ -422,11 +425,50 @@ export const TokenPicker = ({
|
|
|
422
425
|
: [{ label: "RECOMMENDED.", tokens: recommendedTokens }];
|
|
423
426
|
}, [ownedTokens, recommendedTokens]);
|
|
424
427
|
|
|
425
|
-
|
|
426
|
-
|
|
428
|
+
// The current group's label renders OUTSIDE the scroll container (pinned
|
|
429
|
+
// above it, transparent bg), so rows physically clip on the label's bottom
|
|
430
|
+
// edge — the scroller's top edge. Labels of the following groups stay
|
|
431
|
+
// in-flow and take over the pinned slot once they reach that line.
|
|
432
|
+
const listRows = useMemo(
|
|
433
|
+
() =>
|
|
434
|
+
tokenGroups.flatMap((group, groupIndex) => {
|
|
435
|
+
const rows: (
|
|
436
|
+
| { kind: "label"; label: string; groupLabel: string }
|
|
437
|
+
| { kind: "empty"; groupLabel: string }
|
|
438
|
+
| { kind: "token"; token: TokenOption; groupLabel: string }
|
|
439
|
+
)[] =
|
|
440
|
+
groupIndex === 0
|
|
441
|
+
? []
|
|
442
|
+
: [
|
|
443
|
+
{
|
|
444
|
+
kind: "label",
|
|
445
|
+
label: group.label,
|
|
446
|
+
groupLabel: group.label,
|
|
447
|
+
},
|
|
448
|
+
];
|
|
449
|
+
if (group.tokens.length) {
|
|
450
|
+
rows.push(
|
|
451
|
+
...group.tokens.map((token) => ({
|
|
452
|
+
kind: "token" as const,
|
|
453
|
+
token,
|
|
454
|
+
groupLabel: group.label,
|
|
455
|
+
})),
|
|
456
|
+
);
|
|
457
|
+
} else {
|
|
458
|
+
rows.push({ kind: "empty", groupLabel: group.label });
|
|
459
|
+
}
|
|
460
|
+
return rows;
|
|
461
|
+
}),
|
|
427
462
|
[tokenGroups],
|
|
428
463
|
);
|
|
429
464
|
|
|
465
|
+
// Index of the topmost (partially) visible row, reported by Virtuoso.
|
|
466
|
+
const [topRowIndex, setTopRowIndex] = useState(0);
|
|
467
|
+
const pinnedGroupLabel =
|
|
468
|
+
listRows[Math.min(topRowIndex, listRows.length - 1)]?.groupLabel ??
|
|
469
|
+
tokenGroups[0]?.label ??
|
|
470
|
+
"";
|
|
471
|
+
|
|
430
472
|
useEffect(() => {
|
|
431
473
|
if (isOpen && tokenSearchRef.current) {
|
|
432
474
|
setTimeout(() => {
|
|
@@ -545,8 +587,8 @@ export const TokenPicker = ({
|
|
|
545
587
|
|
|
546
588
|
<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">
|
|
547
589
|
<div className="flex items-center gap-2 flex-1 min-w-0">
|
|
548
|
-
<div className="
|
|
549
|
-
<
|
|
590
|
+
<div className="text-t_text_primary opacity-60 flex items-center shrink-0">
|
|
591
|
+
<SearchThinIcon />
|
|
550
592
|
</div>
|
|
551
593
|
<input
|
|
552
594
|
ref={tokenSearchRef}
|
|
@@ -603,45 +645,54 @@ export const TokenPicker = ({
|
|
|
603
645
|
</div>
|
|
604
646
|
</div>
|
|
605
647
|
) : (
|
|
606
|
-
<div className="flex flex-col h-full">
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
648
|
+
<div className="flex flex-col h-full min-h-0">
|
|
649
|
+
{/* Pinned label of the group at the top of the list; sits
|
|
650
|
+
above the scroller, so rows clip on its bottom edge. */}
|
|
651
|
+
<p className="pb-3 text-[10px] font-medium leading-4 tracking-[0.015em] text-t_text_primary text-opacity-30 text-left shrink-0">
|
|
652
|
+
{pinnedGroupLabel}
|
|
653
|
+
</p>
|
|
654
|
+
<div className="relative flex flex-col flex-1 min-h-0">
|
|
655
|
+
<Virtuoso
|
|
656
|
+
style={{ maxHeight: "700px", height: "100%" }}
|
|
657
|
+
totalCount={listRows.length}
|
|
658
|
+
rangeChanged={({ startIndex }) => setTopRowIndex(startIndex)}
|
|
659
|
+
itemContent={(index) => {
|
|
660
|
+
const row = listRows[index];
|
|
661
|
+
if (!row) {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
if (row.kind === "label") {
|
|
665
|
+
return (
|
|
666
|
+
<p className="pt-2 pb-3 text-[10px] font-medium leading-4 tracking-[0.015em] text-t_text_primary text-opacity-30 text-left">
|
|
667
|
+
{row.label}
|
|
668
|
+
</p>
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
if (row.kind === "empty") {
|
|
672
|
+
return (
|
|
673
|
+
<div className="text-center py-1 pb-3 text-sm text-t_text_primary text-opacity-50">
|
|
674
|
+
No token found
|
|
675
|
+
</div>
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
return (
|
|
630
679
|
<TokenItem
|
|
631
680
|
panelType={type}
|
|
632
|
-
token={token}
|
|
681
|
+
token={row.token}
|
|
633
682
|
selectedChainId={chain?.chainId}
|
|
634
683
|
selectedTokenAddress={selectedTokenAddress}
|
|
635
|
-
resetWarning={getResetWarning(token)}
|
|
684
|
+
resetWarning={getResetWarning(row.token)}
|
|
636
685
|
onClick={() => {
|
|
637
|
-
onSelect(token);
|
|
686
|
+
onSelect(row.token);
|
|
638
687
|
setModalOpen(false);
|
|
639
688
|
}}
|
|
640
689
|
/>
|
|
641
|
-
)
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
690
|
+
);
|
|
691
|
+
}}
|
|
692
|
+
/>
|
|
693
|
+
{/* Scroll fade — rows dissolve towards the widget bottom */}
|
|
694
|
+
<div className="pointer-events-none absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-t from-t_bg_secondary/65 to-t_bg_secondary/0" />
|
|
695
|
+
</div>
|
|
645
696
|
</div>
|
|
646
697
|
)}
|
|
647
698
|
</>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChevronDownThinIcon } from "@src/assets/icons";
|
|
2
2
|
import { TokenLogoWithChain } from "@src/components";
|
|
3
3
|
import { useSwapContext } from "@src/context";
|
|
4
4
|
import { Chain, Token } from "@src/models";
|
|
@@ -50,7 +50,7 @@ export const TokenPanel = ({ chain, token, type, className }: Props) => {
|
|
|
50
50
|
onClick={() => {
|
|
51
51
|
setActivePicker(type);
|
|
52
52
|
}}
|
|
53
|
-
className={`flex items-center
|
|
53
|
+
className={`flex items-center shrink-0 min-h-11 rounded-lg ${
|
|
54
54
|
locked ? "" : "hover:opacity-80 transition-opacity"
|
|
55
55
|
} ${className || ""}`}
|
|
56
56
|
>
|
|
@@ -86,8 +86,8 @@ export const TokenPanel = ({ chain, token, type, className }: Props) => {
|
|
|
86
86
|
)}
|
|
87
87
|
</div>
|
|
88
88
|
{!locked && (
|
|
89
|
-
<div className="flex items-center justify-center w-6 h-6
|
|
90
|
-
<
|
|
89
|
+
<div className="flex items-center justify-center w-6 h-6 text-t_text_primary opacity-50">
|
|
90
|
+
<ChevronDownThinIcon />
|
|
91
91
|
</div>
|
|
92
92
|
)}
|
|
93
93
|
</button>
|
|
@@ -16,11 +16,11 @@ export const UsdValue = ({ type }: Props) => {
|
|
|
16
16
|
);
|
|
17
17
|
|
|
18
18
|
if (type === "destination" && isFetchingRoute) {
|
|
19
|
-
return <Skeleton className="w-[80px] h-[16px]" />;
|
|
19
|
+
return <Skeleton className="w-[80px] h-[16px] my-1" />;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
|
-
<p className="text-[10px] leading-4 tracking-[0.01em] text-t_text_primary text-opacity-50 whitespace-nowrap">
|
|
23
|
+
<p className="py-1 text-[10px] leading-4 tracking-[0.01em] text-t_text_primary text-opacity-50 whitespace-nowrap">
|
|
24
24
|
{valueUsd ? `${valueUsd} USD` : ""}
|
|
25
25
|
</p>
|
|
26
26
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChevronDownThinSmallIcon } from "@src/assets/icons";
|
|
2
2
|
import { useWallet } from "@src/context/WalletProvider";
|
|
3
3
|
import { useSwapContext } from "@src/context";
|
|
4
4
|
import { SwapPanelType } from "../..";
|
|
@@ -27,19 +27,18 @@ export const WalletPanel = ({ chain, className }: Props) => {
|
|
|
27
27
|
const openEvmWalletModal = useCallback(() => {
|
|
28
28
|
// Mirror SwapButton's contract: when the integrator supplied their own
|
|
29
29
|
// connect handler and did not opt into the built-in picker, defer to it
|
|
30
|
-
//
|
|
30
|
+
// in every state — the host decides whether to show its connect modal or
|
|
31
|
+
// its account modal (e.g. RainbowKit) for an already-connected wallet.
|
|
31
32
|
if (!integrationConfig.defaultWalletPicker && hasOnConnectWalletCallback) {
|
|
32
33
|
onConnectWallet();
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
setOpenEVMWalletModal(true);
|
|
36
|
-
evm.connectWallet();
|
|
37
37
|
}, [
|
|
38
38
|
integrationConfig.defaultWalletPicker,
|
|
39
39
|
hasOnConnectWalletCallback,
|
|
40
40
|
onConnectWallet,
|
|
41
41
|
setOpenEVMWalletModal,
|
|
42
|
-
evm,
|
|
43
42
|
]);
|
|
44
43
|
|
|
45
44
|
const openWalletModal = useCallback(() => {
|
|
@@ -50,17 +49,10 @@ export const WalletPanel = ({ chain, className }: Props) => {
|
|
|
50
49
|
openEvmWalletModal();
|
|
51
50
|
} else if (chain.ecosystem === "solana") {
|
|
52
51
|
setOpenSolanaWalletModal(true);
|
|
53
|
-
solana.connectWallet();
|
|
54
52
|
} else if (chain.ecosystem === "sui") {
|
|
55
53
|
setOpenSuiWalletModal(true);
|
|
56
54
|
}
|
|
57
|
-
}, [
|
|
58
|
-
chain,
|
|
59
|
-
openEvmWalletModal,
|
|
60
|
-
solana,
|
|
61
|
-
setOpenSolanaWalletModal,
|
|
62
|
-
setOpenSuiWalletModal,
|
|
63
|
-
]);
|
|
55
|
+
}, [chain, openEvmWalletModal, setOpenSolanaWalletModal, setOpenSuiWalletModal]);
|
|
64
56
|
|
|
65
57
|
const address = useMemo(() => {
|
|
66
58
|
if (!chain) {
|
|
@@ -76,23 +68,25 @@ export const WalletPanel = ({ chain, className }: Props) => {
|
|
|
76
68
|
return "";
|
|
77
69
|
}, [chain, evm, solana, sui]);
|
|
78
70
|
|
|
71
|
+
// Reserve the button's height before the chain loads so the card
|
|
72
|
+
// doesn't grow when the wallet button appears.
|
|
79
73
|
if (!chain) {
|
|
80
|
-
return
|
|
74
|
+
return <div className="h-6" aria-hidden />;
|
|
81
75
|
}
|
|
82
76
|
|
|
83
77
|
return (
|
|
84
78
|
<button
|
|
85
79
|
type="button"
|
|
86
80
|
onClick={openWalletModal}
|
|
87
|
-
className={`flex items-center justify-center
|
|
81
|
+
className={`flex items-center justify-center px-2 py-1 rounded bg-t_bg_tertiary bg-opacity-5 hover:bg-opacity-10 transition-colors ${
|
|
88
82
|
className || ""
|
|
89
83
|
}`}
|
|
90
84
|
>
|
|
91
85
|
<p className="text-[10px] leading-4 tracking-[0.01em] text-t_text_primary whitespace-nowrap">
|
|
92
86
|
{address ? shortAddress(address) : "Connect"}
|
|
93
87
|
</p>
|
|
94
|
-
<div className="flex items-center justify-center w-4 h-4
|
|
95
|
-
<
|
|
88
|
+
<div className="flex items-center justify-center w-4 h-4 text-t_text_primary opacity-50">
|
|
89
|
+
<ChevronDownThinSmallIcon />
|
|
96
90
|
</div>
|
|
97
91
|
</button>
|
|
98
92
|
);
|
|
@@ -25,13 +25,13 @@ export const SwapPanel = ({ type }: Props) => {
|
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
27
|
<div
|
|
28
|
-
className={`flex flex-col gap-2 px-4 sm:px-6 py-4 rounded-2xl
|
|
28
|
+
className={`flex flex-col gap-2 px-4 sm:px-6 py-4 rounded-2xl backdrop-blur-[12px] ${
|
|
29
29
|
type === "source"
|
|
30
30
|
? "bg-gradient-to-r from-t_bg_tertiary/5 to-t_bg_tertiary/5 border border-solid border-t_text_primary border-opacity-25"
|
|
31
31
|
: "bg-gradient-to-r from-t_bg_tertiary/[0.03] to-t_bg_tertiary/[0.03]"
|
|
32
32
|
}`}
|
|
33
33
|
>
|
|
34
|
-
<div className="flex gap-2 items-center w-full">
|
|
34
|
+
<div className="flex gap-2 items-center w-full min-h-6">
|
|
35
35
|
<p className="text-[10px] leading-4 tracking-[0.01em] text-t_text_primary text-opacity-50">
|
|
36
36
|
{type === "source" ? "Source" : "Destination"}
|
|
37
37
|
</p>
|
|
@@ -41,7 +41,7 @@ export const SwapPanel = ({ type }: Props) => {
|
|
|
41
41
|
<AmountPanel type={type} />
|
|
42
42
|
<TokenPanel chain={chain} token={token} type={type} />
|
|
43
43
|
</div>
|
|
44
|
-
<div className="flex items-center justify-between w-full gap-4">
|
|
44
|
+
<div className="flex items-center justify-between w-full gap-4 min-h-6">
|
|
45
45
|
<UsdValue type={type} />
|
|
46
46
|
<Balance type={type} />
|
|
47
47
|
</div>
|