@rango-dev/widget-embedded 0.23.1-next.9 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/dist/components/AppRouter.d.ts +1 -6
  2. package/dist/components/AppRouter.d.ts.map +1 -1
  3. package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts +1 -283
  4. package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts.map +1 -1
  5. package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.d.ts.map +1 -1
  6. package/dist/components/HeaderButtons/HeaderButtons.d.ts.map +1 -1
  7. package/dist/components/HeaderButtons/HeaderButtons.styles.d.ts +489 -1
  8. package/dist/components/HeaderButtons/HeaderButtons.styles.d.ts.map +1 -1
  9. package/dist/components/HeaderButtons/InProgressTransactionBadge.d.ts +4 -0
  10. package/dist/components/HeaderButtons/InProgressTransactionBadge.d.ts.map +1 -0
  11. package/dist/components/HeaderButtons/RefreshButton.d.ts.map +1 -1
  12. package/dist/components/HeaderButtons/UnreadNotificationsBadge.d.ts.map +1 -1
  13. package/dist/components/HeaderButtons/WalletButton.d.ts.map +1 -1
  14. package/dist/components/LoadingLiquiditySourceList/LoadingLiquiditySourceList.styles.d.ts +1 -1
  15. package/dist/components/LoadingLiquiditySourceList/LoadingLiquiditySourceList.styles.d.ts.map +1 -1
  16. package/dist/components/NoResult/NoResult.d.ts.map +1 -1
  17. package/dist/components/NoResult/NoResult.helpers.d.ts +8 -0
  18. package/dist/components/NoResult/NoResult.helpers.d.ts.map +1 -1
  19. package/dist/components/NoResult/NoResult.styles.d.ts +167 -1
  20. package/dist/components/NoResult/NoResult.styles.d.ts.map +1 -1
  21. package/dist/components/NoResult/NoResult.types.d.ts +1 -0
  22. package/dist/components/NoResult/NoResult.types.d.ts.map +1 -1
  23. package/dist/components/NotificationContent/NotificationContent.d.ts.map +1 -1
  24. package/dist/components/NotificationContent/NotificationContent.styles.d.ts +165 -0
  25. package/dist/components/NotificationContent/NotificationContent.styles.d.ts.map +1 -1
  26. package/dist/components/Quote/Quote.d.ts.map +1 -1
  27. package/dist/components/Quote/Quote.styles.d.ts.map +1 -1
  28. package/dist/components/Quote/Quote.types.d.ts +1 -0
  29. package/dist/components/Quote/Quote.types.d.ts.map +1 -1
  30. package/dist/components/Quote/QuoteTrigger.d.ts.map +1 -1
  31. package/dist/components/QuoteSkeleton/QuoteSkeleton.styles.d.ts +1 -0
  32. package/dist/components/QuoteSkeleton/QuoteSkeleton.styles.d.ts.map +1 -1
  33. package/dist/components/QuoteSkeleton/QuoteSummarySkeleton.d.ts.map +1 -1
  34. package/dist/components/QuoteSkeleton/StepSkeleton.styles.d.ts +3 -1
  35. package/dist/components/QuoteSkeleton/StepSkeleton.styles.d.ts.map +1 -1
  36. package/dist/components/Quotes/Quotes.d.ts.map +1 -1
  37. package/dist/components/Quotes/Quotes.types.d.ts +1 -0
  38. package/dist/components/Quotes/Quotes.types.d.ts.map +1 -1
  39. package/dist/components/Quotes/SelectStrategy.d.ts.map +1 -1
  40. package/dist/components/Slippage/Slippage.d.ts.map +1 -1
  41. package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
  42. package/dist/components/SwapDetailsModal/SwapDetailsModal.WalletState.d.ts.map +1 -1
  43. package/dist/components/TokenList/TokenList.d.ts.map +1 -1
  44. package/dist/constants/index.d.ts +1 -1
  45. package/dist/constants/index.d.ts.map +1 -1
  46. package/dist/constants/languages.d.ts.map +1 -1
  47. package/dist/constants/quote.d.ts +1 -5
  48. package/dist/constants/quote.d.ts.map +1 -1
  49. package/dist/constants/searchFor.d.ts +7 -0
  50. package/dist/constants/searchFor.d.ts.map +1 -0
  51. package/dist/containers/App/App.d.ts.map +1 -1
  52. package/dist/containers/App/App.styles.d.ts.map +1 -1
  53. package/dist/containers/ExpandedQuotes/ExpandedQuotes.d.ts.map +1 -1
  54. package/dist/containers/ExpandedQuotes/ExpandedQuotes.styles.d.ts +3 -1
  55. package/dist/containers/ExpandedQuotes/ExpandedQuotes.styles.d.ts.map +1 -1
  56. package/dist/containers/Inputs/Inputs.d.ts.map +1 -1
  57. package/dist/containers/Inputs/Inputs.types.d.ts +1 -0
  58. package/dist/containers/Inputs/Inputs.types.d.ts.map +1 -1
  59. package/dist/containers/QuoteInfo/QuoteInfo.d.ts.map +1 -1
  60. package/dist/containers/QuoteInfo/QuoteInfo.types.d.ts +1 -0
  61. package/dist/containers/QuoteInfo/QuoteInfo.types.d.ts.map +1 -1
  62. package/dist/containers/Settings/Lists.d.ts.map +1 -1
  63. package/dist/containers/Wallets/Wallets.d.ts.map +1 -1
  64. package/dist/containers/Wallets/Wallets.types.d.ts +13 -2
  65. package/dist/containers/Wallets/Wallets.types.d.ts.map +1 -1
  66. package/dist/containers/Widget/Widget.d.ts.map +1 -1
  67. package/dist/hooks/useBootstrap/index.d.ts +2 -0
  68. package/dist/hooks/useBootstrap/index.d.ts.map +1 -0
  69. package/dist/hooks/useBootstrap/useBootstrap.d.ts +2 -0
  70. package/dist/hooks/useBootstrap/useBootstrap.d.ts.map +1 -0
  71. package/dist/hooks/useScreenDetect.d.ts +9 -0
  72. package/dist/hooks/useScreenDetect.d.ts.map +1 -0
  73. package/dist/hooks/useSwapInput.d.ts.map +1 -1
  74. package/dist/hooks/useTheme.d.ts.map +1 -1
  75. package/dist/hooks/useWalletList.d.ts.map +1 -1
  76. package/dist/index.js +2 -2
  77. package/dist/index.js.map +4 -4
  78. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  79. package/dist/pages/Home.d.ts.map +1 -1
  80. package/dist/pages/LanguagePage.d.ts.map +1 -1
  81. package/dist/pages/LiquiditySourcePage.d.ts.map +1 -1
  82. package/dist/pages/SelectSwapItemsPage.d.ts.map +1 -1
  83. package/dist/pages/SettingsPage.d.ts.map +1 -1
  84. package/dist/store/AppStore.d.ts +2 -2
  85. package/dist/store/app.d.ts +2 -2
  86. package/dist/store/slices/config.d.ts.map +1 -1
  87. package/dist/store/slices/data.d.ts +3 -1
  88. package/dist/store/slices/data.d.ts.map +1 -1
  89. package/dist/store/slices/settings.d.ts.map +1 -1
  90. package/dist/types/config.d.ts +9 -5
  91. package/dist/types/config.d.ts.map +1 -1
  92. package/dist/utils/colors.d.ts +5 -3
  93. package/dist/utils/colors.d.ts.map +1 -1
  94. package/dist/utils/common.d.ts +4 -0
  95. package/dist/utils/common.d.ts.map +1 -1
  96. package/dist/utils/configs.d.ts +2 -1
  97. package/dist/utils/configs.d.ts.map +1 -1
  98. package/dist/utils/meta.d.ts +1 -0
  99. package/dist/utils/meta.d.ts.map +1 -1
  100. package/dist/utils/swap.d.ts +2 -0
  101. package/dist/utils/swap.d.ts.map +1 -1
  102. package/dist/utils/ui.d.ts +5 -2
  103. package/dist/utils/ui.d.ts.map +1 -1
  104. package/dist/utils/wallets.d.ts +1 -1
  105. package/dist/utils/wallets.d.ts.map +1 -1
  106. package/package.json +7 -6
  107. package/src/components/AppRouter.tsx +1 -29
  108. package/src/components/ConfirmWalletsModal/ConfirmWallets.styles.ts +6 -12
  109. package/src/components/ConfirmWalletsModal/ConfirmWalletsModal.tsx +7 -11
  110. package/src/components/ConfirmWalletsModal/WalletList.tsx +2 -2
  111. package/src/components/HeaderButtons/HeaderButtons.styles.ts +43 -2
  112. package/src/components/HeaderButtons/HeaderButtons.tsx +2 -0
  113. package/src/components/HeaderButtons/InProgressTransactionBadge.tsx +26 -0
  114. package/src/components/HeaderButtons/RefreshButton.tsx +2 -1
  115. package/src/components/HeaderButtons/UnreadNotificationsBadge.tsx +10 -2
  116. package/src/components/HeaderButtons/WalletButton.tsx +26 -6
  117. package/src/components/LoadingLiquiditySourceList/LoadingLiquiditySourceList.styles.ts +1 -1
  118. package/src/components/LoadingLiquiditySourceList/LoadingLiquiditySourceList.tsx +4 -4
  119. package/src/components/NoResult/NoResult.helpers.ts +13 -0
  120. package/src/components/NoResult/NoResult.styles.ts +19 -1
  121. package/src/components/NoResult/NoResult.tsx +27 -16
  122. package/src/components/NoResult/NoResult.types.ts +1 -0
  123. package/src/components/NotificationContent/NotificationContent.styles.ts +14 -1
  124. package/src/components/NotificationContent/NotificationContent.tsx +49 -39
  125. package/src/components/Quote/Quote.styles.ts +13 -14
  126. package/src/components/Quote/Quote.tsx +166 -145
  127. package/src/components/Quote/Quote.types.ts +1 -0
  128. package/src/components/Quote/QuoteTrigger.tsx +19 -14
  129. package/src/components/QuoteSkeleton/QuoteSkeleton.styles.ts +10 -2
  130. package/src/components/QuoteSkeleton/QuoteSkeleton.tsx +2 -2
  131. package/src/components/QuoteSkeleton/QuoteSummarySkeleton.styles.ts +2 -2
  132. package/src/components/QuoteSkeleton/QuoteSummarySkeleton.tsx +5 -4
  133. package/src/components/QuoteSkeleton/StepSkeleton.styles.ts +7 -0
  134. package/src/components/QuoteSkeleton/StepSkeleton.tsx +1 -1
  135. package/src/components/QuoteWarningsAndErrors/HighValueLossWarningModal.tsx +1 -1
  136. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.helpers.ts +3 -3
  137. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.styles.ts +1 -1
  138. package/src/components/Quotes/Quotes.tsx +33 -21
  139. package/src/components/Quotes/Quotes.types.ts +1 -0
  140. package/src/components/Quotes/SelectStrategy.tsx +27 -10
  141. package/src/components/Slippage/Slippage.tsx +11 -13
  142. package/src/components/SwapDetails/SwapDetails.tsx +3 -1
  143. package/src/components/SwapDetailsModal/SwapDetailsModal.WalletState.tsx +5 -1
  144. package/src/components/TokenList/TokenList.tsx +9 -8
  145. package/src/constants/errors.ts +1 -1
  146. package/src/constants/index.ts +1 -1
  147. package/src/constants/languages.ts +27 -1
  148. package/src/constants/quote.ts +1 -24
  149. package/src/constants/searchFor.ts +6 -0
  150. package/src/containers/App/App.styles.ts +0 -4
  151. package/src/containers/App/App.tsx +4 -28
  152. package/src/containers/ExpandedQuotes/ExpandedQuotes.styles.ts +13 -0
  153. package/src/containers/ExpandedQuotes/ExpandedQuotes.tsx +5 -0
  154. package/src/containers/Inputs/Inputs.tsx +2 -3
  155. package/src/containers/Inputs/Inputs.types.ts +1 -0
  156. package/src/containers/QuoteInfo/QuoteInfo.tsx +2 -0
  157. package/src/containers/QuoteInfo/QuoteInfo.types.ts +1 -0
  158. package/src/containers/Settings/Lists.tsx +28 -13
  159. package/src/containers/Wallets/Wallets.tsx +27 -10
  160. package/src/containers/Wallets/Wallets.types.ts +13 -2
  161. package/src/containers/Widget/Widget.tsx +13 -13
  162. package/src/hooks/useBootstrap/index.ts +1 -0
  163. package/src/hooks/useBootstrap/useBootstrap.ts +72 -0
  164. package/src/hooks/useScreenDetect.ts +49 -0
  165. package/src/hooks/useSwapInput.ts +7 -2
  166. package/src/hooks/useTheme.ts +1 -8
  167. package/src/hooks/useWalletList.ts +12 -0
  168. package/src/pages/ConfirmSwapPage.tsx +14 -5
  169. package/src/pages/Home.tsx +29 -7
  170. package/src/pages/LanguagePage.tsx +14 -1
  171. package/src/pages/LiquiditySourcePage.tsx +4 -3
  172. package/src/pages/SelectSwapItemsPage.tsx +2 -7
  173. package/src/pages/SettingsPage.tsx +0 -1
  174. package/src/store/slices/config.ts +3 -2
  175. package/src/store/slices/data.ts +82 -34
  176. package/src/store/slices/settings.ts +10 -4
  177. package/src/types/config.ts +9 -5
  178. package/src/utils/colors.ts +106 -75
  179. package/src/utils/common.ts +181 -0
  180. package/src/utils/configs.ts +12 -1
  181. package/src/utils/meta.ts +21 -0
  182. package/src/utils/swap.ts +12 -5
  183. package/src/utils/ui.ts +7 -5
  184. package/src/utils/wallets.ts +5 -47
  185. package/dist/hooks/useMobileDetect.d.ts +0 -3
  186. package/dist/hooks/useMobileDetect.d.ts.map +0 -1
  187. package/src/hooks/useMobileDetect.ts +0 -21
