@avail-project/widgets 0.0.1

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 (143) hide show
  1. package/README.md +34 -0
  2. package/dist/common/components/ErrorBoundary.d.ts +44 -0
  3. package/dist/common/components/ErrorBoundary.d.ts.map +1 -0
  4. package/dist/common/components/ErrorBoundary.js +65 -0
  5. package/dist/common/hooks/useDebouncedCallback.d.ts +13 -0
  6. package/dist/common/hooks/useDebouncedCallback.d.ts.map +1 -0
  7. package/dist/common/hooks/useDebouncedCallback.js +42 -0
  8. package/dist/common/hooks/useDebouncedValue.d.ts +5 -0
  9. package/dist/common/hooks/useDebouncedValue.d.ts.map +1 -0
  10. package/dist/common/hooks/useDebouncedValue.js +15 -0
  11. package/dist/common/hooks/useInterval.d.ts +11 -0
  12. package/dist/common/hooks/useInterval.d.ts.map +1 -0
  13. package/dist/common/hooks/useInterval.js +25 -0
  14. package/dist/common/hooks/useLatest.d.ts +12 -0
  15. package/dist/common/hooks/useLatest.d.ts.map +1 -0
  16. package/dist/common/hooks/useLatest.js +19 -0
  17. package/dist/common/hooks/useNexusError.d.ts +20 -0
  18. package/dist/common/hooks/useNexusError.d.ts.map +1 -0
  19. package/dist/common/hooks/useNexusError.js +120 -0
  20. package/dist/common/hooks/usePolling.d.ts +7 -0
  21. package/dist/common/hooks/usePolling.d.ts.map +1 -0
  22. package/dist/common/hooks/usePolling.js +29 -0
  23. package/dist/common/hooks/useStableCallback.d.ts +6 -0
  24. package/dist/common/hooks/useStableCallback.d.ts.map +1 -0
  25. package/dist/common/hooks/useStableCallback.js +13 -0
  26. package/dist/common/hooks/useStopwatch.d.ts +17 -0
  27. package/dist/common/hooks/useStopwatch.d.ts.map +1 -0
  28. package/dist/common/hooks/useStopwatch.js +44 -0
  29. package/dist/common/hooks/useTransactionExecution.d.ts +62 -0
  30. package/dist/common/hooks/useTransactionExecution.d.ts.map +1 -0
  31. package/dist/common/hooks/useTransactionExecution.js +273 -0
  32. package/dist/common/hooks/useTransactionFlow.d.ts +71 -0
  33. package/dist/common/hooks/useTransactionFlow.d.ts.map +1 -0
  34. package/dist/common/hooks/useTransactionFlow.js +435 -0
  35. package/dist/common/index.d.ts +17 -0
  36. package/dist/common/index.d.ts.map +1 -0
  37. package/dist/common/index.js +16 -0
  38. package/dist/common/tx/steps.d.ts +19 -0
  39. package/dist/common/tx/steps.d.ts.map +1 -0
  40. package/dist/common/tx/steps.js +89 -0
  41. package/dist/common/tx/types.d.ts +11 -0
  42. package/dist/common/tx/types.d.ts.map +1 -0
  43. package/dist/common/tx/types.js +19 -0
  44. package/dist/common/tx/useTransactionSteps.d.ts +21 -0
  45. package/dist/common/tx/useTransactionSteps.d.ts.map +1 -0
  46. package/dist/common/tx/useTransactionSteps.js +40 -0
  47. package/dist/common/types/transaction-flow.d.ts +48 -0
  48. package/dist/common/types/transaction-flow.d.ts.map +1 -0
  49. package/dist/common/types/transaction-flow.js +2 -0
  50. package/dist/common/utils/constant.d.ts +99 -0
  51. package/dist/common/utils/constant.d.ts.map +1 -0
  52. package/dist/common/utils/constant.js +370 -0
  53. package/dist/common/utils/token-pricing.d.ts +33 -0
  54. package/dist/common/utils/token-pricing.d.ts.map +1 -0
  55. package/dist/common/utils/token-pricing.js +255 -0
  56. package/dist/common/utils/transaction-flow.d.ts +35 -0
  57. package/dist/common/utils/transaction-flow.d.ts.map +1 -0
  58. package/dist/common/utils/transaction-flow.js +65 -0
  59. package/dist/index.d.ts +5 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +2 -0
  62. package/dist/lib/utils.d.ts +4 -0
  63. package/dist/lib/utils.d.ts.map +1 -0
  64. package/dist/lib/utils.js +8 -0
  65. package/dist/nexus/NexusProvider.d.ts +50 -0
  66. package/dist/nexus/NexusProvider.d.ts.map +1 -0
  67. package/dist/nexus/NexusProvider.js +572 -0
  68. package/dist/nexus-widget/components/address-identicon.d.ts +5 -0
  69. package/dist/nexus-widget/components/address-identicon.d.ts.map +1 -0
  70. package/dist/nexus-widget/components/address-identicon.js +39 -0
  71. package/dist/nexus-widget/components/amount-input-unified.d.ts +18 -0
  72. package/dist/nexus-widget/components/amount-input-unified.d.ts.map +1 -0
  73. package/dist/nexus-widget/components/amount-input-unified.js +88 -0
  74. package/dist/nexus-widget/components/deposit-idle-form.d.ts +29 -0
  75. package/dist/nexus-widget/components/deposit-idle-form.d.ts.map +1 -0
  76. package/dist/nexus-widget/components/deposit-idle-form.js +506 -0
  77. package/dist/nexus-widget/components/nexus-widget-progress-screen.d.ts +36 -0
  78. package/dist/nexus-widget/components/nexus-widget-progress-screen.d.ts.map +1 -0
  79. package/dist/nexus-widget/components/nexus-widget-progress-screen.js +737 -0
  80. package/dist/nexus-widget/components/pay-using-selector.d.ts +9 -0
  81. package/dist/nexus-widget/components/pay-using-selector.d.ts.map +1 -0
  82. package/dist/nexus-widget/components/pay-using-selector.js +37 -0
  83. package/dist/nexus-widget/components/pay-with-sources.d.ts +11 -0
  84. package/dist/nexus-widget/components/pay-with-sources.d.ts.map +1 -0
  85. package/dist/nexus-widget/components/pay-with-sources.js +266 -0
  86. package/dist/nexus-widget/components/receive-asset-selector.d.ts +28 -0
  87. package/dist/nexus-widget/components/receive-asset-selector.d.ts.map +1 -0
  88. package/dist/nexus-widget/components/receive-asset-selector.js +1178 -0
  89. package/dist/nexus-widget/components/recipient-input.d.ts +10 -0
  90. package/dist/nexus-widget/components/recipient-input.d.ts.map +1 -0
  91. package/dist/nexus-widget/components/recipient-input.js +44 -0
  92. package/dist/nexus-widget/components/send-idle-form.d.ts +29 -0
  93. package/dist/nexus-widget/components/send-idle-form.d.ts.map +1 -0
  94. package/dist/nexus-widget/components/send-idle-form.js +548 -0
  95. package/dist/nexus-widget/components/status-alerts.d.ts +7 -0
  96. package/dist/nexus-widget/components/status-alerts.d.ts.map +1 -0
  97. package/dist/nexus-widget/components/status-alerts.js +17 -0
  98. package/dist/nexus-widget/components/swap-asset-selector.d.ts +74 -0
  99. package/dist/nexus-widget/components/swap-asset-selector.d.ts.map +1 -0
  100. package/dist/nexus-widget/components/swap-asset-selector.js +1910 -0
  101. package/dist/nexus-widget/components/swap-idle-form.d.ts +29 -0
  102. package/dist/nexus-widget/components/swap-idle-form.d.ts.map +1 -0
  103. package/dist/nexus-widget/components/swap-idle-form.js +1289 -0
  104. package/dist/nexus-widget/components/swap-intent-preview.d.ts +95 -0
  105. package/dist/nexus-widget/components/swap-intent-preview.d.ts.map +1 -0
  106. package/dist/nexus-widget/components/swap-intent-preview.js +1050 -0
  107. package/dist/nexus-widget/nexus-widget.d.ts +4 -0
  108. package/dist/nexus-widget/nexus-widget.d.ts.map +1 -0
  109. package/dist/nexus-widget/nexus-widget.js +7819 -0
  110. package/dist/nexus-widget/sdk-types.d.ts +13 -0
  111. package/dist/nexus-widget/sdk-types.d.ts.map +1 -0
  112. package/dist/nexus-widget/sdk-types.js +1 -0
  113. package/dist/nexus-widget/theme.d.ts +156 -0
  114. package/dist/nexus-widget/theme.d.ts.map +1 -0
  115. package/dist/nexus-widget/theme.js +159 -0
  116. package/dist/nexus-widget/types.d.ts +141 -0
  117. package/dist/nexus-widget/types.d.ts.map +1 -0
  118. package/dist/nexus-widget/types.js +1 -0
  119. package/dist/nexus-widget/utils/citrea-tokens.d.ts +82 -0
  120. package/dist/nexus-widget/utils/citrea-tokens.d.ts.map +1 -0
  121. package/dist/nexus-widget/utils/citrea-tokens.js +136 -0
  122. package/dist/nexus-widget/utils/deposit-source-selection.d.ts +55 -0
  123. package/dist/nexus-widget/utils/deposit-source-selection.d.ts.map +1 -0
  124. package/dist/nexus-widget/utils/deposit-source-selection.js +219 -0
  125. package/dist/swaps/components/stacked-token-icons.d.ts +15 -0
  126. package/dist/swaps/components/stacked-token-icons.d.ts.map +1 -0
  127. package/dist/swaps/components/stacked-token-icons.js +38 -0
  128. package/dist/swaps/components/step-flow.d.ts +32 -0
  129. package/dist/swaps/components/step-flow.d.ts.map +1 -0
  130. package/dist/swaps/components/step-flow.js +54 -0
  131. package/dist/swaps/components/token-icon.d.ts +11 -0
  132. package/dist/swaps/components/token-icon.d.ts.map +1 -0
  133. package/dist/swaps/components/token-icon.js +16 -0
  134. package/dist/swaps/components/transaction-progress.d.ts +43 -0
  135. package/dist/swaps/components/transaction-progress.d.ts.map +1 -0
  136. package/dist/swaps/components/transaction-progress.js +94 -0
  137. package/dist/ui/button.d.ts +11 -0
  138. package/dist/ui/button.d.ts.map +1 -0
  139. package/dist/ui/button.js +34 -0
  140. package/dist/ui/dialog.d.ts +17 -0
  141. package/dist/ui/dialog.d.ts.map +1 -0
  142. package/dist/ui/dialog.js +47 -0
  143. package/package.json +60 -0
