@rango-dev/widget-embedded 0.17.1-next.2 → 0.17.1-next.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.
Files changed (195) hide show
  1. package/dist/components/ConfirmWalletsModal/ConfirmWallets.helpers.d.ts +1 -3
  2. package/dist/components/ConfirmWalletsModal/ConfirmWallets.helpers.d.ts.map +1 -1
  3. package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.d.ts.map +1 -1
  4. package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.types.d.ts +1 -1
  5. package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.types.d.ts.map +1 -1
  6. package/dist/components/NoResult/NoResult.d.ts +4 -0
  7. package/dist/components/NoResult/NoResult.d.ts.map +1 -0
  8. package/dist/components/NoResult/NoResult.helpers.d.ts +4 -0
  9. package/dist/components/NoResult/NoResult.helpers.d.ts.map +1 -0
  10. package/dist/components/{NoRoutes/NoRoutes.styles.d.ts → NoResult/NoResult.styles.d.ts} +1 -1
  11. package/dist/components/{NoRoutes/NoRoutes.styles.d.ts.map → NoResult/NoResult.styles.d.ts.map} +1 -1
  12. package/dist/components/{NoRoutes/NoRoutes.types.d.ts → NoResult/NoResult.types.d.ts} +3 -3
  13. package/dist/components/NoResult/NoResult.types.d.ts.map +1 -0
  14. package/dist/components/NoResult/index.d.ts +2 -0
  15. package/dist/components/NoResult/index.d.ts.map +1 -0
  16. package/dist/components/Quote/Quote.d.ts +4 -0
  17. package/dist/components/Quote/Quote.d.ts.map +1 -0
  18. package/dist/components/Quote/Quote.styles.d.ts +1429 -0
  19. package/dist/components/Quote/Quote.styles.d.ts.map +1 -0
  20. package/dist/components/Quote/Quote.types.d.ts +22 -0
  21. package/dist/components/Quote/Quote.types.d.ts.map +1 -0
  22. package/dist/components/Quote/QuoteSkeleton.d.ts +4 -0
  23. package/dist/components/Quote/QuoteSkeleton.d.ts.map +1 -0
  24. package/dist/components/Quote/QuoteSkeleton.styles.d.ts +319 -0
  25. package/dist/components/Quote/QuoteSkeleton.styles.d.ts.map +1 -0
  26. package/dist/components/Quote/QuoteSkeleton.types.d.ts +6 -0
  27. package/dist/components/Quote/QuoteSkeleton.types.d.ts.map +1 -0
  28. package/dist/components/Quote/QuoteSummary.d.ts +11 -0
  29. package/dist/components/Quote/QuoteSummary.d.ts.map +1 -0
  30. package/dist/components/Quote/QuoteSummary.styles.d.ts +158 -0
  31. package/dist/components/Quote/QuoteSummary.styles.d.ts.map +1 -0
  32. package/dist/components/Quote/index.d.ts +4 -0
  33. package/dist/components/Quote/index.d.ts.map +1 -0
  34. package/dist/components/QuoteWarningsAndErrors/HighValueLossWarningModal.d.ts +11 -0
  35. package/dist/components/QuoteWarningsAndErrors/HighValueLossWarningModal.d.ts.map +1 -0
  36. package/dist/components/QuoteWarningsAndErrors/QuoteErrorsModalItem.d.ts +4 -0
  37. package/dist/components/QuoteWarningsAndErrors/QuoteErrorsModalItem.d.ts.map +1 -0
  38. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.d.ts +4 -0
  39. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.d.ts.map +1 -0
  40. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers.d.ts +9 -0
  41. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers.d.ts.map +1 -0
  42. package/dist/components/{RouteErrors/RouteErrors.styles.d.ts → QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.d.ts} +1 -1
  43. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.d.ts.map +1 -0
  44. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts +22 -0
  45. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts.map +1 -0
  46. package/dist/components/QuoteWarningsAndErrors/SlippageWariningModal.d.ts +11 -0
  47. package/dist/components/QuoteWarningsAndErrors/SlippageWariningModal.d.ts.map +1 -0
  48. package/dist/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.d.ts +11 -0
  49. package/dist/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.d.ts.map +1 -0
  50. package/dist/components/QuoteWarningsAndErrors/index.d.ts +2 -0
  51. package/dist/components/QuoteWarningsAndErrors/index.d.ts.map +1 -0
  52. package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
  53. package/dist/constants/errors.d.ts +4 -4
  54. package/dist/constants/errors.d.ts.map +1 -1
  55. package/dist/constants/messages.d.ts +1 -1
  56. package/dist/constants/warnings.d.ts +2 -2
  57. package/dist/constants/warnings.d.ts.map +1 -1
  58. package/dist/containers/QuoteInfo/QuoteInfo.d.ts +4 -0
  59. package/dist/containers/QuoteInfo/QuoteInfo.d.ts.map +1 -0
  60. package/dist/containers/QuoteInfo/QuoteInfo.styles.d.ts +472 -0
  61. package/dist/containers/QuoteInfo/QuoteInfo.styles.d.ts.map +1 -0
  62. package/dist/containers/QuoteInfo/QuoteInfo.types.d.ts +17 -0
  63. package/dist/containers/QuoteInfo/QuoteInfo.types.d.ts.map +1 -0
  64. package/dist/containers/QuoteInfo/index.d.ts +2 -0
  65. package/dist/containers/QuoteInfo/index.d.ts.map +1 -0
  66. package/dist/hooks/useConfirmSwap/index.d.ts +2 -0
  67. package/dist/hooks/useConfirmSwap/index.d.ts.map +1 -0
  68. package/dist/hooks/useConfirmSwap/useConfirmSwap.d.ts +3 -0
  69. package/dist/hooks/useConfirmSwap/useConfirmSwap.d.ts.map +1 -0
  70. package/dist/hooks/useConfirmSwap/useConfirmSwap.helpers.d.ts +16 -0
  71. package/dist/hooks/useConfirmSwap/useConfirmSwap.helpers.d.ts.map +1 -0
  72. package/dist/hooks/{useConfirmSwap.d.ts → useConfirmSwap/useConfirmSwap.types.d.ts} +5 -7
  73. package/dist/hooks/useConfirmSwap/useConfirmSwap.types.d.ts.map +1 -0
  74. package/dist/hooks/{useFetchBestRoute.d.ts → useFetchQuote.d.ts} +3 -3
  75. package/dist/hooks/useFetchQuote.d.ts.map +1 -0
  76. package/dist/hooks/usePrepareBlockchainList/usePrepareBlockchainList.helpers.d.ts +2 -2
  77. package/dist/hooks/useSwapInput.d.ts +4 -2
  78. package/dist/hooks/useSwapInput.d.ts.map +1 -1
  79. package/dist/index.js +1 -1
  80. package/dist/index.js.map +4 -4
  81. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  82. package/dist/pages/Home.d.ts.map +1 -1
  83. package/dist/store/app.d.ts +2 -2
  84. package/dist/store/{bestRoute.d.ts → quote.d.ts} +25 -20
  85. package/dist/store/quote.d.ts.map +1 -0
  86. package/dist/types/index.d.ts +1 -1
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/quote.d.ts +82 -0
  89. package/dist/types/quote.d.ts.map +1 -0
  90. package/dist/utils/numbers.d.ts +1 -1
  91. package/dist/utils/numbers.d.ts.map +1 -1
  92. package/dist/utils/{routing.d.ts → quote.d.ts} +16 -12
  93. package/dist/utils/quote.d.ts.map +1 -0
  94. package/dist/utils/settings.d.ts +1 -1
  95. package/dist/utils/swap.d.ts +22 -20
  96. package/dist/utils/swap.d.ts.map +1 -1
  97. package/dist/utils/wallets.d.ts +1 -1
  98. package/package.json +2 -2
  99. package/src/components/BlockchainsSection/BlockchainsSection.tsx +3 -3
  100. package/src/components/ConfirmWalletsModal/ConfirmWallets.helpers.ts +2 -64
  101. package/src/components/ConfirmWalletsModal/ConfirmWalletsModal.tsx +23 -26
  102. package/src/components/ConfirmWalletsModal/ConfirmWalletsModal.types.ts +1 -1
  103. package/src/components/LoadingSwapDetails/LoadingSwapDetails.styles.ts +3 -3
  104. package/src/components/LoadingSwapDetails/LoadingSwapDetails.tsx +6 -6
  105. package/src/components/{NoRoutes/NoRoutes.helper.ts → NoResult/NoResult.helpers.ts} +16 -9
  106. package/src/components/{NoRoutes/NoRoutes.styles.ts → NoResult/NoResult.styles.ts} +2 -0
  107. package/src/components/{NoRoutes/NoRoutes.tsx → NoResult/NoResult.tsx} +7 -12
  108. package/src/components/{NoRoutes/NoRoutes.types.ts → NoResult/NoResult.types.ts} +3 -2
  109. package/src/components/NoResult/index.ts +1 -0
  110. package/src/components/Quote/Quote.styles.ts +212 -0
  111. package/src/components/Quote/Quote.tsx +347 -0
  112. package/src/components/Quote/Quote.types.ts +16 -0
  113. package/src/components/Quote/QuoteSkeleton.styles.ts +110 -0
  114. package/src/components/Quote/QuoteSkeleton.tsx +108 -0
  115. package/src/components/Quote/QuoteSkeleton.types.ts +5 -0
  116. package/src/components/Quote/QuoteSummary.styles.ts +15 -0
  117. package/src/components/Quote/QuoteSummary.tsx +46 -0
  118. package/src/components/Quote/index.ts +3 -0
  119. package/src/components/QuoteWarningsAndErrors/HighValueLossWarningModal.tsx +107 -0
  120. package/src/components/{RouteErrors/RouteErrorsModalItem.tsx → QuoteWarningsAndErrors/QuoteErrorsModalItem.tsx} +3 -3
  121. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers.ts +67 -0
  122. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.tsx +103 -0
  123. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.ts +24 -0
  124. package/src/components/QuoteWarningsAndErrors/SlippageWariningModal.tsx +77 -0
  125. package/src/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.tsx +38 -0
  126. package/src/components/QuoteWarningsAndErrors/index.ts +1 -0
  127. package/src/components/SwapDetails/SwapDetails.Placeholder.tsx +1 -1
  128. package/src/components/SwapDetails/SwapDetails.tsx +13 -16
  129. package/src/components/SwitchFromAndTo.tsx +2 -2
  130. package/src/components/UpdateUrl.tsx +12 -12
  131. package/src/constants/errors.ts +8 -10
  132. package/src/constants/messages.ts +1 -1
  133. package/src/constants/warnings.ts +7 -7
  134. package/src/containers/QuoteInfo/QuoteInfo.styles.ts +15 -0
  135. package/src/containers/QuoteInfo/QuoteInfo.tsx +97 -0
  136. package/src/containers/QuoteInfo/QuoteInfo.types.ts +17 -0
  137. package/src/containers/QuoteInfo/index.ts +1 -0
  138. package/src/hooks/useConfirmSwap/index.ts +1 -0
  139. package/src/hooks/useConfirmSwap/useConfirmSwap.helpers.ts +168 -0
  140. package/src/hooks/useConfirmSwap/useConfirmSwap.ts +136 -0
  141. package/src/hooks/useConfirmSwap/useConfirmSwap.types.ts +19 -0
  142. package/src/hooks/{useFetchBestRoute.ts → useFetchQuote.ts} +3 -3
  143. package/src/hooks/useNavigateBack.ts +3 -3
  144. package/src/hooks/useSwapInput.ts +57 -23
  145. package/src/hooks/useSyncStoresWithConfig.ts +2 -2
  146. package/src/pages/ConfirmSwapPage.tsx +58 -227
  147. package/src/pages/HistoryPage.tsx +1 -1
  148. package/src/pages/Home.tsx +52 -241
  149. package/src/pages/LanguagePage.tsx +1 -1
  150. package/src/pages/LiquiditySourcePage.tsx +1 -1
  151. package/src/pages/SelectBlockchainPage.tsx +3 -3
  152. package/src/pages/SelectSwapItemsPage.tsx +2 -2
  153. package/src/pages/SettingsPage.tsx +1 -1
  154. package/src/pages/ThemePage.tsx +1 -1
  155. package/src/pages/WalletsPage.tsx +1 -1
  156. package/src/store/{bestRoute.ts → quote.ts} +42 -38
  157. package/src/types/index.ts +1 -1
  158. package/src/types/quote.ts +107 -0
  159. package/src/utils/numbers.ts +1 -1
  160. package/src/utils/quote.ts +338 -0
  161. package/src/utils/swap.ts +99 -69
  162. package/src/utils/wallets.ts +2 -2
  163. package/dist/components/NoRoutes/NoRoutes.d.ts +0 -4
  164. package/dist/components/NoRoutes/NoRoutes.d.ts.map +0 -1
  165. package/dist/components/NoRoutes/NoRoutes.helper.d.ts +0 -3
  166. package/dist/components/NoRoutes/NoRoutes.helper.d.ts.map +0 -1
  167. package/dist/components/NoRoutes/NoRoutes.types.d.ts.map +0 -1
  168. package/dist/components/NoRoutes/index.d.ts +0 -2
  169. package/dist/components/NoRoutes/index.d.ts.map +0 -1
  170. package/dist/components/RouteErrors/RouteErrors.d.ts +0 -4
  171. package/dist/components/RouteErrors/RouteErrors.d.ts.map +0 -1
  172. package/dist/components/RouteErrors/RouteErrors.styles.d.ts.map +0 -1
  173. package/dist/components/RouteErrors/RouteErrors.types.d.ts +0 -24
  174. package/dist/components/RouteErrors/RouteErrors.types.d.ts.map +0 -1
  175. package/dist/components/RouteErrors/RouteErrorsModal.d.ts +0 -4
  176. package/dist/components/RouteErrors/RouteErrorsModal.d.ts.map +0 -1
  177. package/dist/components/RouteErrors/RouteErrorsModalItem.d.ts +0 -4
  178. package/dist/components/RouteErrors/RouteErrorsModalItem.d.ts.map +0 -1
  179. package/dist/components/RouteErrors/index.d.ts +0 -2
  180. package/dist/components/RouteErrors/index.d.ts.map +0 -1
  181. package/dist/hooks/useConfirmSwap.d.ts.map +0 -1
  182. package/dist/hooks/useFetchBestRoute.d.ts.map +0 -1
  183. package/dist/store/bestRoute.d.ts.map +0 -1
  184. package/dist/types/routing.d.ts +0 -65
  185. package/dist/types/routing.d.ts.map +0 -1
  186. package/dist/utils/routing.d.ts.map +0 -1
  187. package/src/components/NoRoutes/index.ts +0 -1
  188. package/src/components/RouteErrors/RouteErrors.tsx +0 -79
  189. package/src/components/RouteErrors/RouteErrors.types.ts +0 -29
  190. package/src/components/RouteErrors/RouteErrorsModal.tsx +0 -129
  191. package/src/components/RouteErrors/index.ts +0 -1
  192. package/src/hooks/useConfirmSwap.ts +0 -303
  193. package/src/types/routing.ts +0 -77
  194. package/src/utils/routing.ts +0 -321
  195. /package/src/components/{RouteErrors/RouteErrors.styles.ts → QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.ts} +0 -0