@@ -29,6 +29,7 @@ import { useNavigate } from 'react-router-dom';
29
29
  import { SlippageTooltipContainer as TooltipContainer } from '../../components/Slippage/Slippage.styles';
30
30
  import { navigationRoutes } from '../../constants/navigationRoutes';
31
31
  import { ThemeModeEnum } from '../../constants/settings';
32
+ import { useLanguage } from '../../hooks/useLanguage';
32
33
  import { useAppStore } from '../../store/AppStore';
33
34
  import { getContainer } from '../../utils/common';
34
35
  import { getUniqueSwappersGroups, isFeatureHidden } from '../../utils/settings';
@@ -50,7 +51,7 @@ const themesList = [
50
51
  },
51
52
  {
52
53
  id: ThemeModeEnum.DARK,
53
- icon: <DarkModeIcon color="black" size={16} />,
54
+ icon: <DarkModeIcon color="black" size={14} />,
54
55
  tooltip: (
55
56
  <Typography size="xsmall" variant="body">
56
57
  {i18n.t('Dark')}
@@ -69,7 +70,7 @@ const themesList = [
69
70
  ];
70
71
 
71
72
  const getThemeIcon = (theme: ThemeMode) => {
72
- const iconProps: SvgIconProps = { color: 'gray', size: 12 };
73
+ const iconProps: SvgIconProps = { color: 'gray', size: 14 };
73
74
 
74
75
  switch (theme) {
75
76
  case 'auto':
@@ -85,6 +86,10 @@ export function SettingsLists() {
85
86
  const navigate = useNavigate();
86
87
  const { theme: themeConfig } = useAppStore().config;
87
88
  const { setTheme, theme } = useAppStore();
89
+ const { activeLanguage, languages } = useLanguage();
90
+ const currentLanguage = languages.find(
91
+ (language) => language.local === activeLanguage
92
+ )?.label;
88
93
 
89
94
  const fetchStatus = useAppStore().fetchStatus;
90
95
  const swappers = useAppStore().swappers();
@@ -104,9 +109,8 @@ export function SettingsLists() {
104
109
  disabledLiquiditySources
105
110
  );
106
111
 
107
- const bridgeSources = supportedUniqueSwappersGroups.filter(
108
- (uniqueItem) =>
109
- uniqueItem.type === 'BRIDGE' || uniqueItem.type === 'AGGREGATOR'
112
+ const bridgeSources = supportedUniqueSwappersGroups.filter((uniqueItem) =>
113
+ ['BRIDGE', 'AGGREGATOR', 'OFF_CHAIN'].includes(uniqueItem.type)
110
114
  );
111
115
 
112
116
  const totalBridgeSources = bridgeSources.length;
@@ -123,7 +127,7 @@ export function SettingsLists() {
123
127
  (uniqueItem) => uniqueItem.selected
124
128
  ).length;
125
129
 
126
- const handleEndItem = (totalSelected: number, total: number) => {
130
+ const handleSwapperEndItem = (totalSelected: number, total: number) => {
127
131
  switch (fetchStatus) {
128
132
  case 'loading':
129
133
  return <Skeleton variant="text" size="medium" width={50} />;
@@ -151,13 +155,13 @@ export function SettingsLists() {
151
155
  ),
152
156
  end: (
153
157
  <>
154
- {handleEndItem(totalSelectedBridgeSources, totalBridgeSources)}
158
+ {handleSwapperEndItem(totalSelectedBridgeSources, totalBridgeSources)}
155
159
  <Divider direction="horizontal" size={8} />
156
160
  <ChevronRightIcon color="black" />
157
161
  </>
158
162
  ),
159
163
  onClick: () => navigate(navigationRoutes.bridges),
160
- start: <BridgeIcon color="gray" size={12} />,
164
+ start: <BridgeIcon color="gray" size={14} />,
161
165
  };
162
166
 
163
167
  const exchangeItem = {
@@ -169,12 +173,15 @@ export function SettingsLists() {
169
173
  ),
170
174
  end: (
171
175
  <>
172
- {handleEndItem(totalSelectedExchangeSources, totalExchangeSources)}
176
+ {handleSwapperEndItem(
177
+ totalSelectedExchangeSources,
178
+ totalExchangeSources
179
+ )}
173
180
  <Divider direction="horizontal" size={8} />
174
181
  <ChevronRightIcon color="gray" />
175
182
  </>
176
183
  ),
177
- start: <ExchangeIcon color="gray" size={12} />,
184
+ start: <ExchangeIcon color="gray" size={14} />,
178
185
  onClick: () => navigate(navigationRoutes.exchanges),
179
186
  };
180
187
 
@@ -185,8 +192,16 @@ export function SettingsLists() {
185
192
  {i18n.t('Language')}
186
193
  </Typography>
187
194
  ),
188
- start: <LanguageIcon color="gray" size={12} />,
189
- end: <ChevronRightIcon color="gray" />,
195
+ start: <LanguageIcon color="gray" size={14} />,
196
+ end: (
197
+ <>
198
+ <Typography variant="body" size="medium">
199
+ {currentLanguage}
200
+ </Typography>
201
+ <Divider direction="horizontal" size={8} />
202
+ <ChevronRightIcon color="gray" />
203
+ </>
204
+ ),
190
205
  onClick: () => navigate(navigationRoutes.languages),
191
206
  };
192
207
 
@@ -215,7 +230,7 @@ export function SettingsLists() {
215
230
  </Tooltip>
216
231
  </>
217
232
  ),
218
- start: <DoneIcon color="gray" size={12} />,
233
+ start: <DoneIcon color="gray" size={14} />,
219
234
  end: <Switch checked={infiniteApprove} />,
220
235
  onClick: toggleInfiniteApprove,
221
236
  };
@@ -1,5 +1,5 @@
1
1
  import type {
2
- OnConnectHandler,
2
+ OnWalletConnectionChange,
3
3
  PropTypes,
4
4
  WidgetContextInterface,
5
5
  } from './Wallets.types';
@@ -10,7 +10,7 @@ import type { PropsWithChildren } from 'react';
10
10
  import { Events, Provider } from '@rango-dev/wallets-react';
11
11
  import { type Network } from '@rango-dev/wallets-shared';
12
12
  import { isEvmBlockchain } from 'rango-sdk';
13
- import React, { createContext, useEffect, useRef } from 'react';
13
+ import React, { createContext, useEffect, useMemo, useRef } from 'react';
14
14
 
15
15
  import { useWalletProviders } from '../../hooks/useWalletProviders';
16
16
  import { AppStoreProvider, useAppStore } from '../../store/AppStore';
@@ -25,6 +25,9 @@ export const WidgetContext = createContext<WidgetContextInterface>({
25
25
  onConnectWallet: () => {
26
26
  return;
27
27
  },
28
+ onDisconnectWallet: () => {
29
+ return;
30
+ },
28
31
  });
29
32
 
30
33
  function Main(props: PropsWithChildren<PropTypes>) {
@@ -36,7 +39,8 @@ function Main(props: PropsWithChildren<PropTypes>) {
36
39
  };
37
40
  const { providers } = useWalletProviders(props.config.wallets, walletOptions);
38
41
  const { connectWallet, disconnectWallet } = useWalletsStore();
39
- const onConnectWalletHandler = useRef<OnConnectHandler>();
42
+ const onConnectWalletHandler = useRef<OnWalletConnectionChange>();
43
+ const onDisconnectWalletHandler = useRef<OnWalletConnectionChange>();
40
44
 
41
45
  useEffect(() => {
42
46
  void fetchMeta().catch(console.log);
@@ -70,6 +74,13 @@ function Main(props: PropsWithChildren<PropTypes>) {
70
74
  }
71
75
  } else {
72
76
  disconnectWallet(type);
77
+ if (!!onDisconnectWalletHandler.current) {
78
+ onDisconnectWalletHandler.current(type);
79
+ } else {
80
+ console.warn(
81
+ `onDisconnectWallet handler hasn't been set. Are you sure?`
82
+ );
83
+ }
73
84
  }
74
85
  }
75
86
  if (event === Events.ACCOUNTS && state.connected) {
@@ -102,14 +113,20 @@ function Main(props: PropsWithChildren<PropTypes>) {
102
113
  };
103
114
  const isActiveTab = useUiStore.use.isActiveTab();
104
115
 
116
+ const handlers = useMemo(
117
+ () => ({
118
+ onConnectWallet: (handler: OnWalletConnectionChange) => {
119
+ onConnectWalletHandler.current = handler;
120
+ },
121
+ onDisconnectWallet: (handler: OnWalletConnectionChange) => {
122
+ onDisconnectWalletHandler.current = handler;
123
+ },
124
+ }),
125
+ []
126
+ );
127
+
105
128
  return (
106
- <WidgetContext.Provider
107
- // eslint-disable-next-line react/jsx-no-constructed-context-values
108
- value={{
109
- onConnectWallet: (handler) => {
110
- onConnectWalletHandler.current = handler;
111
- },
112
- }}>
129
+ <WidgetContext.Provider value={handlers}>
113
130
  <Provider
114
131
  allBlockChains={blockchains}
115
132
  providers={providers}
@@ -1,9 +1,20 @@
1
1
  import type { WidgetConfig } from '../../types';
2
2
  import type { EventHandler } from '@rango-dev/wallets-react';
3
3
 
4
- export type OnConnectHandler = (key: string) => void;
4
+ export type OnWalletConnectionChange = (key: string) => void;
5
5
  export interface WidgetContextInterface {
6
- onConnectWallet(handler: OnConnectHandler): void;
6
+ /**
7
+ * A wallet connection handler, utilized within the wallet provider,
8
+ * is linked to the useBootstrap hook for synchronizing the state of the last connected wallet.
9
+ * It's important not to override this handler in other locations.
10
+ */
11
+ onConnectWallet(handler: OnWalletConnectionChange): void;
12
+ /**
13
+ * A wallet disconnection handler, utilized within the wallet provider,
14
+ * is linked to the useBootstrap hook for synchronizing the state of the last disconnected wallet.
15
+ * It's important not to override this handler in other locations.
16
+ */
17
+ onDisconnectWallet(handler: OnWalletConnectionChange): void;
7
18
  }
8
19
 
9
20
  export interface PropTypes {
@@ -1,25 +1,25 @@
1
1
  import type { WidgetProps } from './Widget.types';
2
2
  import type { PropsWithChildren } from 'react';
3
3
 
4
- import React, { useEffect } from 'react';
4
+ import React from 'react';
5
5
 
6
+ import { AppRouter } from '../../components/AppRouter';
6
7
  import { DEFAULT_CONFIG } from '../../store/slices/config';
7
- import { tabManager } from '../../store/ui';
8
8
  import { Main } from '../App';
9
9
  import { WidgetProvider } from '../WidgetProvider';
10
10
 
11
11
  export function Widget(props: PropsWithChildren<WidgetProps>) {
12
- useEffect(() => {
13
- tabManager.init();
14
- return tabManager.destroy;
15
- }, []);
12
+ const isExternalWalletsEnabled = props.config?.externalWallets;
16
13
 
17
- if (!props.config?.externalWallets) {
18
- return (
19
- <WidgetProvider config={props.config ?? DEFAULT_CONFIG}>
14
+ return (
15
+ <AppRouter>
16
+ {isExternalWalletsEnabled ? (
20
17
  <Main />
21
- </WidgetProvider>
22
- );
23
- }
24
- return <Main />;
18
+ ) : (
19
+ <WidgetProvider config={props.config ?? DEFAULT_CONFIG}>
20
+ <Main />
21
+ </WidgetProvider>
22
+ )}
23
+ </AppRouter>
24
+ );
25
25
  }
@@ -0,0 +1 @@
1
+ export { useBootstrap } from './useBootstrap';
@@ -0,0 +1,72 @@
1
+ import type { WalletType } from '../..';
2
+
3
+ import { useQueueManager } from '@rango-dev/queue-manager-rango-preset';
4
+ import { splitWalletNetwork } from '@rango-dev/wallets-shared';
5
+ import { isEvmBlockchain } from 'rango-sdk';
6
+ import { useContext, useEffect, useState } from 'react';
7
+
8
+ import { useWallets } from '../..';
9
+ import { WidgetContext } from '../../containers/Wallets';
10
+ import { globalFont } from '../../globalStyles';
11
+ import { useAppStore } from '../../store/AppStore';
12
+ import { useNotificationStore } from '../../store/notification';
13
+ import { tabManager } from '../../store/ui';
14
+ import { useFetchApiConfig } from '../useFetchApiConfig';
15
+ import { useForceAutoConnect } from '../useForceAutoConnect';
16
+
17
+ export function useBootstrap() {
18
+ globalFont();
19
+ useForceAutoConnect();
20
+ const blockchains = useAppStore().blockchains();
21
+ const { canSwitchNetworkTo } = useWallets();
22
+ const [lastConnectedWalletWithNetwork, setLastConnectedWalletWithNetwork] =
23
+ useState('');
24
+ const [disconnectedWallet, setDisconnectedWallet] = useState<WalletType>();
25
+ const widgetContext = useContext(WidgetContext);
26
+
27
+ const evmChains = blockchains.filter(isEvmBlockchain);
28
+
29
+ const { fetchApiConfig } = useFetchApiConfig();
30
+
31
+ // At the moment, we only detect the disconnection of EVM wallets.
32
+ useQueueManager({
33
+ lastConnectedWallet: lastConnectedWalletWithNetwork,
34
+ clearDisconnectedWallet: () => {
35
+ setDisconnectedWallet(undefined);
36
+ },
37
+ disconnectedWallet: disconnectedWallet,
38
+ evmChains,
39
+ canSwitchNetworkTo,
40
+ });
41
+
42
+ useEffect(() => {
43
+ tabManager.init();
44
+
45
+ if (!useNotificationStore.persist.hasHydrated()) {
46
+ void useNotificationStore.persist.rehydrate();
47
+ }
48
+
49
+ /**
50
+ * Add handlers to the widget context for connecting and disconnecting wallets.
51
+ * We pass these handlers to the wallet provider to keep track of the last connected and last disconnected wallets.
52
+ * The 'queue-manager' uses these details to spot any changes in the connection status of the required wallet during the swap process.
53
+ *
54
+ * with this approch anyone who use the widget context can override these handlers and causes some bugs happens.
55
+ * it the future we should add a safer soloution like considering array of handlers .
56
+ * https://github.com/rango-exchange/rango-client/pull/630/files#r1518846728
57
+ */
58
+ widgetContext.onConnectWallet(setLastConnectedWalletWithNetwork);
59
+ widgetContext.onDisconnectWallet((walletType) => {
60
+ setDisconnectedWallet(walletType);
61
+ if (
62
+ walletType === splitWalletNetwork(lastConnectedWalletWithNetwork)?.[0]
63
+ ) {
64
+ setLastConnectedWalletWithNetwork('');
65
+ }
66
+ });
67
+
68
+ void fetchApiConfig().catch(console.log);
69
+
70
+ return tabManager.destroy;
71
+ }, []);
72
+ }
@@ -0,0 +1,49 @@
1
+ import { useLayoutEffect, useState } from 'react';
2
+
3
+ /*
4
+ * mobile: screen <= 480
5
+ * tablet: screen > 480 and screen <= 768
6
+ * notebook: screen > 768 & screen <= 1024
7
+ * large: screen > 1024 & screen <= 1200
8
+ * extra large: screen > 1200
9
+ */
10
+
11
+ const MIN_TABLET_WIDTH = 480;
12
+ const MIN_NOTEBOOK_WIDTH = 768;
13
+ const MIN_LARGE_SCREEN_WIDTH = 1024;
14
+ const MIN_EXTRA_LARGE_SCREEN_WIDTH = 1200;
15
+
16
+ const useScreenDetect = () => {
17
+ const [isMobile, setIsMobile] = useState(false);
18
+ const [isTablet, setIsTablet] = useState(false);
19
+ const [isNotebook, setIsNotebook] = useState(false);
20
+ const [isLargeScreen, setIsLargeScreen] = useState(false);
21
+ const [isExtraLargeScreen, setIsExtraLargeScreen] = useState(false);
22
+
23
+ const handleResize = () => {
24
+ setIsMobile(window.innerWidth <= MIN_TABLET_WIDTH);
25
+ setIsTablet(
26
+ window.innerWidth > MIN_TABLET_WIDTH &&
27
+ window.innerWidth <= MIN_NOTEBOOK_WIDTH
28
+ );
29
+ setIsNotebook(
30
+ window.innerWidth > MIN_NOTEBOOK_WIDTH &&
31
+ window.innerWidth <= MIN_LARGE_SCREEN_WIDTH
32
+ );
33
+ setIsLargeScreen(
34
+ window.innerWidth > MIN_LARGE_SCREEN_WIDTH &&
35
+ window.innerWidth <= MIN_EXTRA_LARGE_SCREEN_WIDTH
36
+ );
37
+ setIsExtraLargeScreen(window.innerWidth > MIN_EXTRA_LARGE_SCREEN_WIDTH);
38
+ };
39
+
40
+ useLayoutEffect(() => {
41
+ handleResize(); // Initial check
42
+ window.addEventListener('resize', handleResize);
43
+ return () => window.removeEventListener('resize', handleResize);
44
+ }, []);
45
+
46
+ return { isMobile, isTablet, isNotebook, isLargeScreen, isExtraLargeScreen };
47
+ };
48
+
49
+ export default useScreenDetect;
@@ -46,7 +46,11 @@ export function useSwapInput({
46
46
  refetchQuote,
47
47
  }: UseSwapInputProps): UseSwapInput {
48
48
  const { fetch: fetchQuote, cancelFetch } = useFetchAllQuotes();
49
- const { enableNewLiquiditySources, features } = useAppStore().config;
49
+ const {
50
+ excludeLiquiditySources: configExcludeLiquiditySources,
51
+ features,
52
+ enableCentralizedSwappers,
53
+ } = useAppStore().config;
50
54
  const connectedWallets = useWalletsStore.use.connectedWallets();
51
55
 
52
56
  const tokens = useAppStore().tokens();
@@ -118,6 +122,7 @@ export function useSwapInput({
118
122
  affiliateRef,
119
123
  affiliatePercent,
120
124
  affiliateWallets,
125
+ enableCentralizedSwappers,
121
126
  });
122
127
  if (isFeatureEnabled('experimentalRoute', features)) {
123
128
  requestBody.experimental = true;
@@ -223,7 +228,7 @@ export function useSwapInput({
223
228
  toToken?.blockchain,
224
229
  shouldSkipRequest,
225
230
  liquiditySources?.length,
226
- enableNewLiquiditySources,
231
+ configExcludeLiquiditySources,
227
232
  disabledLiquiditySources.length,
228
233
  userSlippage,
229
234
  affiliateRef,
@@ -21,12 +21,11 @@ export function useTheme(props: WidgetTheme) {
21
21
  fontFamily = DEFAULT_FONT_FAMILY,
22
22
  borderRadius = DEFAULT_PRIMARY_RADIUS,
23
23
  secondaryBorderRadius = DEFAULT_SECONDARY_RADIUS,
24
- mode = 'auto',
25
24
  } = props;
26
25
 
27
26
  const [OSTheme, setOSTheme] = useState('light');
28
27
 
29
- const { setTheme, theme } = useAppStore();
28
+ const { theme } = useAppStore();
30
29
 
31
30
  const { dark, light } = customizedThemeTokens(colors);
32
31
 
@@ -81,12 +80,6 @@ export function useTheme(props: WidgetTheme) {
81
80
  };
82
81
  }, []);
83
82
 
84
- useEffect(() => {
85
- if (mode !== 'auto') {
86
- setTheme(mode);
87
- }
88
- }, [mode]);
89
-
90
83
  const getActiveTheme = () => {
91
84
  const lightClassNames = lightThemeClasses.join(' ');
92
85
  const darkClassNames = darkThemeClasses.join(' ');
@@ -109,6 +109,18 @@ export function useWalletList(params: Params) {
109
109
  * but we have ethereum injected
110
110
  */
111
111
  const shouldShowDefaultInjectedWallet = (wallets: WalletInfo[]) => {
112
+ // don't show default injected wallet when it's not installed
113
+ const defaultWallet = wallets.find(
114
+ (wallet) => wallet.type === WalletTypes.DEFAULT
115
+ );
116
+ if (!defaultWallet || defaultWallet.state === WalletState.NOT_INSTALLED) {
117
+ return false;
118
+ }
119
+
120
+ /*
121
+ * if we have another evm wallet installed (except wallet connect),
122
+ * there is no need to show default injected wallet anymore
123
+ */
112
124
  const isEvmWalletInstalledExceptDefault = wallets.filter(
113
125
  (wallet) =>
114
126
  wallet.state != WalletState.NOT_INSTALLED &&
@@ -87,6 +87,7 @@ export function ConfirmSwapPage() {
87
87
  const { connectedWallets } = useWalletsStore();
88
88
  const showWalletsOnInit = !quoteWalletsConfirmed;
89
89
  const [showWallets, setShowWallets] = useState(false);
90
+ const [isConfirming, setIsConfirming] = useState(false);
90
91
  const { isActiveTab } = useUiStore();
91
92
  const disabledLiquiditySources = useAppStore().getDisabledLiquiditySources();
92
93
  const prevDisabledLiquiditySources = useRef(disabledLiquiditySources);
@@ -137,7 +138,9 @@ export function ConfirmSwapPage() {
137
138
  };
138
139
 
139
140
  const onConfirm = async () => {
141
+ setIsConfirming(true);
140
142
  await addNewSwap();
143
+ setIsConfirming(false);
141
144
  };
142
145
 
143
146
  const onStartConfirmSwap = async () => {
@@ -326,7 +329,7 @@ export function ConfirmSwapPage() {
326
329
  type="primary"
327
330
  size="large"
328
331
  fullWidth
329
- loading={fetchingConfirmationQuote}
332
+ loading={fetchingConfirmationQuote || isConfirming}
330
333
  disabled={!!confirmSwapResult.error || !isActiveTab}
331
334
  onClick={onStartConfirmSwap}>
332
335
  {i18n.t('Start Swap')}
@@ -336,7 +339,8 @@ export function ConfirmSwapPage() {
336
339
  variant="contained"
337
340
  type="primary"
338
341
  size="large"
339
- loading={fetchingConfirmationQuote}
342
+ loading={fetchingConfirmationQuote || isConfirming}
343
+ disabled={!isActiveTab}
340
344
  onClick={setShowWallets.bind(null, true)}>
341
345
  <WalletIcon size={24} />
342
346
  </IconButton>
@@ -371,14 +375,19 @@ export function ConfirmSwapPage() {
371
375
  </div>
372
376
  <Divider size="12" />
373
377
 
374
- {joinList(alerts, <Divider size={10} />)}
378
+ {joinList(
379
+ alerts.map((alert, index) => ({
380
+ element: alert,
381
+ key: `alert-${index}`,
382
+ })),
383
+ <Divider size={10} />
384
+ )}
375
385
  {alerts.length > 0 ? <Divider size={10} /> : null}
376
386
 
377
387
  <QuoteInfo
378
388
  quote={selectedQuote}
379
389
  type="swap-preview"
380
- expanded={true}
381
- selected
390
+ expanded
382
391
  tagHidden
383
392
  error={confirmSwapResult.error}
384
393
  loading={fetchingConfirmationQuote}
@@ -1,3 +1,5 @@
1
+ import type { SelectedQuote } from '../types';
2
+
1
3
  import { i18n } from '@lingui/core';
2
4
  import { Button, Divider, styled, WarningIcon } from '@rango-dev/ui';
3
5
  import React, { useEffect, useState } from 'react';
@@ -10,19 +12,20 @@ import { navigationRoutes } from '../constants/navigationRoutes';
10
12
  import { ExpandedQuotes } from '../containers/ExpandedQuotes';
11
13
  import { Inputs } from '../containers/Inputs';
12
14
  import { QuoteInfo } from '../containers/QuoteInfo';
13
- import useMobileDetect from '../hooks/useMobileDetect';
15
+ import useScreenDetect from '../hooks/useScreenDetect';
14
16
  import { useSwapInput } from '../hooks/useSwapInput';
15
17
  import { useAppStore } from '../store/AppStore';
16
18
  import { useQuoteStore } from '../store/quote';
17
19
  import { useUiStore } from '../store/ui';
18
20
  import { useWalletsStore } from '../store/wallets';
19
- import { getSwapButtonState } from '../utils/swap';
21
+ import { isVariantExpandable } from '../utils/configs';
22
+ import { getSwapButtonState, isTokensIdentical } from '../utils/swap';
20
23
 
21
24
  const MainContainer = styled('div', {
22
25
  display: 'grid',
23
26
  gridTemplateColumns: 'auto auto',
24
27
  alignItems: 'flex-start',
25
- height: 700,
28
+ maxHeight: 700,
26
29
  '& .footer__alert': {
27
30
  paddingTop: '0',
28
31
  },
@@ -46,7 +49,7 @@ export function Home() {
46
49
  updateQuotePartialState,
47
50
  } = useQuoteStore();
48
51
  const [isVisibleExpanded, setIsVisibleExpanded] = useState<boolean>(false);
49
- const isMobile = useMobileDetect();
52
+ const { isLargeScreen, isExtraLargeScreen } = useScreenDetect();
50
53
 
51
54
  const { fetch: fetchQuote, loading } = useSwapInput({ refetchQuote });
52
55
  const { config, fetchStatus: fetchMetaStatus } = useAppStore();
@@ -67,9 +70,20 @@ export function Home() {
67
70
  warning: quoteWarning,
68
71
  needsToWarnEthOnPath,
69
72
  });
70
- const isExpandable = config?.variant === 'expandable' && !isMobile;
73
+
74
+ const isExpandable = isVariantExpandable(
75
+ isLargeScreen,
76
+ isExtraLargeScreen,
77
+ config?.variant
78
+ );
79
+
71
80
  const hasInputs =
72
- !!inputAmount && !!fromToken && !!toToken && inputAmount !== '0';
81
+ !!inputAmount &&
82
+ !!fromToken &&
83
+ !!toToken &&
84
+ inputAmount !== '0' &&
85
+ !isTokensIdentical(fromToken, toToken);
86
+
73
87
  const fetchingQuote = hasInputs && fetchMetaStatus === 'success' && loading;
74
88
 
75
89
  const hasValidQuotes =
@@ -102,6 +116,13 @@ export function Home() {
102
116
  }
103
117
  };
104
118
 
119
+ const onClickOnQuote = (quote: SelectedQuote) => {
120
+ if (selectedQuote?.requestId !== quote.requestId) {
121
+ setShowQuoteWarningModal(false);
122
+ setSelectedQuote(quote);
123
+ }
124
+ };
125
+
105
126
  return (
106
127
  <MainContainer>
107
128
  <Layout
@@ -148,6 +169,7 @@ export function Home() {
148
169
  <Inputs
149
170
  fetchingQuote={fetchingQuote}
150
171
  fetchMetaStatus={fetchMetaStatus}
172
+ isExpandable={isExpandable}
151
173
  onClickToken={(mode) => {
152
174
  onHandleNavigation(
153
175
  mode === 'from'
@@ -203,7 +225,7 @@ export function Home() {
203
225
  {isExpandable ? (
204
226
  <ExpandedQuotes
205
227
  loading={fetchingQuote}
206
- onClickOnQuote={(quote) => setSelectedQuote(quote)}
228
+ onClickOnQuote={onClickOnQuote}
207
229
  fetch={fetchQuote}
208
230
  onClickRefresh={onClickRefresh}
209
231
  isVisible={isVisibleExpanded}
@@ -1,5 +1,7 @@
1
1
  import { i18n } from '@lingui/core';
2
2
  import {
3
+ Alert,
4
+ Divider,
3
5
  List,
4
6
  ListItemButton,
5
7
  Radio,
@@ -10,9 +12,11 @@ import React from 'react';
10
12
 
11
13
  import { Layout, PageContainer } from '../components/Layout';
12
14
  import { useLanguage } from '../hooks/useLanguage';
15
+ import { useNavigateBack } from '../hooks/useNavigateBack';
13
16
 
14
17
  export function LanguagePage() {
15
18
  const { activeLanguage, changeLanguage, languages } = useLanguage();
19
+ const navigateBack = useNavigateBack();
16
20
 
17
21
  const languageList = languages.map((languageItem) => {
18
22
  const { local, label, SVGFlag } = languageItem;
@@ -24,7 +28,10 @@ export function LanguagePage() {
24
28
  {label}
25
29
  </Typography>
26
30
  ),
27
- onClick: () => changeLanguage(languageItem.local),
31
+ onClick: () => {
32
+ changeLanguage(languageItem.local);
33
+ navigateBack();
34
+ },
28
35
  end: <Radio value={local} />,
29
36
  start: <SVGFlag />,
30
37
  };
@@ -36,6 +43,12 @@ export function LanguagePage() {
36
43
  title: i18n.t('Language'),
37
44
  }}>
38
45
  <PageContainer>
46
+ <Alert
47
+ type="warning"
48
+ variant="alarm"
49
+ title="Important Notice: Machine translations are in use"
50
+ />
51
+ <Divider size={'8'} />
39
52
  <RadioRoot value={activeLanguage}>
40
53
  <List
41
54
  type={
@@ -44,8 +44,7 @@ export function LiquiditySourcePage({ sourceType }: PropTypes) {
44
44
  validTypes.push('DEX');
45
45
  }
46
46
  if (sourceType === 'Bridges') {
47
- validTypes.push('BRIDGE');
48
- validTypes.push('AGGREGATOR');
47
+ validTypes.push('BRIDGE', 'AGGREGATOR', 'OFF_CHAIN');
49
48
  }
50
49
 
51
50
  const liquiditySources = supportedUniqueSwappersGroups.filter((uniqueItem) =>
@@ -136,11 +135,13 @@ export function LiquiditySourcePage({ sourceType }: PropTypes) {
136
135
  fetchStatus === 'success' && (
137
136
  <LiquiditySourceList disabled={campaignMode}>
138
137
  {filteredList.map((sourceItem) => {
138
+ const { groupTitle, ...otherProps } = sourceItem;
139
+
139
140
  return (
140
141
  <React.Fragment key={sourceItem.id}>
141
142
  <ListItemButton
142
143
  style={{ height: '61px' }}
143
- {...sourceItem}
144
+ {...otherProps}
144
145
  selected={false}
145
146
  hasDivider
146
147
  />