@@ -0,0 +1,1050 @@
1
+ // biome-ignore-all lint: NexusWidget registry component from shadcn registry.
2
+ "use client";
3
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ import Decimal from "decimal.js";
5
+ import { ChevronDown, Info, Loader2 } from "lucide-react";
6
+ import React, { useRef, useState } from "react";
7
+ import { CHAIN_METADATA, getShortChainName } from "../../common/utils/constant";
8
+ import TransactionProgress from "../../swaps/components/transaction-progress";
9
+ import { Button } from "../../ui/button";
10
+ import {} from "../types";
11
+ import {} from "./swap-asset-selector";
12
+ const fontFamily = '"Geist", var(--font-geist-sans), system-ui, sans-serif';
13
+ const primary = "var(--foreground-primary, #161615)";
14
+ const muted = "var(--foreground-muted, #848483)";
15
+ const border = "var(--border-default, #E8E8E7)";
16
+ const brand = "var(--foreground-brand)";
17
+ const stripNumeric = (value) => String(value).replace(/[^0-9.-]/g, "");
18
+ const parseDecimal = (value) => {
19
+ if (value === null || value === undefined || value === "")
20
+ return undefined;
21
+ if (Decimal.isDecimal(value))
22
+ return value;
23
+ const cleaned = stripNumeric(value);
24
+ if (!cleaned || cleaned === "-" || cleaned === "." || cleaned === "-.") {
25
+ return undefined;
26
+ }
27
+ try {
28
+ const parsed = new Decimal(cleaned);
29
+ return parsed.isFinite() ? parsed : undefined;
30
+ }
31
+ catch {
32
+ return undefined;
33
+ }
34
+ };
35
+ const toDecimal = (value) => parseDecimal(value) ?? new Decimal(0);
36
+ const formatAmount = (value, options = {}) => {
37
+ const amount = toDecimal(value);
38
+ const max = options.max ?? 2;
39
+ return amount.toDecimalPlaces(max).toFixed();
40
+ };
41
+ const formatUsdDelta = (value) => {
42
+ if (value.gt(0) && value.lt(0.01))
43
+ return "-<0.01 USD";
44
+ return value.gt(0) ? `-${formatAmount(value)} USD` : "0 USD";
45
+ };
46
+ const formatUsdAmount = (value) => {
47
+ if (value.gt(0) && value.lt(0.01))
48
+ return "<0.01 USD";
49
+ return value.gt(0) ? `${formatAmount(value)} USD` : "0 USD";
50
+ };
51
+ const formatUsdValue = (value) => {
52
+ const absolute = value.abs();
53
+ if (absolute.eq(0))
54
+ return "$0";
55
+ if (absolute.lt(0.01))
56
+ return value.lt(0) ? "-<$0.01" : "<$0.01";
57
+ const amount = formatAmount(absolute, { max: 2 });
58
+ return value.lt(0) ? `-$${amount}` : `$${amount}`;
59
+ };
60
+ const formatTokenAmount = (value) => {
61
+ const amount = toDecimal(value);
62
+ return amount.toDecimalPlaces(8).toFixed();
63
+ };
64
+ const formatHeaderTokenAmount = (value) => {
65
+ const amount = toDecimal(value);
66
+ if (amount.isZero())
67
+ return "0";
68
+ if (amount.abs().gte(1000)) {
69
+ return amount.toDecimalPlaces(2).toFixed();
70
+ }
71
+ if (amount.abs().gte(1)) {
72
+ return amount.toDecimalPlaces(4).toFixed();
73
+ }
74
+ return amount.toDecimalPlaces(8).toFixed();
75
+ };
76
+ const getFontSize = (amountStr, symbolStr) => {
77
+ const totalLength = String(amountStr || "").length + String(symbolStr || "").length;
78
+ if (totalLength > 16)
79
+ return "13px";
80
+ if (totalLength > 12)
81
+ return "15px";
82
+ return "17px";
83
+ };
84
+ const unique = (values) => Array.from(new Set(values.filter(Boolean)));
85
+ const isNativeTokenAddress = (address) => {
86
+ const lower = (address ?? "").toLowerCase();
87
+ return (!lower ||
88
+ lower === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" ||
89
+ lower === "0x0000000000000000000000000000000000000000");
90
+ };
91
+ const normalizeIntentToken = (token, chainId) => {
92
+ const chainMeta = chainId ? CHAIN_METADATA[chainId] : undefined;
93
+ const shouldUseNative = isNativeTokenAddress(token?.contractAddress) && Boolean(chainMeta);
94
+ const symbol = shouldUseNative && chainMeta?.nativeCurrency.symbol
95
+ ? chainMeta.nativeCurrency.symbol
96
+ : token?.symbol || chainMeta?.nativeCurrency.symbol || "-";
97
+ const decimals = shouldUseNative && chainMeta?.nativeCurrency.decimals !== undefined
98
+ ? chainMeta.nativeCurrency.decimals
99
+ : (token?.decimals ?? chainMeta?.nativeCurrency.decimals ?? 18);
100
+ return {
101
+ contractAddress: token?.contractAddress ?? "",
102
+ decimals,
103
+ logo: shouldUseNative ? chainMeta?.logo : undefined,
104
+ symbol,
105
+ };
106
+ };
107
+ const formatSymbolSummary = (symbols) => {
108
+ const visible = unique(symbols);
109
+ if (visible.length === 0)
110
+ return "-";
111
+ if (visible.length <= 2)
112
+ return visible.join(", ");
113
+ if (visible.length === 3)
114
+ return `${visible[0]}, ${visible[1]} and ${visible[2]}`;
115
+ const others = visible.length - 2;
116
+ return `${visible[0]}, ${visible[1]} and ${others} other${others === 1 ? "" : "s"}`;
117
+ };
118
+ const sortSourceDetailRowsByUsdDesc = (rows) => [...rows].sort((a, b) => {
119
+ const usdDelta = toDecimal(b.usdAmount).cmp(toDecimal(a.usdAmount));
120
+ if (usdDelta !== 0)
121
+ return usdDelta;
122
+ return (a.symbol ?? "").localeCompare(b.symbol ?? "");
123
+ });
124
+ function IntentLogo({ src, alt, label, size, fontSize, outline, style, }) {
125
+ const [failed, setFailed] = useState(!src);
126
+ React.useEffect(() => {
127
+ setFailed(!src);
128
+ }, [src]);
129
+ const fallbackLabel = (label || alt || "?").trim().slice(0, 1).toUpperCase();
130
+ if (!failed && src) {
131
+ return (_jsx("img", { alt: alt || label || "", onError: () => setFailed(true), src: src, style: {
132
+ backgroundColor: "#FFFFFE",
133
+ borderRadius: "999px",
134
+ height: `${size}px`,
135
+ objectFit: "cover",
136
+ outline,
137
+ width: `${size}px`,
138
+ ...style,
139
+ } }));
140
+ }
141
+ return (_jsx("div", { "aria-label": alt || label || "Token", role: "img", style: {
142
+ alignItems: "center",
143
+ backgroundColor: "#E8F0FF",
144
+ borderRadius: "999px",
145
+ color: brand,
146
+ display: "flex",
147
+ fontFamily,
148
+ fontSize: `${fontSize}px`,
149
+ fontWeight: 700,
150
+ height: `${size}px`,
151
+ justifyContent: "center",
152
+ lineHeight: `${size}px`,
153
+ outline,
154
+ width: `${size}px`,
155
+ ...style,
156
+ }, children: fallbackLabel || "?" }));
157
+ }
158
+ function DetailToggle({ expanded, onClick, }) {
159
+ return (_jsxs("button", { onClick: onClick, style: {
160
+ alignItems: "center",
161
+ background: "transparent",
162
+ border: "none",
163
+ color: brand,
164
+ cursor: "pointer",
165
+ display: "flex",
166
+ fontFamily,
167
+ fontSize: "12px",
168
+ gap: "3px",
169
+ lineHeight: "14px",
170
+ padding: 0,
171
+ }, type: "button", children: [expanded ? "Hide Details" : "View Details", _jsx(ChevronDown, { style: {
172
+ height: 12,
173
+ transform: expanded ? "rotate(180deg)" : "rotate(0deg)",
174
+ transition: "transform 180ms ease",
175
+ width: 12,
176
+ } })] }));
177
+ }
178
+ function TruncatedAddress({ address }) {
179
+ const [showTooltip, setShowTooltip] = useState(false);
180
+ const label = address.length > 12
181
+ ? `${address.slice(0, 6)}...${address.slice(-4)}`
182
+ : address;
183
+ return (_jsxs("span", { onBlur: () => setShowTooltip(false), onFocus: () => setShowTooltip(true), onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), style: {
184
+ color: brand,
185
+ display: "inline-flex",
186
+ fontFamily,
187
+ fontSize: "13px",
188
+ fontWeight: 500,
189
+ lineHeight: "15px",
190
+ outline: "none",
191
+ position: "relative",
192
+ }, tabIndex: 0, children: [label, showTooltip && (_jsx("span", { role: "tooltip", style: {
193
+ background: "#FFFFFE",
194
+ border: `1px solid ${border}`,
195
+ borderRadius: "8px",
196
+ boxShadow: "0 6px 18px rgba(22,22,21,0.10)",
197
+ color: primary,
198
+ fontFamily,
199
+ fontSize: "13px",
200
+ fontWeight: 500,
201
+ lineHeight: "17px",
202
+ padding: "7px 9px",
203
+ pointerEvents: "none",
204
+ position: "absolute",
205
+ right: 0,
206
+ top: "calc(100% + 8px)",
207
+ whiteSpace: "nowrap",
208
+ zIndex: 10000,
209
+ }, children: address }))] }));
210
+ }
211
+ function RecipientRow({ address }) {
212
+ return (_jsxs("div", { style: {
213
+ borderTop: `1px solid ${border}`,
214
+ display: "flex",
215
+ justifyContent: "space-between",
216
+ padding: "13px 14px",
217
+ }, children: [_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "5px" }, children: [_jsx("div", { style: {
218
+ color: primary,
219
+ fontFamily,
220
+ fontSize: "14px",
221
+ fontWeight: 600,
222
+ lineHeight: "18px",
223
+ }, children: "Recipient" }), _jsx("div", { style: {
224
+ color: muted,
225
+ fontFamily,
226
+ fontSize: "12px",
227
+ lineHeight: "14px",
228
+ }, children: "Wallet address" })] }), _jsx("div", { style: { alignItems: "flex-end", display: "flex" }, children: _jsx(TruncatedAddress, { address: address }) })] }));
229
+ }
230
+ function InlineInfoTooltip({ message }) {
231
+ const [showTooltip, setShowTooltip] = useState(false);
232
+ return (_jsxs("span", { onBlur: () => setShowTooltip(false), onFocus: () => setShowTooltip(true), onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), style: {
233
+ alignItems: "center",
234
+ color: muted,
235
+ display: "inline-flex",
236
+ lineHeight: 0,
237
+ outline: "none",
238
+ position: "relative",
239
+ }, tabIndex: 0, children: [_jsx(Info, { style: { height: 13, width: 13 } }), showTooltip && (_jsx("span", { role: "tooltip", style: {
240
+ background: "#FFFFFE",
241
+ border: `1px solid ${border}`,
242
+ borderRadius: "8px",
243
+ boxShadow: "0 6px 18px rgba(22,22,21,0.10)",
244
+ color: primary,
245
+ fontFamily,
246
+ fontSize: "13px",
247
+ fontWeight: 500,
248
+ lineHeight: "17px",
249
+ padding: "7px 9px",
250
+ pointerEvents: "none",
251
+ position: "absolute",
252
+ bottom: "calc(100% + 8px)",
253
+ left: "50%",
254
+ transform: "translateX(-50%)",
255
+ whiteSpace: "normal",
256
+ width: "210px",
257
+ zIndex: 10000,
258
+ }, children: message }))] }));
259
+ }
260
+ function MayanPoweredBadge() {
261
+ return (_jsxs("div", { style: {
262
+ alignItems: "center",
263
+ background: "#F3F6FF",
264
+ border: "1px solid #E8EEFF",
265
+ borderRadius: "8px",
266
+ color: brand,
267
+ display: "flex",
268
+ fontFamily,
269
+ fontSize: "12px",
270
+ fontWeight: 500,
271
+ gap: "4px",
272
+ lineHeight: "16px",
273
+ minHeight: "36px",
274
+ padding: "9px 12px",
275
+ width: "100%",
276
+ }, children: [_jsx(Info, { style: { flexShrink: 0, height: 13, width: 13 } }), _jsx("span", { style: { flexShrink: 0 }, children: "This transaction is powered by" }), _jsx("img", { alt: "Mayan", src: "/mayan_logo.svg", style: {
277
+ display: "block",
278
+ height: "20px",
279
+ objectFit: "contain",
280
+ width: "auto",
281
+ } })] }));
282
+ }
283
+ function Row({ title, subtitle, value, secondaryValue, children, }) {
284
+ return (_jsxs("div", { style: {
285
+ borderTop: `1px solid ${border}`,
286
+ display: "flex",
287
+ justifyContent: "space-between",
288
+ padding: "16px 16px",
289
+ }, children: [_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [_jsx("div", { style: {
290
+ color: primary,
291
+ fontFamily,
292
+ fontSize: "14px",
293
+ fontWeight: 600,
294
+ lineHeight: "20px",
295
+ }, children: title }), _jsx("div", { style: {
296
+ color: muted,
297
+ fontFamily,
298
+ fontSize: "12px",
299
+ lineHeight: "15px",
300
+ }, children: subtitle })] }), _jsxs("div", { style: {
301
+ alignItems: "flex-end",
302
+ display: "flex",
303
+ flexDirection: "column",
304
+ gap: "5px",
305
+ textAlign: "right",
306
+ }, children: [_jsx("div", { style: {
307
+ color: primary,
308
+ fontFamily,
309
+ fontSize: "14px",
310
+ fontWeight: 600,
311
+ lineHeight: "18px",
312
+ }, children: value }), secondaryValue ? (_jsx("div", { style: {
313
+ color: muted,
314
+ fontFamily,
315
+ fontSize: "12px",
316
+ lineHeight: "14px",
317
+ }, children: secondaryValue })) : (children)] })] }));
318
+ }
319
+ function AnimatedDetails({ open, children, background = "#F9F9F8", gap = "9px", padding = "12px 14px", }) {
320
+ return (_jsx("div", { "aria-hidden": !open, style: {
321
+ background,
322
+ borderTop: `1px solid ${border}`,
323
+ borderTopWidth: open ? "1px" : 0,
324
+ display: "grid",
325
+ gridTemplateRows: open ? "1fr" : "0fr",
326
+ opacity: open ? 1 : 0,
327
+ overflow: "hidden",
328
+ transition: "grid-template-rows 220ms ease, opacity 180ms ease, border-top-width 220ms ease",
329
+ }, children: _jsx("div", { style: { minHeight: 0, overflow: "hidden" }, children: _jsx("div", { style: {
330
+ display: "flex",
331
+ flexDirection: "column",
332
+ gap,
333
+ padding: open ? padding : "0 16px",
334
+ transition: "padding 220ms ease",
335
+ }, children: children }) }) }));
336
+ }
337
+ export function SwapIntentPreview({ fromTokens, fromToken, toToken, fromAmount, fromAmountUsd, toAmount, toAmountUsd, toAmountTokens, totalFeeUsd, isLoading, isRefreshing, isExecuting, swapType, intentData, mode, opportunity, recipientAddress, activeMode, steps, explorerUrls, onAccept, onTransitionChange, }) {
338
+ const [showSourceDetails, setShowSourceDetails] = useState(false);
339
+ const [showFeeDetails, setShowFeeDetails] = useState(false);
340
+ const [showImpactDetails, setShowImpactDetails] = useState(false);
341
+ const sourceDetailsScrollRef = useRef(null);
342
+ const [transitionTimeoutId, setTransitionTimeoutId] = useState(null);
343
+ const startTransition = () => {
344
+ if (onTransitionChange) {
345
+ onTransitionChange(true);
346
+ }
347
+ if (transitionTimeoutId) {
348
+ clearTimeout(transitionTimeoutId);
349
+ }
350
+ const id = setTimeout(() => {
351
+ if (onTransitionChange) {
352
+ onTransitionChange(false);
353
+ }
354
+ setTransitionTimeoutId(null);
355
+ }, 280);
356
+ setTransitionTimeoutId(id);
357
+ };
358
+ React.useEffect(() => {
359
+ return () => {
360
+ if (transitionTimeoutId) {
361
+ clearTimeout(transitionTimeoutId);
362
+ }
363
+ };
364
+ }, [transitionTimeoutId]);
365
+ const flowMode = mode ?? activeMode ?? "swap";
366
+ const isDepositMode = flowMode === "deposit";
367
+ const isSendMode = flowMode === "send";
368
+ const hasRecipientTransfer = Boolean(recipientAddress) && !isDepositMode;
369
+ const isExactOutDisplayFlow = (isDepositMode || isSendMode) && swapType === "exactOut";
370
+ const shouldShowSwapBuffer = swapType !== "exactIn";
371
+ const intentSources = intentData?.sources ?? [];
372
+ const intentDest = intentData?.destination;
373
+ const normalizedIntentSources = intentSources.map((source) => ({
374
+ ...source,
375
+ token: normalizeIntentToken(source.token, source.chain.id),
376
+ }));
377
+ const normalizedIntentDest = intentDest
378
+ ? {
379
+ ...intentDest,
380
+ token: normalizeIntentToken(intentDest.token, intentDest.chain.id),
381
+ gas: {
382
+ ...intentDest.gas,
383
+ token: normalizeIntentToken(intentDest.gas?.token, intentDest.chain.id),
384
+ },
385
+ }
386
+ : undefined;
387
+ const fallbackSources = fromTokens && fromTokens.length > 0
388
+ ? fromTokens
389
+ : fromToken
390
+ ? [fromToken]
391
+ : [];
392
+ const baseSourceSymbols = normalizedIntentSources.length > 0
393
+ ? unique(normalizedIntentSources.map((source) => source.token.symbol))
394
+ : unique(fallbackSources.map((source) => source.symbol));
395
+ const baseSourceAssetCount = normalizedIntentSources.length ||
396
+ fallbackSources.length ||
397
+ baseSourceSymbols.length;
398
+ const hasResolvedQuote = Boolean(normalizedIntentDest &&
399
+ (normalizedIntentSources.length > 0 || isExactOutDisplayFlow));
400
+ const quoteUnavailable = !isLoading && !hasResolvedQuote;
401
+ const destTokenSymbol = normalizedIntentDest?.token.symbol ||
402
+ toToken?.symbol ||
403
+ opportunity?.tokenSymbol ||
404
+ "-";
405
+ const destChainName = flowMode === "deposit"
406
+ ? opportunity?.title || opportunity?.protocol || "App"
407
+ : getShortChainName(normalizedIntentDest?.chain.id ?? toToken?.chainId, normalizedIntentDest?.chain.name || toToken?.chainName || "");
408
+ const requestedDestinationAmount = isExactOutDisplayFlow
409
+ ? parseDecimal(toAmountTokens ?? toAmount)
410
+ : undefined;
411
+ const quotedDestinationAmount = parseDecimal(normalizedIntentDest?.amount);
412
+ const destinationBalanceAmount = parseDecimal(toToken?.balance);
413
+ const displayOnlyDestinationCoverage = (() => {
414
+ if (!isExactOutDisplayFlow ||
415
+ !requestedDestinationAmount ||
416
+ requestedDestinationAmount.lte(0) ||
417
+ !destinationBalanceAmount ||
418
+ destinationBalanceAmount.lte(0)) {
419
+ return undefined;
420
+ }
421
+ const externallyProducedAmount = normalizedIntentSources.length > 0 &&
422
+ quotedDestinationAmount &&
423
+ quotedDestinationAmount.gt(0)
424
+ ? quotedDestinationAmount
425
+ : new Decimal(0);
426
+ const destinationBalanceAmountNeeded = Decimal.max(requestedDestinationAmount.minus(externallyProducedAmount), 0);
427
+ const coveredAmount = Decimal.min(destinationBalanceAmountNeeded, destinationBalanceAmount);
428
+ return coveredAmount.gt(0) ? coveredAmount : undefined;
429
+ })();
430
+ const displayOnlyDestinationSourceAmount = displayOnlyDestinationCoverage;
431
+ const requestedDestinationUsd = parseDecimal(toAmountUsd);
432
+ const destinationDisplayUsdRate = requestedDestinationAmount &&
433
+ requestedDestinationAmount.gt(0) &&
434
+ requestedDestinationUsd &&
435
+ requestedDestinationUsd.gt(0)
436
+ ? requestedDestinationUsd.div(requestedDestinationAmount)
437
+ : quotedDestinationAmount &&
438
+ quotedDestinationAmount.gt(0) &&
439
+ normalizedIntentDest?.value
440
+ ? (parseDecimal(normalizedIntentDest.value) ?? new Decimal(0)).div(quotedDestinationAmount)
441
+ : undefined;
442
+ const displayOnlyDestinationCoverageUsd = displayOnlyDestinationCoverage &&
443
+ displayOnlyDestinationCoverage.gt(0) &&
444
+ destinationDisplayUsdRate &&
445
+ destinationDisplayUsdRate.gt(0)
446
+ ? displayOnlyDestinationCoverage.mul(destinationDisplayUsdRate)
447
+ : undefined;
448
+ const displayOnlyDestinationSourceUsd = displayOnlyDestinationSourceAmount &&
449
+ displayOnlyDestinationSourceAmount.gt(0) &&
450
+ destinationDisplayUsdRate &&
451
+ destinationDisplayUsdRate.gt(0)
452
+ ? displayOnlyDestinationSourceAmount.mul(destinationDisplayUsdRate)
453
+ : undefined;
454
+ const intentSourceUsdValues = normalizedIntentSources.map((source) => parseDecimal(source.value));
455
+ const intentSourceUsdNumber = normalizedIntentSources.length > 0
456
+ ? intentSourceUsdValues.every((value) => value !== undefined)
457
+ ? intentSourceUsdValues.reduce((sum, value) => sum.plus(value ?? 0), new Decimal(0))
458
+ : parseDecimal(fromAmountUsd)
459
+ : parseDecimal(fromAmountUsd);
460
+ const effectiveSourceUsdNumber = displayOnlyDestinationCoverageUsd !== undefined
461
+ ? (intentSourceUsdNumber ?? new Decimal(0)).plus(displayOnlyDestinationCoverageUsd)
462
+ : intentSourceUsdNumber;
463
+ const destinationUsdNumber = hasResolvedQuote
464
+ ? isExactOutDisplayFlow
465
+ ? (parseDecimal(toAmountUsd) ?? parseDecimal(normalizedIntentDest?.value))
466
+ : (parseDecimal(normalizedIntentDest?.value) ?? parseDecimal(toAmountUsd))
467
+ : undefined;
468
+ const hasFiatQuote = effectiveSourceUsdNumber !== undefined &&
469
+ destinationUsdNumber !== undefined &&
470
+ effectiveSourceUsdNumber.gt(0) &&
471
+ destinationUsdNumber.gt(0);
472
+ const bridgeFees = intentData?.feesAndBuffer?.bridge;
473
+ const bridgeFeeData = bridgeFees && typeof bridgeFees === "object" ? bridgeFees : undefined;
474
+ const bridgeTotalNumber = typeof bridgeFees === "string"
475
+ ? parseDecimal(bridgeFees)
476
+ : parseDecimal(bridgeFeeData?.total);
477
+ const collectionFeeNumber = parseDecimal(bridgeFeeData?.collection);
478
+ const fulfilmentFeeNumber = parseDecimal(bridgeFeeData?.fulfilment);
479
+ const executionGasFeeNumber = parseDecimal(bridgeFeeData?.caGas) ??
480
+ (collectionFeeNumber !== undefined || fulfilmentFeeNumber !== undefined
481
+ ? (collectionFeeNumber ?? new Decimal(0)).plus(fulfilmentFeeNumber ?? new Decimal(0))
482
+ : undefined);
483
+ const protocolFeeNumber = parseDecimal(bridgeFeeData?.protocol);
484
+ const solverFeeNumber = parseDecimal(bridgeFeeData?.solver);
485
+ const gasSuppliedNumber = parseDecimal(bridgeFeeData?.gasSupplied);
486
+ const swapBufferNumber = parseDecimal(intentData?.feesAndBuffer?.buffer);
487
+ const bridgeComponentsTotalNumber = bridgeFeeData
488
+ ? [
489
+ executionGasFeeNumber,
490
+ protocolFeeNumber,
491
+ solverFeeNumber,
492
+ gasSuppliedNumber,
493
+ ].reduce((sum, value) => sum.plus(value ?? new Decimal(0)), new Decimal(0))
494
+ : undefined;
495
+ const explicitFeeNumber = bridgeTotalNumber ??
496
+ (bridgeComponentsTotalNumber && bridgeComponentsTotalNumber.gt(0)
497
+ ? bridgeComponentsTotalNumber
498
+ : undefined) ??
499
+ parseDecimal(totalFeeUsd) ??
500
+ parseDecimal(intentData?.fees?.total);
501
+ const feeNumber = explicitFeeNumber ?? (hasFiatQuote ? new Decimal(0) : undefined);
502
+ const quotedDestinationUsdNumber = parseDecimal(normalizedIntentDest?.value);
503
+ const exactOutPaidUsdNumber = (() => {
504
+ if (!isExactOutDisplayFlow)
505
+ return effectiveSourceUsdNumber;
506
+ const candidates = [
507
+ effectiveSourceUsdNumber,
508
+ requestedDestinationUsd,
509
+ ].filter((value) => Boolean(value && value.gt(0)));
510
+ if (requestedDestinationUsd && requestedDestinationUsd.gt(0)) {
511
+ if (intentSourceUsdNumber &&
512
+ intentSourceUsdNumber.gt(0) &&
513
+ quotedDestinationUsdNumber &&
514
+ quotedDestinationUsdNumber.gt(0)) {
515
+ candidates.push(requestedDestinationUsd.plus(Decimal.max(intentSourceUsdNumber.minus(quotedDestinationUsdNumber), 0)));
516
+ }
517
+ const knownOverhead = (feeNumber ?? new Decimal(0)).plus(swapBufferNumber ?? new Decimal(0));
518
+ if (knownOverhead.gt(0)) {
519
+ candidates.push(requestedDestinationUsd.plus(knownOverhead));
520
+ }
521
+ }
522
+ return candidates.reduce((max, value) => (!max || value.gt(max) ? value : max), undefined);
523
+ })();
524
+ const quoteImpactUsd = hasFiatQuote && feeNumber !== undefined
525
+ ? Decimal.max(effectiveSourceUsdNumber
526
+ .minus(destinationUsdNumber)
527
+ .minus(feeNumber)
528
+ .minus(swapBufferNumber ?? new Decimal(0)), 0)
529
+ : undefined;
530
+ const priceImpactUsd = quoteImpactUsd ?? parseDecimal(intentData?.priceImpactUsd);
531
+ const computedSwapImpactPercent = hasFiatQuote && priceImpactUsd !== undefined
532
+ ? priceImpactUsd.eq(0)
533
+ ? new Decimal(0)
534
+ : effectiveSourceUsdNumber !== undefined &&
535
+ effectiveSourceUsdNumber.gt(0)
536
+ ? priceImpactUsd.neg().div(effectiveSourceUsdNumber).mul(100)
537
+ : undefined
538
+ : undefined;
539
+ const swapImpactPercent = computedSwapImpactPercent ??
540
+ parseDecimal(intentData?.swapImpactPercent) ??
541
+ parseDecimal(intentData?.priceImpactPercent);
542
+ const destinationTokenAmount = isExactOutDisplayFlow && (toAmountTokens || toAmount)
543
+ ? toAmountTokens || toAmount || "0"
544
+ : normalizedIntentDest?.amount || toAmountTokens || toAmount || "0";
545
+ const feeDetailRows = bridgeFeeData
546
+ ? [
547
+ {
548
+ label: "Execution Gas Fee",
549
+ value: executionGasFeeNumber ?? new Decimal(0),
550
+ },
551
+ {
552
+ label: "Protocol Fee",
553
+ value: protocolFeeNumber ?? new Decimal(0),
554
+ },
555
+ {
556
+ label: "Solver Fee",
557
+ value: solverFeeNumber ?? new Decimal(0),
558
+ },
559
+ ...(gasSuppliedNumber && gasSuppliedNumber.gt(0)
560
+ ? [{ label: "Gas Sponsorship", value: gasSuppliedNumber }]
561
+ : []),
562
+ ]
563
+ : feeNumber !== undefined
564
+ ? [{ label: "Network & protocol", value: feeNumber }]
565
+ : [];
566
+ const pendingLabel = isLoading ? "Fetching quote" : "Quote unavailable";
567
+ const pendingValue = isLoading ? "..." : "--";
568
+ const sourceUsd = exactOutPaidUsdNumber !== undefined
569
+ ? `${formatAmount(exactOutPaidUsdNumber)} USD`
570
+ : pendingValue;
571
+ const receiveUsd = hasFiatQuote
572
+ ? `${formatAmount(destinationUsdNumber)} USD`
573
+ : pendingValue;
574
+ const feeUsd = feeNumber !== undefined ? formatUsdAmount(feeNumber) : pendingValue;
575
+ const impactUsd = priceImpactUsd !== undefined
576
+ ? formatUsdDelta(priceImpactUsd)
577
+ : pendingValue;
578
+ const impactPercent = swapImpactPercent !== undefined
579
+ ? `${formatAmount(swapImpactPercent, {
580
+ min: 2,
581
+ max: 2,
582
+ })}%`
583
+ : pendingValue;
584
+ const destinationHeaderAmount = hasResolvedQuote
585
+ ? formatHeaderTokenAmount(destinationTokenAmount)
586
+ : pendingValue;
587
+ const destinationTokenDisplay = hasResolvedQuote
588
+ ? `${formatTokenAmount(destinationTokenAmount)} ${destTokenSymbol}`
589
+ : pendingLabel;
590
+ const destinationSourceKey = [
591
+ normalizedIntentDest?.chain.id ?? toToken?.chainId ?? "",
592
+ (normalizedIntentDest?.token.contractAddress ??
593
+ toToken?.contractAddress ??
594
+ "").toLowerCase(),
595
+ ].join("-");
596
+ const hasDestinationSourceRow = Boolean(destinationSourceKey !== "-" &&
597
+ (normalizedIntentSources.length > 0
598
+ ? normalizedIntentSources.some((source) => {
599
+ const sourceKey = [
600
+ source.chain.id,
601
+ source.token.contractAddress.toLowerCase(),
602
+ ].join("-");
603
+ return sourceKey === destinationSourceKey;
604
+ })
605
+ : fallbackSources.some((source) => {
606
+ const sourceKey = [
607
+ source.chainId ?? "",
608
+ source.contractAddress.toLowerCase(),
609
+ ].join("-");
610
+ return sourceKey === destinationSourceKey;
611
+ })));
612
+ const swapBufferDisplay = swapBufferNumber !== undefined
613
+ ? formatUsdValue(swapBufferNumber)
614
+ : pendingValue;
615
+ const baseSourceDetailRows = normalizedIntentSources.length > 0
616
+ ? normalizedIntentSources.map((source, index) => {
617
+ const fallbackSource = fallbackSources.find((token) => token.chainId === source.chain.id &&
618
+ (token.contractAddress?.toLowerCase() ===
619
+ source.token.contractAddress?.toLowerCase() ||
620
+ token.symbol === source.token.symbol));
621
+ const sourceKey = [
622
+ source.chain.id,
623
+ source.token.contractAddress.toLowerCase(),
624
+ ].join("-");
625
+ const isDestinationSource = sourceKey === destinationSourceKey &&
626
+ displayOnlyDestinationSourceAmount !== undefined;
627
+ const sourceAmountNumber = parseDecimal(source.amount);
628
+ const displaySourceAmount = isDestinationSource && displayOnlyDestinationSourceAmount
629
+ ? (sourceAmountNumber ?? new Decimal(0)).plus(displayOnlyDestinationSourceAmount)
630
+ : sourceAmountNumber;
631
+ const sourceValueNumber = parseDecimal(source.value);
632
+ const displaySourceUsd = isDestinationSource && displayOnlyDestinationSourceUsd
633
+ ? (sourceValueNumber ?? new Decimal(0)).plus(displayOnlyDestinationSourceUsd)
634
+ : sourceValueNumber;
635
+ const tokenAmountValue = displaySourceAmount !== undefined
636
+ ? formatTokenAmount(displaySourceAmount)
637
+ : formatTokenAmount(source.amount);
638
+ return {
639
+ key: `${source.chain.id}-${source.token.contractAddress}-${index}`,
640
+ tokenLogo: source.token.logo || fallbackSource?.logo || "",
641
+ chainLogo: source.chain.logo || fallbackSource?.chainLogo || "",
642
+ symbol: source.token.symbol,
643
+ chainName: getShortChainName(source.chain.id, source.chain.name),
644
+ tokenAmount: `${tokenAmountValue} ${source.token.symbol}`,
645
+ tokenAmountValue,
646
+ usdAmount: displaySourceUsd !== undefined
647
+ ? formatUsdValue(displaySourceUsd)
648
+ : pendingValue,
649
+ index,
650
+ };
651
+ })
652
+ : fallbackSources.map((source, index) => {
653
+ const sourceAmount = source.userAmount ||
654
+ (fallbackSources.length === 1 ? fromAmount : "");
655
+ const sourceKey = [
656
+ source.chainId ?? "",
657
+ source.contractAddress.toLowerCase(),
658
+ ].join("-");
659
+ const isDestinationSource = sourceKey === destinationSourceKey &&
660
+ displayOnlyDestinationSourceAmount !== undefined;
661
+ const sourceAmountNumber = parseDecimal(sourceAmount);
662
+ const displaySourceAmount = isDestinationSource && displayOnlyDestinationSourceAmount
663
+ ? (sourceAmountNumber ?? new Decimal(0)).plus(displayOnlyDestinationSourceAmount)
664
+ : sourceAmountNumber;
665
+ const sourceUsdNumber = source.balanceInFiat && source.balance
666
+ ? toDecimal(source.userAmount || 0).mul(toDecimal(source.balanceInFiat).div(Decimal.max(toDecimal(source.balance), 1)))
667
+ : undefined;
668
+ const displaySourceUsd = isDestinationSource && displayOnlyDestinationSourceUsd
669
+ ? (sourceUsdNumber ?? new Decimal(0)).plus(displayOnlyDestinationSourceUsd)
670
+ : sourceUsdNumber;
671
+ const tokenAmountValue = displaySourceAmount !== undefined
672
+ ? formatTokenAmount(displaySourceAmount)
673
+ : "";
674
+ return {
675
+ key: `${source.chainId ?? "chain"}-${source.contractAddress}-${index}`,
676
+ tokenLogo: source.logo || "",
677
+ chainLogo: source.chainLogo || "",
678
+ symbol: source.symbol,
679
+ chainName: getShortChainName(source.chainId, source.chainName),
680
+ tokenAmount: tokenAmountValue
681
+ ? `${tokenAmountValue} ${source.symbol}`
682
+ : pendingLabel,
683
+ tokenAmountValue,
684
+ usdAmount: displaySourceUsd !== undefined
685
+ ? formatUsdValue(displaySourceUsd)
686
+ : pendingValue,
687
+ index,
688
+ };
689
+ });
690
+ const displayOnlyDestinationSourceRow = displayOnlyDestinationSourceAmount &&
691
+ displayOnlyDestinationSourceAmount.gt(0) &&
692
+ !hasDestinationSourceRow
693
+ ? {
694
+ key: `destination-existing-${normalizedIntentDest?.chain.id ?? toToken?.chainId ?? "chain"}-${normalizedIntentDest?.token.contractAddress ?? toToken?.contractAddress ?? "token"}`,
695
+ tokenLogo: normalizedIntentDest?.token.logo || toToken?.logo || "",
696
+ chainLogo: normalizedIntentDest?.chain.logo || toToken?.chainLogo || "",
697
+ symbol: destTokenSymbol,
698
+ chainName: getShortChainName(normalizedIntentDest?.chain.id ?? toToken?.chainId, normalizedIntentDest?.chain.name || toToken?.chainName || ""),
699
+ tokenAmount: `${formatTokenAmount(displayOnlyDestinationSourceAmount)} ${destTokenSymbol}`,
700
+ tokenAmountValue: formatTokenAmount(displayOnlyDestinationSourceAmount),
701
+ usdAmount: displayOnlyDestinationSourceUsd !== undefined
702
+ ? formatUsdValue(displayOnlyDestinationSourceUsd)
703
+ : pendingValue,
704
+ index: baseSourceDetailRows.length,
705
+ }
706
+ : undefined;
707
+ const sourceDetailRows = sortSourceDetailRowsByUsdDesc(displayOnlyDestinationSourceRow
708
+ ? [...baseSourceDetailRows, displayOnlyDestinationSourceRow]
709
+ : baseSourceDetailRows);
710
+ const sourceSymbols = (() => {
711
+ const symbols = sourceDetailRows.length > 0
712
+ ? sourceDetailRows.map((source) => source.symbol)
713
+ : baseSourceSymbols;
714
+ return destTokenSymbol && symbols.includes(destTokenSymbol)
715
+ ? unique([
716
+ destTokenSymbol,
717
+ ...symbols.filter((symbol) => symbol !== destTokenSymbol),
718
+ ])
719
+ : unique(symbols);
720
+ })();
721
+ const sourceLabel = formatSymbolSummary(sourceSymbols);
722
+ const sourceAssetCount = sourceDetailRows.length || baseSourceAssetCount || sourceSymbols.length;
723
+ const singleSourceHeader = (() => {
724
+ if (displayOnlyDestinationSourceRow)
725
+ return null;
726
+ if (!displayOnlyDestinationSourceRow &&
727
+ normalizedIntentSources.length === 1) {
728
+ const source = normalizedIntentSources[0];
729
+ const sourceRow = baseSourceDetailRows[0];
730
+ return {
731
+ amount: sourceRow?.tokenAmountValue ?? formatHeaderTokenAmount(source.amount),
732
+ chainName: getShortChainName(source.chain.id, source.chain.name),
733
+ symbol: source.token.symbol,
734
+ };
735
+ }
736
+ if (normalizedIntentSources.length === 0 && fallbackSources.length === 1) {
737
+ const source = fallbackSources[0];
738
+ const sourceAmount = source.userAmount || fromAmount;
739
+ if (!sourceAmount)
740
+ return null;
741
+ return {
742
+ amount: baseSourceDetailRows[0]?.tokenAmountValue ??
743
+ formatHeaderTokenAmount(sourceAmount),
744
+ chainName: getShortChainName(source.chainId, source.chainName),
745
+ symbol: source.symbol,
746
+ };
747
+ }
748
+ return null;
749
+ })();
750
+ const sourceHeaderAmount = isExactOutDisplayFlow && exactOutPaidUsdNumber !== undefined
751
+ ? formatAmount(exactOutPaidUsdNumber)
752
+ : singleSourceHeader?.amount ||
753
+ (exactOutPaidUsdNumber !== undefined
754
+ ? formatAmount(exactOutPaidUsdNumber)
755
+ : pendingValue);
756
+ const sourceHeaderUnit = isExactOutDisplayFlow && exactOutPaidUsdNumber !== undefined
757
+ ? "USD"
758
+ : singleSourceHeader?.symbol || "USD";
759
+ const sourceHeaderSubtitle = (() => {
760
+ if (isExactOutDisplayFlow && exactOutPaidUsdNumber !== undefined) {
761
+ const count = sourceAssetCount || 1;
762
+ return `${count} asset${count === 1 ? "" : "s"}`;
763
+ }
764
+ if (singleSourceHeader) {
765
+ return singleSourceHeader.chainName
766
+ ? `on ${singleSourceHeader.chainName}`
767
+ : "";
768
+ }
769
+ const count = sourceAssetCount || 1;
770
+ return `${count} asset${count === 1 ? "" : "s"}`;
771
+ })();
772
+ const shouldScrollSourceDetails = sourceDetailRows.length > 5;
773
+ const progressExplorerUrls = explorerUrls ?? {
774
+ destinationExplorerUrl: null,
775
+ sourceExplorerUrl: null,
776
+ };
777
+ const progressSources = sourceDetailRows.map((source) => ({
778
+ chainLogo: source.chainLogo,
779
+ symbol: source.symbol,
780
+ tokenLogo: source.tokenLogo,
781
+ }));
782
+ const primarySourceForProgress = progressSources[0] ?? {
783
+ chainLogo: fromToken?.chainLogo ?? "",
784
+ symbol: sourceSymbols[0] ?? "",
785
+ tokenLogo: fromToken?.logo ?? "",
786
+ };
787
+ const destinationProgressLogos = {
788
+ chain: normalizedIntentDest?.chain.logo || toToken?.chainLogo || "",
789
+ token: normalizedIntentDest?.token.logo || toToken?.logo || "",
790
+ };
791
+ const ctaLabel = flowMode === "deposit"
792
+ ? "Deposit now"
793
+ : flowMode === "send" || hasRecipientTransfer
794
+ ? "Send now"
795
+ : "Swap now";
796
+ const shouldPulseCta = !isLoading && !isRefreshing && !isExecuting && !quoteUnavailable;
797
+ const shouldShowMayanBadge = intentData?.bridgeProvider === "mayan";
798
+ return (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "10px" }, children: [_jsx("style", { children: `
799
+ @keyframes nexusPreviewCtaPulse {
800
+ 0% {
801
+ background-color: var(--nexus-widget-primary, #1F1F1F);
802
+ box-shadow: 0px 1px 4px 0px #5555550D, 0 0 0 0 rgba(31, 31, 31, 0.18);
803
+ transform: scale(1);
804
+ }
805
+ 58% {
806
+ background-color: var(--nexus-widget-primary, #161615);
807
+ box-shadow: 0px 5px 12px rgba(22, 22, 21, 0.1), 0 0 0 5px rgba(22, 22, 21, 0.05);
808
+ transform: scale(1.009);
809
+ }
810
+ 100% {
811
+ background-color: var(--nexus-widget-primary, #1F1F1F);
812
+ box-shadow: 0px 1px 4px 0px #5555550D, 0 0 0 8px rgba(31, 31, 31, 0);
813
+ transform: scale(1);
814
+ }
815
+ }
816
+ ` }), _jsxs("div", { style: {
817
+ background: "#FFFFFE",
818
+ border: `1px solid ${border}`,
819
+ borderRadius: "9px",
820
+ boxShadow: "0px 1px 12px 0px #5B5B5B0D",
821
+ overflow: "hidden",
822
+ width: "100%",
823
+ }, children: [_jsxs("div", { style: {
824
+ background: "linear-gradient(180deg, #FFFFFE 0%, #EEF5FF 100%)",
825
+ display: "grid",
826
+ gridTemplateColumns: "1fr auto 1fr",
827
+ minHeight: "79px",
828
+ padding: "19px 14px 16px",
829
+ }, children: [_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "5px" }, children: [_jsxs("div", { style: {
830
+ alignItems: "baseline",
831
+ color: primary,
832
+ display: "flex",
833
+ gap: "5px",
834
+ fontFamily,
835
+ fontSize: getFontSize(sourceHeaderAmount, sourceHeaderUnit),
836
+ fontWeight: 600,
837
+ lineHeight: "22px",
838
+ }, children: [sourceHeaderAmount, _jsx("span", { style: { color: muted, fontSize: "9px", fontWeight: 500 }, children: sourceHeaderUnit })] }), _jsx("div", { style: {
839
+ color: muted,
840
+ fontFamily,
841
+ fontSize: "9px",
842
+ lineHeight: "14px",
843
+ }, children: sourceHeaderSubtitle })] }), _jsx("div", { "aria-hidden": "true", style: {
844
+ alignItems: "center",
845
+ display: "flex",
846
+ gap: "5px",
847
+ justifyContent: "center",
848
+ padding: "0 12px",
849
+ }, children: [0, 1, 2, 3, 4].map((index) => (_jsx("span", { style: {
850
+ background: index === 2 ? brand : "#9FC4FF",
851
+ borderRadius: "2px",
852
+ display: "block",
853
+ height: "4px",
854
+ opacity: index === 2 ? 1 : 0.55,
855
+ width: "4px",
856
+ } }, index))) }), _jsxs("div", { style: {
857
+ alignItems: "flex-end",
858
+ display: "flex",
859
+ flexDirection: "column",
860
+ gap: "5px",
861
+ textAlign: "right",
862
+ }, children: [_jsxs("div", { style: {
863
+ alignItems: "baseline",
864
+ color: primary,
865
+ display: "flex",
866
+ gap: "5px",
867
+ fontFamily,
868
+ fontSize: getFontSize(destinationHeaderAmount, destTokenSymbol),
869
+ fontWeight: 600,
870
+ lineHeight: "22px",
871
+ }, children: [destinationHeaderAmount, _jsx("span", { style: { color: muted, fontSize: "9px", fontWeight: 500 }, children: destTokenSymbol })] }), _jsx("div", { style: {
872
+ color: muted,
873
+ fontFamily,
874
+ fontSize: "9px",
875
+ lineHeight: "14px",
876
+ }, children: destChainName ? `on ${destChainName}` : destTokenSymbol })] })] }), singleSourceHeader ? (_jsx(Row, { secondaryValue: `${singleSourceHeader.amount} ${singleSourceHeader.symbol}`, subtitle: singleSourceHeader.chainName
877
+ ? `${singleSourceHeader.symbol} on ${singleSourceHeader.chainName}`
878
+ : singleSourceHeader.symbol, title: isDepositMode || isSendMode ? "Paying With" : "You Swap", value: sourceUsd })) : (_jsx(Row, { subtitle: sourceLabel, title: isDepositMode || isSendMode ? "Paying With" : "You Swap", value: sourceUsd, children: _jsx(DetailToggle, { expanded: showSourceDetails, onClick: () => {
879
+ startTransition();
880
+ setShowSourceDetails((value) => !value);
881
+ } }) })), !singleSourceHeader && (_jsx(AnimatedDetails, { open: showSourceDetails, children: sourceDetailRows.length > 0 ? (_jsxs("div", { style: {
882
+ position: "relative",
883
+ }, children: [_jsx("div", { ref: sourceDetailsScrollRef, style: {
884
+ display: "flex",
885
+ flexDirection: "column",
886
+ gap: "0",
887
+ maxHeight: shouldScrollSourceDetails ? "156px" : undefined,
888
+ overflowY: shouldScrollSourceDetails ? "auto" : undefined,
889
+ paddingRight: shouldScrollSourceDetails ? "8px" : undefined,
890
+ scrollbarColor: shouldScrollSourceDetails
891
+ ? "#C8C8C7 transparent"
892
+ : undefined,
893
+ scrollbarWidth: shouldScrollSourceDetails
894
+ ? "thin"
895
+ : undefined,
896
+ }, children: sourceDetailRows.map((source) => (_jsxs("div", { style: {
897
+ alignItems: "center",
898
+ display: "flex",
899
+ gap: "9px",
900
+ justifyContent: "space-between",
901
+ minHeight: "47px",
902
+ padding: "6px 0",
903
+ }, children: [_jsxs("div", { style: {
904
+ alignItems: "center",
905
+ display: "flex",
906
+ gap: "9px",
907
+ minWidth: 0,
908
+ }, children: [_jsxs("div", { style: {
909
+ flexShrink: 0,
910
+ height: "23px",
911
+ position: "relative",
912
+ width: "23px",
913
+ }, children: [_jsx(IntentLogo, { alt: source.symbol, fontSize: 11, label: source.symbol, size: 23, src: source.tokenLogo }), source.chainLogo && (_jsx(IntentLogo, { alt: source.chainName, fontSize: 5, label: source.chainName, outline: "1px solid #FFFFFE", size: 11, src: source.chainLogo, style: {
914
+ bottom: -2,
915
+ position: "absolute",
916
+ right: -2,
917
+ } }))] }), _jsxs("div", { style: {
918
+ display: "flex",
919
+ flexDirection: "column",
920
+ gap: "3px",
921
+ minWidth: 0,
922
+ }, children: [_jsx("span", { style: {
923
+ color: primary,
924
+ fontFamily,
925
+ fontSize: "13px",
926
+ fontWeight: 600,
927
+ lineHeight: "16px",
928
+ }, children: source.symbol }), _jsxs("span", { style: {
929
+ color: muted,
930
+ fontFamily,
931
+ fontSize: "12px",
932
+ lineHeight: "16px",
933
+ overflow: "hidden",
934
+ textOverflow: "ellipsis",
935
+ whiteSpace: "nowrap",
936
+ }, children: ["on ", source.chainName || "Unknown chain"] })] })] }), _jsxs("div", { style: {
937
+ alignItems: "flex-end",
938
+ display: "flex",
939
+ flexDirection: "column",
940
+ flexShrink: 0,
941
+ gap: "3px",
942
+ textAlign: "right",
943
+ }, children: [_jsx("span", { style: {
944
+ color: primary,
945
+ fontFamily,
946
+ fontSize: "12px",
947
+ }, children: source.tokenAmount }), !isExactOutDisplayFlow && (_jsx("span", { style: {
948
+ color: muted,
949
+ fontFamily,
950
+ fontSize: "12px",
951
+ }, children: source.usdAmount }))] })] }, source.key))) }), shouldScrollSourceDetails && (_jsx("button", { "aria-label": "Scroll source assets", onClick: () => {
952
+ sourceDetailsScrollRef.current?.scrollBy({
953
+ behavior: "smooth",
954
+ top: 54,
955
+ });
956
+ }, style: {
957
+ alignItems: "center",
958
+ background: "#FFFFFE",
959
+ border: `1px solid ${border}`,
960
+ borderRadius: "999px",
961
+ boxShadow: "0 2px 8px rgba(22,22,21,0.08)",
962
+ bottom: "4px",
963
+ cursor: "pointer",
964
+ display: "flex",
965
+ height: "20px",
966
+ justifyContent: "center",
967
+ left: "50%",
968
+ padding: 0,
969
+ position: "absolute",
970
+ transform: "translateX(-50%)",
971
+ width: "20px",
972
+ }, type: "button", children: _jsx(ChevronDown, { style: { color: muted, height: 12, width: 12 } }) }))] })) : (_jsx("div", { style: {
973
+ alignItems: "center",
974
+ display: "flex",
975
+ justifyContent: "space-between",
976
+ }, children: _jsx("span", { style: { color: muted, fontFamily, fontSize: "12px" }, children: pendingLabel }) })) })), _jsx(Row, { secondaryValue: destinationTokenDisplay, subtitle: destChainName
977
+ ? `${destTokenSymbol} on ${destChainName}`
978
+ : destTokenSymbol, title: isDepositMode
979
+ ? "You Deposit"
980
+ : isSendMode
981
+ ? "You Send"
982
+ : "You Receive", value: receiveUsd }), hasRecipientTransfer && recipientAddress && (_jsx(RecipientRow, { address: recipientAddress })), _jsx(Row, { subtitle: "Network & protocol", title: "Total Fees", value: feeUsd, children: _jsx(DetailToggle, { expanded: showFeeDetails, onClick: () => {
983
+ startTransition();
984
+ setShowFeeDetails((value) => !value);
985
+ } }) }), _jsx(AnimatedDetails, { open: showFeeDetails, children: feeDetailRows.length > 0 ? (feeDetailRows.map((row) => (_jsxs("div", { style: {
986
+ alignItems: "center",
987
+ display: "flex",
988
+ justifyContent: "space-between",
989
+ }, children: [_jsx("span", { style: { color: muted, fontFamily, fontSize: "12px" }, children: row.label }), _jsx("span", { style: { color: primary, fontFamily, fontSize: "12px" }, children: formatUsdValue(row.value) })] }, row.label)))) : (_jsxs("div", { style: {
990
+ alignItems: "center",
991
+ display: "flex",
992
+ justifyContent: "space-between",
993
+ }, children: [_jsx("span", { style: { color: muted, fontFamily, fontSize: "12px" }, children: "Network & protocol" }), _jsx("span", { style: { color: primary, fontFamily, fontSize: "12px" }, children: pendingValue })] })) }), _jsx(Row, { subtitle: `${destTokenSymbol} · estimated`, title: "Price Impact", value: impactUsd, children: _jsx(DetailToggle, { expanded: showImpactDetails, onClick: () => {
994
+ startTransition();
995
+ setShowImpactDetails((value) => !value);
996
+ } }) }), _jsxs(AnimatedDetails, { background: "#FAFAF9", gap: "12px", open: showImpactDetails, padding: "13px 14px", children: [_jsxs("div", { style: {
997
+ alignItems: "center",
998
+ display: "flex",
999
+ justifyContent: "space-between",
1000
+ }, children: [_jsx("span", { style: { color: muted, fontFamily, fontSize: "12px" }, children: "Swap Impact" }), _jsx("span", { style: {
1001
+ color: hasFiatQuote &&
1002
+ swapImpactPercent !== undefined &&
1003
+ swapImpactPercent.gte(0)
1004
+ ? "#168A47"
1005
+ : primary,
1006
+ fontFamily,
1007
+ fontSize: "12px",
1008
+ }, children: impactPercent })] }), _jsxs("div", { style: {
1009
+ alignItems: "center",
1010
+ display: "flex",
1011
+ justifyContent: "space-between",
1012
+ }, children: [_jsx("span", { style: { color: muted, fontFamily, fontSize: "12px" }, children: "Max. Slippage" }), _jsx("span", { style: { color: primary, fontFamily, fontSize: "12px" }, children: "Auto" })] })] }), shouldShowSwapBuffer && (_jsx(Row, { subtitle: "Excess funds are refunded", title: _jsxs("span", { style: {
1013
+ alignItems: "center",
1014
+ display: "inline-flex",
1015
+ gap: "6px",
1016
+ }, children: ["Swap Buffer", _jsx(InlineInfoTooltip, { message: "Temporary buffer collected to ensure swaps succeed. Excess funds are refunded." })] }), value: swapBufferDisplay }))] }), isExecuting && steps && steps.length > 0 && (_jsx("div", { style: {
1017
+ background: "#FFFFFE",
1018
+ border: `1px solid ${border}`,
1019
+ borderRadius: "9px",
1020
+ boxShadow: "0px 1px 12px 0px #5B5B5B0D",
1021
+ padding: "11px 13px",
1022
+ width: "100%",
1023
+ }, children: _jsx(TransactionProgress, { depositOpportunityName: isDepositMode
1024
+ ? opportunity?.title || opportunity?.protocol
1025
+ : undefined, destinationLogos: destinationProgressLogos, destinationSymbol: destTokenSymbol, explorerUrls: progressExplorerUrls, hasMultipleSources: progressSources.length > 1, isTransferMode: hasRecipientTransfer, sourceLogos: {
1026
+ chain: primarySourceForProgress.chainLogo,
1027
+ token: primarySourceForProgress.tokenLogo,
1028
+ }, sourceSymbol: primarySourceForProgress.symbol, sources: progressSources.length > 1 ? progressSources : undefined, steps: steps }) })), shouldShowMayanBadge && _jsx(MayanPoweredBadge, {}), _jsx(Button, { disabled: isLoading || isRefreshing || isExecuting || quoteUnavailable, onClick: onAccept, style: {
1029
+ animation: shouldPulseCta
1030
+ ? "nexusPreviewCtaPulse 1800ms ease-in-out infinite"
1031
+ : undefined,
1032
+ background: quoteUnavailable
1033
+ ? "#F6F6F6"
1034
+ : "var(--nexus-widget-primary, #1F1F1F)",
1035
+ borderRadius: "10px",
1036
+ boxShadow: "0px 1px 4px 0px #5555550D",
1037
+ color: quoteUnavailable
1038
+ ? "#848483"
1039
+ : "var(--nexus-widget-primary-foreground, #FFFFFE)",
1040
+ fontFamily,
1041
+ fontSize: "14px",
1042
+ fontWeight: 500,
1043
+ height: "42px",
1044
+ transformOrigin: "center",
1045
+ willChange: shouldPulseCta
1046
+ ? "box-shadow, transform, background-color"
1047
+ : undefined,
1048
+ width: "100%",
1049
+ }, children: isExecuting ? (isDepositMode ? ("Depositing...") : isSendMode || hasRecipientTransfer ? ("Sending...") : ("Swapping...")) : isLoading ? (_jsx(Loader2, { className: "h-4 w-4 animate-spin" })) : isRefreshing ? ("Refreshing quotes...") : quoteUnavailable ? (pendingLabel) : (ctaLabel) })] }));
1050
+ }