@ensofinance/checkout-widget 0.1.2 → 0.1.3
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/dist/checkout-widget.es.js +5399 -5368
- package/dist/checkout-widget.es.js.map +1 -1
- package/dist/checkout-widget.umd.js +46 -46
- package/dist/checkout-widget.umd.js.map +1 -1
- package/package.json +2 -1
- package/src/components/AmountInput.tsx +233 -0
- package/src/components/steps/ExchangeFlow.tsx +62 -143
- package/src/components/steps/WalletFlow/WalletAmountStep.tsx +75 -155
- package/src/util/common.tsx +23 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ensofinance/checkout-widget",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://www.enso.build/",
|
|
6
6
|
"repository": {
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"globals": "^15.14.0",
|
|
61
61
|
"orval": "^7.10.0",
|
|
62
62
|
"prettier": "^3.4.2",
|
|
63
|
+
"source-map-explorer": "^2.5.3",
|
|
63
64
|
"typescript": "~5.8.2",
|
|
64
65
|
"typescript-eslint": "^8.18.2",
|
|
65
66
|
"vite": "^6.0.5",
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { Box, Icon, Text } from "@chakra-ui/react";
|
|
2
|
+
import { ArrowDownUpIcon } from "lucide-react";
|
|
3
|
+
import { Input, IconButton, Tab } from "@/components/ui";
|
|
4
|
+
import { formatNumber, formatUSD } from "@/util";
|
|
5
|
+
import { precisionizeNumber, sanitizeDecimalInput } from "@/util/common";
|
|
6
|
+
|
|
7
|
+
export type InputMode = "usd" | "token";
|
|
8
|
+
|
|
9
|
+
export type AmountInputValue = {
|
|
10
|
+
tokenAmount: string;
|
|
11
|
+
usdAmount: string;
|
|
12
|
+
mode: InputMode;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type PercentOption = {
|
|
16
|
+
label: string;
|
|
17
|
+
value: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type AmountInputProps = {
|
|
21
|
+
value: AmountInputValue;
|
|
22
|
+
onChange: (value: AmountInputValue) => void;
|
|
23
|
+
tokenSymbol?: string;
|
|
24
|
+
tokenPriceUsd?: number;
|
|
25
|
+
tokenBalance?: number;
|
|
26
|
+
roundingPrecision?: number;
|
|
27
|
+
usdPrecision?: number;
|
|
28
|
+
percentOptions?: PercentOption[];
|
|
29
|
+
onPercentSelect?: (
|
|
30
|
+
percent: number,
|
|
31
|
+
) => { tokenAmount: string; usdAmount: string } | null | undefined;
|
|
32
|
+
showPercentTabs?: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const defaultPercentOptions: PercentOption[] = [
|
|
36
|
+
{ label: "25%", value: 25 },
|
|
37
|
+
{ label: "50%", value: 50 },
|
|
38
|
+
{ label: "75%", value: 75 },
|
|
39
|
+
{ label: "Max", value: 100 },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
export const AmountInput = ({
|
|
43
|
+
value,
|
|
44
|
+
onChange,
|
|
45
|
+
tokenSymbol,
|
|
46
|
+
tokenPriceUsd,
|
|
47
|
+
tokenBalance,
|
|
48
|
+
roundingPrecision = 6,
|
|
49
|
+
usdPrecision = 2,
|
|
50
|
+
percentOptions = defaultPercentOptions,
|
|
51
|
+
onPercentSelect,
|
|
52
|
+
showPercentTabs = true,
|
|
53
|
+
}: AmountInputProps) => {
|
|
54
|
+
const updateValue = (next: Partial<AmountInputValue>) => {
|
|
55
|
+
onChange({ ...value, ...next });
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleInputChange = (rawValue: string) => {
|
|
59
|
+
if (value.mode === "usd") {
|
|
60
|
+
const cleanUsd = sanitizeDecimalInput(
|
|
61
|
+
rawValue.replace("$", ""),
|
|
62
|
+
usdPrecision,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (!cleanUsd || cleanUsd === ".") {
|
|
66
|
+
updateValue({ usdAmount: cleanUsd, tokenAmount: "" });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!tokenPriceUsd || tokenPriceUsd <= 0) {
|
|
71
|
+
updateValue({ usdAmount: cleanUsd, tokenAmount: "" });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const tokenAmountFromUsd = precisionizeNumber(
|
|
76
|
+
parseFloat(cleanUsd) / tokenPriceUsd,
|
|
77
|
+
roundingPrecision,
|
|
78
|
+
);
|
|
79
|
+
updateValue({
|
|
80
|
+
usdAmount: cleanUsd,
|
|
81
|
+
tokenAmount: tokenAmountFromUsd,
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const cleanTokenAmount = sanitizeDecimalInput(
|
|
87
|
+
rawValue,
|
|
88
|
+
roundingPrecision,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!cleanTokenAmount || cleanTokenAmount === ".") {
|
|
92
|
+
updateValue({ tokenAmount: cleanTokenAmount, usdAmount: "" });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!tokenPriceUsd || tokenPriceUsd <= 0) {
|
|
97
|
+
updateValue({ tokenAmount: cleanTokenAmount });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
updateValue({
|
|
102
|
+
tokenAmount: cleanTokenAmount,
|
|
103
|
+
usdAmount: (
|
|
104
|
+
parseFloat(cleanTokenAmount) * tokenPriceUsd
|
|
105
|
+
).toFixed(usdPrecision),
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const handleToggleMode = () => {
|
|
110
|
+
updateValue({
|
|
111
|
+
mode: value.mode === "usd" ? "token" : "usd",
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const handlePercentSelect = (percent: number) => {
|
|
116
|
+
if (onPercentSelect) {
|
|
117
|
+
const nextValues = onPercentSelect(percent);
|
|
118
|
+
if (!nextValues) return;
|
|
119
|
+
|
|
120
|
+
updateValue(nextValues);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!tokenBalance || !tokenPriceUsd || tokenPriceUsd <= 0) return;
|
|
125
|
+
|
|
126
|
+
const tokenAmount = precisionizeNumber(
|
|
127
|
+
(tokenBalance * percent) / 100,
|
|
128
|
+
roundingPrecision,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
updateValue({
|
|
132
|
+
tokenAmount,
|
|
133
|
+
usdAmount: (
|
|
134
|
+
parseFloat(tokenAmount || "0") * tokenPriceUsd
|
|
135
|
+
).toFixed(usdPrecision),
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const placeholder = value.mode === "usd" ? "$10.00" : "0.00";
|
|
140
|
+
const displayValue =
|
|
141
|
+
value.mode === "usd"
|
|
142
|
+
? value.usdAmount
|
|
143
|
+
? `$${value.usdAmount}`
|
|
144
|
+
: ""
|
|
145
|
+
: value.tokenAmount;
|
|
146
|
+
|
|
147
|
+
const hasTokenValue = !!value.tokenAmount && value.tokenAmount !== ".";
|
|
148
|
+
const hasUsdValue = !!value.usdAmount && value.usdAmount !== ".";
|
|
149
|
+
|
|
150
|
+
const formattedTokenValue = hasTokenValue
|
|
151
|
+
? formatNumber(value.tokenAmount)
|
|
152
|
+
: "";
|
|
153
|
+
const tokenSuffix = tokenSymbol ? ` ${tokenSymbol}` : "";
|
|
154
|
+
const equivalentValue =
|
|
155
|
+
value.mode === "usd"
|
|
156
|
+
? hasTokenValue
|
|
157
|
+
? `${formattedTokenValue}${tokenSuffix}`
|
|
158
|
+
: "—"
|
|
159
|
+
: hasUsdValue
|
|
160
|
+
? formatUSD(value.usdAmount)
|
|
161
|
+
: "—";
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Box display={"flex"} flexDirection={"column"} gap={"8px"}>
|
|
165
|
+
<Box
|
|
166
|
+
display={"flex"}
|
|
167
|
+
flexDirection={"column"}
|
|
168
|
+
gap={"8px"}
|
|
169
|
+
alignItems={"center"}
|
|
170
|
+
padding={"25.5px"}
|
|
171
|
+
>
|
|
172
|
+
{/* Main Input */}
|
|
173
|
+
<Input
|
|
174
|
+
inputMode="decimal"
|
|
175
|
+
marginY={"8px"}
|
|
176
|
+
variant={"text"}
|
|
177
|
+
placeholder={placeholder}
|
|
178
|
+
value={displayValue}
|
|
179
|
+
onChange={(event) => handleInputChange(event.target.value)}
|
|
180
|
+
/>
|
|
181
|
+
|
|
182
|
+
{/* Toggle Button and Equivalent Display */}
|
|
183
|
+
<Box
|
|
184
|
+
display={"flex"}
|
|
185
|
+
gap={"3"}
|
|
186
|
+
alignItems={"center"}
|
|
187
|
+
onClick={handleToggleMode}
|
|
188
|
+
_hover={{ background: "bg.subtle" }}
|
|
189
|
+
cursor={"pointer"}
|
|
190
|
+
borderRadius={"lg"}
|
|
191
|
+
px={"3"}
|
|
192
|
+
>
|
|
193
|
+
<IconButton
|
|
194
|
+
minWidth={"24px"}
|
|
195
|
+
minHeight={"24px"}
|
|
196
|
+
maxWidth={"24px"}
|
|
197
|
+
background={"transparent"}
|
|
198
|
+
>
|
|
199
|
+
<Icon
|
|
200
|
+
as={ArrowDownUpIcon}
|
|
201
|
+
color="gray"
|
|
202
|
+
width={"16px"}
|
|
203
|
+
height={"16px"}
|
|
204
|
+
/>
|
|
205
|
+
</IconButton>
|
|
206
|
+
|
|
207
|
+
{/* Small equivalent value display */}
|
|
208
|
+
<Text fontSize="sm" color="fg.muted">
|
|
209
|
+
{equivalentValue}
|
|
210
|
+
</Text>
|
|
211
|
+
</Box>
|
|
212
|
+
</Box>
|
|
213
|
+
|
|
214
|
+
{showPercentTabs && percentOptions.length > 0 && (
|
|
215
|
+
<Box
|
|
216
|
+
display={"flex"}
|
|
217
|
+
gap={"4px"}
|
|
218
|
+
justifyContent={"center"}
|
|
219
|
+
paddingBottom={"35px"}
|
|
220
|
+
>
|
|
221
|
+
{percentOptions.map((option) => (
|
|
222
|
+
<Tab
|
|
223
|
+
key={option.label}
|
|
224
|
+
onClick={() => handlePercentSelect(option.value)}
|
|
225
|
+
>
|
|
226
|
+
{option.label}
|
|
227
|
+
</Tab>
|
|
228
|
+
))}
|
|
229
|
+
</Box>
|
|
230
|
+
)}
|
|
231
|
+
</Box>
|
|
232
|
+
);
|
|
233
|
+
};
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
Image,
|
|
10
10
|
Table,
|
|
11
11
|
} from "@chakra-ui/react";
|
|
12
|
-
import { ChevronLeft, X,
|
|
12
|
+
import { ChevronLeft, X, TriangleAlert } from "lucide-react";
|
|
13
13
|
import { useContext, useEffect, useMemo, useState, useCallback } from "react";
|
|
14
14
|
import { useAccount, useSignMessage } from "wagmi";
|
|
15
15
|
import { getUserOperationHash } from "viem/account-abstraction";
|
|
@@ -20,7 +20,8 @@ import {
|
|
|
20
20
|
HeaderWrapper,
|
|
21
21
|
ListWrapper,
|
|
22
22
|
} from "../ui/styled";
|
|
23
|
-
import { IconButton, Button,
|
|
23
|
+
import { IconButton, Button, Input } from "../ui";
|
|
24
|
+
import { AmountInput, AmountInputValue } from "../AmountInput";
|
|
24
25
|
import { CheckoutContext } from "../Checkout";
|
|
25
26
|
import Modal from "../modal";
|
|
26
27
|
import {
|
|
@@ -797,13 +798,17 @@ const ChooseAmountStep = ({
|
|
|
797
798
|
setStep: (step: WithdrawalStep) => void;
|
|
798
799
|
selectedToken: MatchedToken | null;
|
|
799
800
|
}) => {
|
|
800
|
-
const [
|
|
801
|
-
|
|
802
|
-
|
|
801
|
+
const [amountInput, setAmountInput] = useState<AmountInputValue>({
|
|
802
|
+
tokenAmount: "",
|
|
803
|
+
usdAmount: "",
|
|
804
|
+
mode: "usd",
|
|
805
|
+
});
|
|
803
806
|
const setAmountIn = useAppStore((s) => s.setAmountIn);
|
|
804
807
|
const { tokenInData, selectedIntegration } = useAppDetails();
|
|
805
808
|
const isStable = selectedToken?.symbol.toLowerCase().includes("USD");
|
|
806
809
|
const roundingPrecision = isStable ? 2 : 6;
|
|
810
|
+
const amount = amountInput.tokenAmount;
|
|
811
|
+
const usdValue = amountInput.usdAmount;
|
|
807
812
|
|
|
808
813
|
// Only apply CEX withdrawal limits if using a CEX holding (not smart account)
|
|
809
814
|
const isWithdrawal = !isDelayedBalanceUsed(selectedIntegration.type);
|
|
@@ -816,8 +821,13 @@ const ChooseAmountStep = ({
|
|
|
816
821
|
: selectedToken.marketValue.toFixed(2)
|
|
817
822
|
: 0;
|
|
818
823
|
|
|
824
|
+
const tokenPriceUsd = useMemo(() => {
|
|
825
|
+
if (!selectedToken || !selectedToken.balance) return undefined;
|
|
826
|
+
return selectedToken.marketValue / selectedToken.balance;
|
|
827
|
+
}, [selectedToken]);
|
|
828
|
+
|
|
819
829
|
// Handle percentage selection with limits (only for CEX withdrawals)
|
|
820
|
-
const
|
|
830
|
+
const getPercentAmounts = useCallback(
|
|
821
831
|
(percent: number) => {
|
|
822
832
|
if (!selectedToken) return;
|
|
823
833
|
|
|
@@ -851,8 +861,13 @@ const ChooseAmountStep = ({
|
|
|
851
861
|
finalTokenAmount = (selectedToken.balance * percent) / 100;
|
|
852
862
|
}
|
|
853
863
|
|
|
854
|
-
|
|
855
|
-
|
|
864
|
+
return {
|
|
865
|
+
tokenAmount: precisionizeNumber(
|
|
866
|
+
finalTokenAmount,
|
|
867
|
+
roundingPrecision,
|
|
868
|
+
),
|
|
869
|
+
usdAmount: finalUsdAmount.toFixed(2),
|
|
870
|
+
};
|
|
856
871
|
},
|
|
857
872
|
[selectedToken, isWithdrawal, maxUsdAmount, roundingPrecision],
|
|
858
873
|
);
|
|
@@ -860,85 +875,43 @@ const ChooseAmountStep = ({
|
|
|
860
875
|
// Set max value on load
|
|
861
876
|
useEffect(() => {
|
|
862
877
|
if (selectedToken) {
|
|
863
|
-
|
|
878
|
+
const percentAmounts = getPercentAmounts(100);
|
|
879
|
+
if (!percentAmounts) return;
|
|
880
|
+
|
|
881
|
+
setAmountInput((prev) => ({
|
|
882
|
+
...prev,
|
|
883
|
+
...percentAmounts,
|
|
884
|
+
}));
|
|
864
885
|
}
|
|
865
|
-
}, [selectedToken,
|
|
886
|
+
}, [selectedToken, getPercentAmounts]);
|
|
866
887
|
|
|
867
888
|
useEffect(() => {
|
|
868
|
-
if (tokenInData?.decimals)
|
|
869
|
-
setAmountIn(
|
|
870
|
-
Number(
|
|
871
|
-
denormalizeValue(amount || "0", tokenInData?.decimals),
|
|
872
|
-
).toFixed(),
|
|
873
|
-
);
|
|
874
|
-
}, [amount, tokenInData?.decimals]);
|
|
889
|
+
if (!tokenInData?.decimals) return;
|
|
875
890
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
891
|
+
const normalizedAmount = amount.endsWith(".")
|
|
892
|
+
? amount.slice(0, -1)
|
|
893
|
+
: amount;
|
|
879
894
|
|
|
880
|
-
if (
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
if (!cleanUsd) {
|
|
884
|
-
setAmount("");
|
|
885
|
-
return;
|
|
886
|
-
}
|
|
887
|
-
// Calculate token amount from USD value
|
|
888
|
-
const tokenPrice =
|
|
889
|
-
selectedToken.marketValue / selectedToken.balance;
|
|
890
|
-
const tokenAmount = parseFloat(cleanUsd) / tokenPrice;
|
|
891
|
-
setAmount(
|
|
892
|
-
isNaN(tokenAmount)
|
|
893
|
-
? ""
|
|
894
|
-
: precisionizeNumber(tokenAmount, roundingPrecision),
|
|
895
|
-
);
|
|
896
|
-
} else {
|
|
897
|
-
if (!value) {
|
|
898
|
-
setAmount("");
|
|
899
|
-
setUsdValue("");
|
|
900
|
-
return;
|
|
901
|
-
}
|
|
902
|
-
setAmount(precisionizeNumber(value, roundingPrecision));
|
|
903
|
-
// Calculate USD value from token amount
|
|
904
|
-
const tokenPrice =
|
|
905
|
-
selectedToken.marketValue / selectedToken.balance;
|
|
906
|
-
const usdAmount = parseFloat(value) * tokenPrice;
|
|
907
|
-
setUsdValue(isNaN(usdAmount) ? "" : usdAmount.toFixed(2));
|
|
895
|
+
if (!normalizedAmount || normalizedAmount === ".") {
|
|
896
|
+
setAmountIn("0");
|
|
897
|
+
return;
|
|
908
898
|
}
|
|
909
|
-
};
|
|
910
899
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
// Get input placeholder and display value
|
|
917
|
-
const getInputDisplay = () => {
|
|
918
|
-
if (inputMode === "usd") {
|
|
919
|
-
return {
|
|
920
|
-
placeholder: "$10.00",
|
|
921
|
-
displayValue: usdValue ? `$${usdValue}` : "",
|
|
922
|
-
equivalentValue: amount
|
|
923
|
-
? `${formatNumber(parseFloat(amount))} ${selectedToken?.symbol}`
|
|
924
|
-
: "—",
|
|
925
|
-
};
|
|
926
|
-
} else {
|
|
927
|
-
return {
|
|
928
|
-
placeholder: "0.00",
|
|
929
|
-
displayValue: amount,
|
|
930
|
-
equivalentValue: usdValue ? `$${usdValue}` : "—",
|
|
931
|
-
};
|
|
900
|
+
try {
|
|
901
|
+
setAmountIn(denormalizeValue(normalizedAmount, tokenInData.decimals));
|
|
902
|
+
} catch (error) {
|
|
903
|
+
setAmountIn("0");
|
|
932
904
|
}
|
|
933
|
-
};
|
|
905
|
+
}, [amount, tokenInData?.decimals, setAmountIn]);
|
|
934
906
|
|
|
935
|
-
const
|
|
907
|
+
const hasAmount = !!amount && amount !== ".";
|
|
908
|
+
const hasUsdValue = !!usdValue && usdValue !== ".";
|
|
936
909
|
const notEnoughBalance = selectedToken
|
|
937
|
-
? parseFloat(amount) > selectedToken.balance
|
|
910
|
+
? hasAmount && parseFloat(amount) > selectedToken.balance
|
|
938
911
|
: true;
|
|
939
912
|
|
|
940
913
|
// Limits validation logic - only for CEX withdrawals
|
|
941
|
-
const currentUsdValue = parseFloat(usdValue);
|
|
914
|
+
const currentUsdValue = hasUsdValue ? parseFloat(usdValue) : 0;
|
|
942
915
|
const minValueForToken =
|
|
943
916
|
isWithdrawal && selectedToken
|
|
944
917
|
? EXCHANGE_MIN_LIMIT[
|
|
@@ -949,17 +922,19 @@ const ChooseAmountStep = ({
|
|
|
949
922
|
const isBelowMinAmount =
|
|
950
923
|
isWithdrawal &&
|
|
951
924
|
selectedToken &&
|
|
925
|
+
hasAmount &&
|
|
952
926
|
currentUsdValue > 0 &&
|
|
953
927
|
minValueForToken &&
|
|
954
928
|
+amount < minValueForToken;
|
|
955
929
|
const isAboveMaxAmount =
|
|
956
930
|
isWithdrawal &&
|
|
957
931
|
selectedToken &&
|
|
932
|
+
hasAmount &&
|
|
958
933
|
currentUsdValue > 0 &&
|
|
959
934
|
currentUsdValue > +maxUsdAmount;
|
|
960
935
|
|
|
961
936
|
const isAmountInvalid =
|
|
962
|
-
isBelowMinAmount || isAboveMaxAmount || notEnoughBalance;
|
|
937
|
+
!hasAmount || isBelowMinAmount || isAboveMaxAmount || notEnoughBalance;
|
|
963
938
|
|
|
964
939
|
if (!selectedToken) {
|
|
965
940
|
return (
|
|
@@ -988,70 +963,14 @@ const ChooseAmountStep = ({
|
|
|
988
963
|
gap={"8px"}
|
|
989
964
|
width="100%"
|
|
990
965
|
>
|
|
991
|
-
<
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
<Input
|
|
1000
|
-
inputMode="decimal"
|
|
1001
|
-
marginY={"8px"}
|
|
1002
|
-
variant={"text"}
|
|
1003
|
-
placeholder={placeholder}
|
|
1004
|
-
value={displayValue}
|
|
1005
|
-
onChange={(e) => handleInputChange(e.target.value)}
|
|
1006
|
-
/>
|
|
1007
|
-
|
|
1008
|
-
{/* Toggle Button and Equivalent Display */}
|
|
1009
|
-
<Box
|
|
1010
|
-
display={"flex"}
|
|
1011
|
-
gap={"3"}
|
|
1012
|
-
alignItems={"center"}
|
|
1013
|
-
onClick={handleToggleMode}
|
|
1014
|
-
_hover={{ background: "bg.subtle" }}
|
|
1015
|
-
cursor={"pointer"}
|
|
1016
|
-
borderRadius={"lg"}
|
|
1017
|
-
px={"3"}
|
|
1018
|
-
>
|
|
1019
|
-
<IconButton
|
|
1020
|
-
minWidth={"24px"}
|
|
1021
|
-
minHeight={"24px"}
|
|
1022
|
-
maxWidth={"24px"}
|
|
1023
|
-
background={"transparent"}
|
|
1024
|
-
>
|
|
1025
|
-
<Icon
|
|
1026
|
-
as={ArrowDownUpIcon}
|
|
1027
|
-
color="gray"
|
|
1028
|
-
width={"16px"}
|
|
1029
|
-
height={"16px"}
|
|
1030
|
-
/>
|
|
1031
|
-
</IconButton>
|
|
1032
|
-
|
|
1033
|
-
{/* Small equivalent value display */}
|
|
1034
|
-
<Text fontSize="sm" color="fg.muted">
|
|
1035
|
-
{equivalentValue}
|
|
1036
|
-
</Text>
|
|
1037
|
-
</Box>
|
|
1038
|
-
</Box>
|
|
1039
|
-
|
|
1040
|
-
<Box
|
|
1041
|
-
display={"flex"}
|
|
1042
|
-
gap={"4px"}
|
|
1043
|
-
justifyContent={"center"}
|
|
1044
|
-
paddingBottom={"35px"}
|
|
1045
|
-
>
|
|
1046
|
-
{[25, 50, 75, 100].map((percent) => (
|
|
1047
|
-
<Tab
|
|
1048
|
-
key={percent}
|
|
1049
|
-
onClick={() => handlePercentageSelect(percent)}
|
|
1050
|
-
>
|
|
1051
|
-
{percent === 100 ? "Max" : `${percent}%`}
|
|
1052
|
-
</Tab>
|
|
1053
|
-
))}
|
|
1054
|
-
</Box>
|
|
966
|
+
<AmountInput
|
|
967
|
+
value={amountInput}
|
|
968
|
+
onChange={setAmountInput}
|
|
969
|
+
tokenSymbol={selectedToken.symbol}
|
|
970
|
+
tokenPriceUsd={tokenPriceUsd}
|
|
971
|
+
roundingPrecision={roundingPrecision}
|
|
972
|
+
onPercentSelect={getPercentAmounts}
|
|
973
|
+
/>
|
|
1055
974
|
</Box>
|
|
1056
975
|
|
|
1057
976
|
{
|
|
@@ -1062,10 +981,10 @@ const ChooseAmountStep = ({
|
|
|
1062
981
|
h={3}
|
|
1063
982
|
m={-1}
|
|
1064
983
|
visibility={
|
|
1065
|
-
isAmountInvalid
|
|
984
|
+
isAmountInvalid ? "visible" : "hidden"
|
|
1066
985
|
}
|
|
1067
986
|
>
|
|
1068
|
-
{!
|
|
987
|
+
{!hasAmount
|
|
1069
988
|
? "Please enter an amount"
|
|
1070
989
|
: isBelowMinAmount
|
|
1071
990
|
? `Minimum amount is ${formatNumber(minValueForToken)} ${selectedToken.symbol}`
|
|
@@ -1079,11 +998,11 @@ const ChooseAmountStep = ({
|
|
|
1079
998
|
|
|
1080
999
|
<Button
|
|
1081
1000
|
onClick={() =>
|
|
1082
|
-
isAmountInvalid
|
|
1001
|
+
isAmountInvalid
|
|
1083
1002
|
? undefined
|
|
1084
1003
|
: setStep(WithdrawalStep.SignUserOp)
|
|
1085
1004
|
}
|
|
1086
|
-
disabled={isAmountInvalid
|
|
1005
|
+
disabled={isAmountInvalid}
|
|
1087
1006
|
>
|
|
1088
1007
|
Continue
|
|
1089
1008
|
</Button>
|