@@ -0,0 +1,347 @@
1
+ import type { QuoteProps } from './Quote.types';
2
+ import type { Step } from '@rango-dev/ui';
3
+ import type { SwapResult } from 'rango-sdk';
4
+
5
+ import { i18n } from '@lingui/core';
6
+ import {
7
+ Alert,
8
+ ChevronDownIcon,
9
+ ChevronRightIcon,
10
+ Divider,
11
+ Image,
12
+ InfoIcon,
13
+ QuoteCost,
14
+ StepDetails,
15
+ TokenAmount,
16
+ Tooltip,
17
+ Typography,
18
+ } from '@rango-dev/ui';
19
+ import React, { useLayoutEffect, useRef, useState } from 'react';
20
+
21
+ import {
22
+ GAS_FEE_MAX_DECIMALS,
23
+ GAS_FEE_MIN_DECIMALS,
24
+ PERCENTAGE_CHANGE_MAX_DECIMALS,
25
+ PERCENTAGE_CHANGE_MIN_DECIMALS,
26
+ TOKEN_AMOUNT_MAX_DECIMALS,
27
+ TOKEN_AMOUNT_MIN_DECIMALS,
28
+ } from '../../constants/routing';
29
+ import {
30
+ FooterAlert,
31
+ FooterStepAlarm,
32
+ } from '../../containers/QuoteInfo/QuoteInfo.styles';
33
+ import { useMetaStore } from '../../store/meta';
34
+ import { QuoteErrorType, QuoteWarningType } from '../../types';
35
+ import {
36
+ numberToString,
37
+ secondsToString,
38
+ totalArrivalTime,
39
+ } from '../../utils/numbers';
40
+ import { getPriceImpact, getPriceImpactLevel } from '../../utils/quote';
41
+ import { getTotalFeeInUsd } from '../../utils/swap';
42
+
43
+ import {
44
+ Chains,
45
+ Content,
46
+ EXPANDABLE_QUOTE_TRANSITION_DURATION,
47
+ FrameIcon,
48
+ HorizontalSeparator,
49
+ IconContainer,
50
+ QuoteContainer,
51
+ SummaryContainer,
52
+ } from './Quote.styles';
53
+ import { QuoteSummary } from './QuoteSummary';
54
+
55
+ export function Quote(props: QuoteProps) {
56
+ const {
57
+ meta: { tokens },
58
+ } = useMetaStore();
59
+ const {
60
+ quote,
61
+ input,
62
+ output,
63
+ error,
64
+ warning,
65
+ type,
66
+ recommended = true,
67
+ } = props;
68
+
69
+ const [expanded, setExpanded] = useState(props.expanded);
70
+ const quoteRef = useRef<HTMLButtonElement | null>(null);
71
+ const totalFee = numberToString(
72
+ getTotalFeeInUsd(quote.result?.swaps ?? [], tokens),
73
+ GAS_FEE_MIN_DECIMALS,
74
+ GAS_FEE_MAX_DECIMALS
75
+ );
76
+ const totalTime = secondsToString(totalArrivalTime(quote.result?.swaps));
77
+
78
+ const priceImpact = getPriceImpact(input.usdValue, output.usdValue ?? null);
79
+ const percentageChange = numberToString(
80
+ String(priceImpact),
81
+ PERCENTAGE_CHANGE_MIN_DECIMALS,
82
+ PERCENTAGE_CHANGE_MAX_DECIMALS
83
+ );
84
+ const priceImpactWarningLevel = getPriceImpactLevel(priceImpact ?? 0);
85
+
86
+ const getQuoteSteps = (swaps: SwapResult[]): Step[] => {
87
+ return swaps.map((swap, index) => {
88
+ let stepState: 'error' | 'warning' | undefined = undefined;
89
+ const stepHasError =
90
+ (error?.type === QuoteErrorType.BRIDGE_LIMIT &&
91
+ error.swap.swapperId === swap.swapperId) ||
92
+ (warning?.type === QuoteWarningType.INSUFFICIENT_SLIPPAGE &&
93
+ warning.recommendedSlippages?.has(index));
94
+ const stepHasWarning =
95
+ warning?.type === QuoteWarningType.INSUFFICIENT_SLIPPAGE &&
96
+ warning.recommendedSlippages?.has(index);
97
+
98
+ if (stepHasError) {
99
+ stepState = 'error';
100
+ } else if (stepHasWarning) {
101
+ stepState = 'warning';
102
+ }
103
+
104
+ return {
105
+ swapper: { displayName: swap.swapperId, image: swap.swapperLogo },
106
+ from: {
107
+ token: { displayName: swap.from.symbol, image: swap.from.logo },
108
+ chain: {
109
+ displayName: swap.from.blockchain,
110
+ image: swap.from.blockchainLogo,
111
+ },
112
+ price: {
113
+ value:
114
+ index === 0
115
+ ? numberToString(
116
+ input.value,
117
+ TOKEN_AMOUNT_MIN_DECIMALS,
118
+ TOKEN_AMOUNT_MAX_DECIMALS
119
+ )
120
+ : swap.fromAmount,
121
+ },
122
+ },
123
+ to: {
124
+ token: { displayName: swap.to.symbol, image: swap.to.logo },
125
+ chain: {
126
+ displayName: swap.to.blockchain,
127
+ image: swap.to.blockchainLogo,
128
+ },
129
+ price: {
130
+ value: swap.toAmount,
131
+ },
132
+ },
133
+ state: stepState,
134
+ alerts:
135
+ stepHasError || stepHasWarning ? (
136
+ <FooterStepAlarm>
137
+ <Alert
138
+ type={stepHasError ? 'error' : 'warning'}
139
+ title={
140
+ error?.type === QuoteErrorType.BRIDGE_LIMIT
141
+ ? error?.recommendation
142
+ : i18n.t('Slippage Error:')
143
+ }
144
+ footer={
145
+ <FooterAlert>
146
+ {error?.type === QuoteErrorType.BRIDGE_LIMIT && (
147
+ <>
148
+ <Typography
149
+ size="xsmall"
150
+ variant="body"
151
+ color="neutral900">
152
+ {error.fromAmountRangeError}
153
+ </Typography>
154
+ <Divider direction="horizontal" size={8} />
155
+ <Typography
156
+ size="xsmall"
157
+ variant="body"
158
+ color="neutral900">
159
+ |
160
+ </Typography>
161
+ <Divider direction="horizontal" size={8} />
162
+ <Typography
163
+ size="xsmall"
164
+ variant="body"
165
+ color="neutral900">
166
+ {i18n.t({
167
+ id: 'Yours: {amount} {symbol}',
168
+ values: {
169
+ amount: numberToString(
170
+ swap.fromAmount,
171
+ TOKEN_AMOUNT_MIN_DECIMALS,
172
+ TOKEN_AMOUNT_MAX_DECIMALS
173
+ ),
174
+ symbol: swap?.from.symbol,
175
+ },
176
+ })}
177
+ </Typography>
178
+ </>
179
+ )}
180
+ {(error?.type === QuoteErrorType.INSUFFICIENT_SLIPPAGE ||
181
+ warning?.type ===
182
+ QuoteWarningType.INSUFFICIENT_SLIPPAGE) && (
183
+ <Typography
184
+ size="xsmall"
185
+ variant="body"
186
+ color="neutral900">
187
+ {i18n.t({
188
+ id: 'min required Slippage: {minRequiredSlippage}',
189
+ values: {
190
+ ...(error?.type ===
191
+ QuoteErrorType.INSUFFICIENT_SLIPPAGE && {
192
+ minRequiredSlippage:
193
+ error.recommendedSlippages?.get(index),
194
+ }),
195
+ ...(warning?.type ===
196
+ QuoteWarningType.INSUFFICIENT_SLIPPAGE && {
197
+ minRequiredSlippage:
198
+ warning.recommendedSlippages?.get(index),
199
+ }),
200
+ },
201
+ })}
202
+ </Typography>
203
+ )}
204
+ </FooterAlert>
205
+ }
206
+ />
207
+ </FooterStepAlarm>
208
+ ) : undefined,
209
+ };
210
+ });
211
+ };
212
+ const steps = getQuoteSteps(quote.result?.swaps ?? []);
213
+ const numberOfSteps = steps.length;
214
+
215
+ useLayoutEffect(() => {
216
+ if (expanded && quoteRef.current) {
217
+ setTimeout(() => {
218
+ quoteRef?.current?.scrollIntoView({ behavior: 'smooth' });
219
+ }, EXPANDABLE_QUOTE_TRANSITION_DURATION);
220
+ }
221
+ }, [expanded]);
222
+
223
+ return (
224
+ <>
225
+ <SummaryContainer
226
+ recommended={recommended}
227
+ listItem={type === 'list-item'}
228
+ basic={type === 'basic'}>
229
+ <div className="summary">
230
+ <QuoteCost fee={totalFee} time={totalTime} steps={numberOfSteps} />
231
+ {type === 'basic' && (
232
+ <div className="basic-info">
233
+ <FrameIcon>
234
+ <InfoIcon size={12} color="gray" />
235
+ </FrameIcon>
236
+ <Typography
237
+ size="small"
238
+ variant="body"
239
+ style={{ letterSpacing: 0.4 }}>
240
+ {`${input.value} ${steps[0].from.token.displayName} = ${
241
+ output.value
242
+ } ${steps[steps.length - 1].to.token.displayName}`}
243
+ </Typography>
244
+ <Typography
245
+ color="$neutral600"
246
+ ml={2}
247
+ size="xsmall"
248
+ variant="body">
249
+ {`($${output.usdValue})`}
250
+ </Typography>
251
+ </div>
252
+ )}
253
+ {type === 'list-item' && (
254
+ <TokenAmount
255
+ type="output"
256
+ direction="vertical"
257
+ price={{ value: output.value, usdValue: output.usdValue }}
258
+ token={{
259
+ displayName: steps[numberOfSteps - 1].to.token.displayName,
260
+ image: steps[numberOfSteps - 1].to.token.image,
261
+ }}
262
+ chain={{ image: steps[numberOfSteps - 1].to.chain.image }}
263
+ percentageChange={percentageChange}
264
+ warningLevel={priceImpactWarningLevel}
265
+ />
266
+ )}
267
+ {type === 'swap-preview' && (
268
+ <>
269
+ <QuoteSummary
270
+ from={steps[0].from}
271
+ to={steps[numberOfSteps - 1].to}
272
+ percentageChange={percentageChange}
273
+ warningLevel={priceImpactWarningLevel}
274
+ />
275
+ <Divider size={4} />
276
+ </>
277
+ )}
278
+ </div>
279
+ <QuoteContainer
280
+ recommended={recommended}
281
+ open={expanded}
282
+ onOpenChange={setExpanded}>
283
+ <Chains
284
+ ref={(ref) => (quoteRef.current = ref)}
285
+ recommended={recommended}
286
+ onClick={setExpanded.bind(null, (prevState) => !prevState)}>
287
+ <div>
288
+ {steps.map((step, index) => {
289
+ const key = `item-${index}`;
290
+ return (
291
+ <React.Fragment key={key}>
292
+ <Tooltip
293
+ container={props.tooltipContainer}
294
+ side="bottom"
295
+ sideOffset={4}
296
+ content={step.from.chain.displayName}>
297
+ <Image src={step.from.chain.image} size={16} />
298
+ </Tooltip>
299
+ {index === numberOfSteps - 1 && (
300
+ <>
301
+ <IconContainer>
302
+ <ChevronRightIcon size={12} color="black" />
303
+ </IconContainer>
304
+ <Tooltip
305
+ container={props.tooltipContainer}
306
+ side="bottom"
307
+ sideOffset={4}
308
+ content={step.to.chain.displayName}>
309
+ <Image src={step.to.chain.image} size={16} />
310
+ </Tooltip>
311
+ </>
312
+ )}
313
+ {index !== numberOfSteps - 1 && (
314
+ <IconContainer>
315
+ <ChevronRightIcon size={12} color="black" />
316
+ </IconContainer>
317
+ )}
318
+ </React.Fragment>
319
+ );
320
+ })}
321
+ </div>
322
+ <IconContainer orientation={expanded ? 'up' : 'down'}>
323
+ <ChevronDownIcon size={12} color="black" />
324
+ </IconContainer>
325
+ </Chains>
326
+ <Content open={expanded}>
327
+ <HorizontalSeparator />
328
+ <div className="steps-details">
329
+ {steps.map((step, index) => {
330
+ const key = `item-${index}`;
331
+ return (
332
+ <StepDetails
333
+ type="quote-details"
334
+ key={key}
335
+ step={step}
336
+ hasSeparator={index !== steps.length - 1}
337
+ state={step.state}
338
+ />
339
+ );
340
+ })}
341
+ </div>
342
+ </Content>
343
+ </QuoteContainer>
344
+ </SummaryContainer>
345
+ </>
346
+ );
347
+ }
@@ -0,0 +1,16 @@
1
+ import type { QuoteError, QuoteWarning } from '../../types';
2
+ import type { BestRouteResponse } from 'rango-sdk';
3
+ import type { ReactNode } from 'react';
4
+
5
+ export type QuoteProps = {
6
+ type: 'basic' | 'list-item' | 'swap-preview';
7
+ error: QuoteError | null;
8
+ warning: QuoteWarning | null;
9
+ recommended: boolean;
10
+ tag?: ReactNode;
11
+ quote: BestRouteResponse;
12
+ input: { value: string; usdValue: string };
13
+ output: { value: string; usdValue?: string };
14
+ expanded?: boolean;
15
+ tooltipContainer?: HTMLElement;
16
+ };
@@ -0,0 +1,110 @@
1
+ import { darkTheme, styled } from '@rango-dev/ui';
2
+
3
+ export const Container = styled('div', {
4
+ $$color: '$colors$neutral100',
5
+ [`.${darkTheme} &`]: {
6
+ $$color: '$colors$neutral300',
7
+ },
8
+ backgroundColor: '$$color',
9
+ borderBottomLeftRadius: '$xm',
10
+ borderBottomRightRadius: '$xm',
11
+ padding: '$15 ',
12
+ '& .cost-and-tag': {
13
+ display: 'flex',
14
+ justifyContent: 'space-between',
15
+ alignItems: 'center',
16
+ height: '22px',
17
+ },
18
+ variants: {
19
+ rounded: {
20
+ true: {
21
+ borderRadius: '$xm',
22
+ },
23
+ },
24
+ },
25
+ '& .cost': {
26
+ display: 'flex',
27
+ },
28
+ '& .basic-summary': {
29
+ padding: '$15 $0 14px $0',
30
+ },
31
+ '& .output': {
32
+ padding: '$6 $0 $15 $0',
33
+ display: 'flex',
34
+ flexDirection: 'column',
35
+ },
36
+ '& .output__token-info': {
37
+ display: 'flex',
38
+ justifyContent: 'start',
39
+ alignItems: 'center',
40
+ paddingBottom: '$5',
41
+ },
42
+ '& .quote-summary': {
43
+ display: 'flex',
44
+ justifyContent: 'space-between',
45
+ alignItems: 'end',
46
+ },
47
+ '& .quote-summary__separator': {
48
+ height: '$28',
49
+ marginLeft: '13px',
50
+ borderLeft: '1px solid $neutral700',
51
+ },
52
+ '& .token-amount': {
53
+ display: 'flex',
54
+ justifyContent: 'space-between',
55
+ },
56
+ '& .token-amount__label': {
57
+ display: 'flex',
58
+ flexDirection: 'column',
59
+ alignItems: 'start',
60
+ },
61
+ '& .chains': {
62
+ paddingTop: '$2',
63
+ },
64
+ '& .swap-preview': {
65
+ padding: '$15 $0 $15 $0',
66
+ },
67
+ '& .steps': {
68
+ paddingLeft: '$8',
69
+ },
70
+ '& .step__title': {
71
+ display: 'flex',
72
+ alignItems: 'center',
73
+ },
74
+ '& .step__content': {
75
+ display: 'flex',
76
+ alignItems: 'start',
77
+ },
78
+ '& .step__tokens': {
79
+ paddingTop: '$5',
80
+ paddingBottom: '$10',
81
+ display: 'flex',
82
+ alignItems: 'center',
83
+ },
84
+ '& .step__token-info': {
85
+ display: 'flex',
86
+ alignItems: 'center',
87
+ },
88
+ '& .step__icon-container': {
89
+ margin: '$0 $2',
90
+ padding: '$4',
91
+ display: 'flex',
92
+ justifyContent: 'center',
93
+ alignItems: 'center',
94
+ },
95
+ });
96
+
97
+ export const StepSeparator = styled('div', {
98
+ borderLeft: '1px dashed black',
99
+ minHeight: ' 64px',
100
+ margin: '0px 11.5px',
101
+ alignSelf: 'stretch',
102
+ variants: {
103
+ hideSeparator: {
104
+ true: {
105
+ minHeight: 'unset',
106
+ height: '0',
107
+ },
108
+ },
109
+ },
110
+ });
@@ -0,0 +1,108 @@
1
+ import type { PropTypes } from './QuoteSkeleton.types';
2
+
3
+ import { ChainToken, Divider, NextIcon, Skeleton } from '@rango-dev/ui';
4
+ import React from 'react';
5
+
6
+ import { Container, StepSeparator } from './QuoteSkeleton.styles';
7
+
8
+ function StepSkeleton(props: { separator?: boolean }) {
9
+ const { separator = true } = props;
10
+ return (
11
+ <>
12
+ <div className="step__title">
13
+ <Skeleton height={22} width={22} variant="circular" />
14
+ <Divider direction="horizontal" size={8} />
15
+ <Skeleton height={15} width={148} variant="rounded" />
16
+ </div>
17
+ <div className="step__content">
18
+ <StepSeparator hideSeparator={!separator} />
19
+ <div className="step__tokens">
20
+ <div className="step__token-info">
21
+ <ChainToken size="small" loading chainImage="" tokenImage="" />
22
+ <Divider direction="horizontal" size={8} />
23
+ <Skeleton height={12} width={76} variant="rounded" />
24
+ </div>
25
+ <div className="step__icon-container">
26
+ <NextIcon color="gray" size={16} />
27
+ </div>
28
+ <div className="step__token-info">
29
+ <ChainToken size="small" loading chainImage="" tokenImage="" />
30
+ <Divider direction="horizontal" size={8} />
31
+ <Skeleton height={12} width={76} variant="rounded" />
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </>
36
+ );
37
+ }
38
+
39
+ export function QuoteSkeleton(props: PropTypes) {
40
+ const { type, expanded, tag = false } = props;
41
+ const quoteSummary = (
42
+ <div className="quote-summary">
43
+ <div className="token-amount">
44
+ <ChainToken loading size="medium" chainImage="" tokenImage="" />
45
+ <Divider size={8} direction="horizontal" />
46
+ <div className="token-amount__label">
47
+ <Skeleton height={10} width={60} variant="rounded" />
48
+ <Divider size={4} />
49
+ <Skeleton height={15} width={148} variant="rounded" />
50
+ </div>
51
+ </div>
52
+ <Skeleton height={12} width={64} variant="rounded" />
53
+ </div>
54
+ );
55
+
56
+ return (
57
+ <Container>
58
+ <div className="cost-and-tag">
59
+ <div className="cost">
60
+ <Skeleton width={60} height={10} variant="rounded" />
61
+ <Divider size={4} direction="horizontal" />
62
+ <Skeleton width={60} height={10} variant="rounded" />
63
+ <Divider size={4} direction="horizontal" />
64
+ <Skeleton width={60} height={10} variant="rounded" />
65
+ </div>
66
+ {tag && <Skeleton height={22} width={100} variant="rounded" />}
67
+ </div>
68
+ {type === 'basic' && (
69
+ <div className="basic-summary">
70
+ <Skeleton height={15} width={148} variant="rounded" />
71
+ </div>
72
+ )}
73
+ {type === 'list-item' && (
74
+ <div className="output">
75
+ <div className="output__token-info">
76
+ <ChainToken loading size="medium" chainImage="" tokenImage="" />
77
+ <Divider direction="horizontal" size={4} />
78
+ <Skeleton height={15} width={150} variant="rounded" />
79
+ </div>
80
+ <Divider size={4} />
81
+ <Skeleton height={10} width={184} variant="rounded" />
82
+ </div>
83
+ )}
84
+ {type === 'swap-preview' && (
85
+ <>
86
+ <Divider size={4} />
87
+ <div className="swap-preview">
88
+ {quoteSummary}
89
+ <div className="quote-summary__separator" />
90
+ {quoteSummary}
91
+ </div>
92
+ </>
93
+ )}
94
+ <div className="chains">
95
+ <Skeleton height={15} width={321} variant="rounded" />
96
+ </div>
97
+
98
+ {expanded && (
99
+ <div className="steps">
100
+ <Divider size={20} />
101
+ <StepSkeleton />
102
+ <StepSkeleton />
103
+ <StepSkeleton separator={false} />
104
+ </div>
105
+ )}
106
+ </Container>
107
+ );
108
+ }
@@ -0,0 +1,5 @@
1
+ export type PropTypes = {
2
+ type: 'basic' | 'list-item' | 'swap-preview';
3
+ expanded?: boolean;
4
+ tag?: boolean;
5
+ };
@@ -0,0 +1,15 @@
1
+ import { styled } from '@rango-dev/ui';
2
+
3
+ export const Container = styled('div', {
4
+ position: 'relative',
5
+ display: 'flex',
6
+ flexDirection: 'column',
7
+ width: '100%',
8
+ '& .separator': {
9
+ height: '14px',
10
+ marginLeft: '14px',
11
+ position: 'absolute',
12
+ borderLeft: '1px solid $foreground',
13
+ top: '42%',
14
+ },
15
+ });
@@ -0,0 +1,46 @@
1
+ import type { PriceImpactWarningLevel, Step } from '@rango-dev/ui';
2
+
3
+ import { TokenAmount } from '@rango-dev/ui';
4
+ import React from 'react';
5
+
6
+ import { Container } from './QuoteSummary.styles';
7
+
8
+ type PropTypes = {
9
+ from: Step['from'];
10
+ to: Step['to'];
11
+ percentageChange?: string | null;
12
+ warningLevel: PriceImpactWarningLevel;
13
+ };
14
+
15
+ export function QuoteSummary(props: PropTypes) {
16
+ const { from, to, percentageChange, warningLevel } = props;
17
+ return (
18
+ <Container>
19
+ <TokenAmount
20
+ direction="horizontal"
21
+ label="Swap input"
22
+ type="input"
23
+ price={{ value: from.price.value, usdValue: from.price.usdValue }}
24
+ token={{
25
+ displayName: from.token.displayName,
26
+ image: from.token.image,
27
+ }}
28
+ chain={{ image: from.chain.image }}
29
+ />
30
+ <div className="separator" />
31
+ <TokenAmount
32
+ direction="horizontal"
33
+ label="Estimated output"
34
+ type="output"
35
+ price={{ value: to.price.value, usdValue: to.price.usdValue }}
36
+ token={{
37
+ displayName: to.token.displayName,
38
+ image: to.token.image,
39
+ }}
40
+ chain={{ image: to.chain.image }}
41
+ percentageChange={percentageChange}
42
+ warningLevel={warningLevel}
43
+ />
44
+ </Container>
45
+ );
46
+ }
@@ -0,0 +1,3 @@
1
+ export { Quote } from './Quote';
2
+ export { QuoteSkeleton } from './QuoteSkeleton';
3
+ export { QuoteSummary } from './QuoteSummary';