@lifi/widget 3.25.0 → 3.26.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 (217) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/esm/components/AmountInput/AmountInput.js +75 -17
  3. package/dist/esm/components/AmountInput/AmountInput.js.map +1 -1
  4. package/dist/esm/components/AmountInput/AmountInput.style.d.ts +4 -0
  5. package/dist/esm/components/AmountInput/AmountInput.style.js +11 -0
  6. package/dist/esm/components/AmountInput/AmountInput.style.js.map +1 -1
  7. package/dist/esm/components/AmountInput/AmountInputAdornment.style.d.ts +1 -0
  8. package/dist/esm/components/AmountInput/AmountInputAdornment.style.js +64 -5
  9. package/dist/esm/components/AmountInput/AmountInputAdornment.style.js.map +1 -1
  10. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +20 -7
  11. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
  12. package/dist/esm/components/AmountInput/PriceFormHelperText.js +41 -15
  13. package/dist/esm/components/AmountInput/PriceFormHelperText.js.map +1 -1
  14. package/dist/esm/components/AmountInput/PriceFormHelperText.style.d.ts +1 -0
  15. package/dist/esm/components/AmountInput/PriceFormHelperText.style.js +29 -0
  16. package/dist/esm/components/AmountInput/PriceFormHelperText.style.js.map +1 -0
  17. package/dist/esm/components/AppContainer.js +1 -0
  18. package/dist/esm/components/AppContainer.js.map +1 -1
  19. package/dist/esm/components/ChainSelect/useChainSelect.js +2 -4
  20. package/dist/esm/components/ChainSelect/useChainSelect.js.map +1 -1
  21. package/dist/esm/components/Chains/VirtualizedChainList.js +5 -3
  22. package/dist/esm/components/Chains/VirtualizedChainList.js.map +1 -1
  23. package/dist/esm/components/Header/NavigationHeader.js +5 -1
  24. package/dist/esm/components/Header/NavigationHeader.js.map +1 -1
  25. package/dist/esm/components/Routes/RoutesContent.js +3 -2
  26. package/dist/esm/components/Routes/RoutesContent.js.map +1 -1
  27. package/dist/esm/components/Routes/RoutesExpanded.style.js +3 -2
  28. package/dist/esm/components/Routes/RoutesExpanded.style.js.map +1 -1
  29. package/dist/esm/components/SendToWallet/SendToWalletButton.js +1 -1
  30. package/dist/esm/components/SendToWallet/SendToWalletButton.js.map +1 -1
  31. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js +3 -3
  32. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js.map +1 -1
  33. package/dist/esm/components/Step/StepProcess.js +3 -8
  34. package/dist/esm/components/Step/StepProcess.js.map +1 -1
  35. package/dist/esm/components/TokenList/TokenDetailsSheetContent.js +1 -2
  36. package/dist/esm/components/TokenList/TokenDetailsSheetContent.js.map +1 -1
  37. package/dist/esm/components/TokenList/useTokenSelect.js +2 -4
  38. package/dist/esm/components/TokenList/useTokenSelect.js.map +1 -1
  39. package/dist/esm/config/version.d.ts +1 -1
  40. package/dist/esm/config/version.js +1 -1
  41. package/dist/esm/hooks/useFromAmountThreshold.js +2 -2
  42. package/dist/esm/hooks/useFromAmountThreshold.js.map +1 -1
  43. package/dist/esm/hooks/useGasSufficiency.js +3 -3
  44. package/dist/esm/hooks/useGasSufficiency.js.map +1 -1
  45. package/dist/esm/hooks/useNavigateBack.d.ts +1 -1
  46. package/dist/esm/hooks/useNavigateBack.js +8 -2
  47. package/dist/esm/hooks/useNavigateBack.js.map +1 -1
  48. package/dist/esm/hooks/useRouteExecution.js +1 -2
  49. package/dist/esm/hooks/useRouteExecution.js.map +1 -1
  50. package/dist/esm/hooks/useRoutes.js +19 -4
  51. package/dist/esm/hooks/useRoutes.js.map +1 -1
  52. package/dist/esm/hooks/useSettingMonitor.js +1 -2
  53. package/dist/esm/hooks/useSettingMonitor.js.map +1 -1
  54. package/dist/esm/hooks/useTokenAddressBalance.js +4 -1
  55. package/dist/esm/hooks/useTokenAddressBalance.js.map +1 -1
  56. package/dist/esm/hooks/useTokenSearch.js +5 -2
  57. package/dist/esm/hooks/useTokenSearch.js.map +1 -1
  58. package/dist/esm/hooks/useTokens.js +2 -2
  59. package/dist/esm/hooks/useTokens.js.map +1 -1
  60. package/dist/esm/hooks/useTools.js +2 -2
  61. package/dist/esm/hooks/useTools.js.map +1 -1
  62. package/dist/esm/i18n/bn.json +1 -1
  63. package/dist/esm/i18n/de.json +1 -1
  64. package/dist/esm/i18n/en.json +1 -1
  65. package/dist/esm/i18n/es.json +1 -1
  66. package/dist/esm/i18n/fr.json +1 -1
  67. package/dist/esm/i18n/hi.json +1 -1
  68. package/dist/esm/i18n/id.json +1 -1
  69. package/dist/esm/i18n/it.json +1 -1
  70. package/dist/esm/i18n/ja.json +1 -1
  71. package/dist/esm/i18n/ko.json +1 -1
  72. package/dist/esm/i18n/pt.json +1 -1
  73. package/dist/esm/i18n/th.json +1 -1
  74. package/dist/esm/i18n/tr.json +1 -1
  75. package/dist/esm/i18n/uk.json +1 -1
  76. package/dist/esm/i18n/vi.json +1 -1
  77. package/dist/esm/i18n/zh.json +1 -1
  78. package/dist/esm/pages/SelectEnabledToolsPage.js +4 -2
  79. package/dist/esm/pages/SelectEnabledToolsPage.js.map +1 -1
  80. package/dist/esm/pages/SelectTokenPage/SearchTokenInput.js +14 -7
  81. package/dist/esm/pages/SelectTokenPage/SearchTokenInput.js.map +1 -1
  82. package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js +1 -2
  83. package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js.map +1 -1
  84. package/dist/esm/pages/TransactionPage/TransactionPage.js +5 -3
  85. package/dist/esm/pages/TransactionPage/TransactionPage.js.map +1 -1
  86. package/dist/esm/stores/bookmarks/BookmarkStore.d.ts +1 -2
  87. package/dist/esm/stores/bookmarks/BookmarkStore.js +3 -3
  88. package/dist/esm/stores/bookmarks/BookmarkStore.js.map +1 -1
  89. package/dist/esm/stores/bookmarks/useBookmarkActions.js +1 -2
  90. package/dist/esm/stores/bookmarks/useBookmarkActions.js.map +1 -1
  91. package/dist/esm/stores/bookmarks/useBookmarks.js +1 -2
  92. package/dist/esm/stores/bookmarks/useBookmarks.js.map +1 -1
  93. package/dist/esm/stores/chains/ChainOrderStore.d.ts +1 -1
  94. package/dist/esm/stores/chains/ChainOrderStore.js +3 -2
  95. package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
  96. package/dist/esm/stores/chains/useChainOrder.js +1 -2
  97. package/dist/esm/stores/chains/useChainOrder.js.map +1 -1
  98. package/dist/esm/stores/form/useFieldActions.js +1 -2
  99. package/dist/esm/stores/form/useFieldActions.js.map +1 -1
  100. package/dist/esm/stores/form/useFieldValues.js +1 -2
  101. package/dist/esm/stores/form/useFieldValues.js.map +1 -1
  102. package/dist/esm/stores/form/useFormStore.d.ts +1 -2
  103. package/dist/esm/stores/form/useFormStore.js +3 -3
  104. package/dist/esm/stores/form/useFormStore.js.map +1 -1
  105. package/dist/esm/stores/form/useTouchedFields.js +1 -2
  106. package/dist/esm/stores/form/useTouchedFields.js.map +1 -1
  107. package/dist/esm/stores/form/useValidation.js +5 -2
  108. package/dist/esm/stores/form/useValidation.js.map +1 -1
  109. package/dist/esm/stores/form/useValidationActions.js +1 -2
  110. package/dist/esm/stores/form/useValidationActions.js.map +1 -1
  111. package/dist/esm/stores/header/useHeaderStore.d.ts +1 -1
  112. package/dist/esm/stores/header/useHeaderStore.js +3 -2
  113. package/dist/esm/stores/header/useHeaderStore.js.map +1 -1
  114. package/dist/esm/stores/inputMode/useInputModeStore.d.ts +9 -0
  115. package/dist/esm/stores/inputMode/useInputModeStore.js +19 -0
  116. package/dist/esm/stores/inputMode/useInputModeStore.js.map +1 -0
  117. package/dist/esm/stores/routes/RouteExecutionStore.d.ts +1 -1
  118. package/dist/esm/stores/routes/RouteExecutionStore.js +3 -2
  119. package/dist/esm/stores/routes/RouteExecutionStore.js.map +1 -1
  120. package/dist/esm/stores/routes/useExecutingRoutesIds.js +1 -2
  121. package/dist/esm/stores/routes/useExecutingRoutesIds.js.map +1 -1
  122. package/dist/esm/stores/settings/useSendToWalletStore.d.ts +2 -1
  123. package/dist/esm/stores/settings/useSendToWalletStore.js +6 -3
  124. package/dist/esm/stores/settings/useSendToWalletStore.js.map +1 -1
  125. package/dist/esm/stores/settings/useSettings.js +1 -2
  126. package/dist/esm/stores/settings/useSettings.js.map +1 -1
  127. package/dist/esm/stores/settings/useSettingsActions.js +1 -2
  128. package/dist/esm/stores/settings/useSettingsActions.js.map +1 -1
  129. package/dist/esm/stores/settings/useSettingsStore.d.ts +2 -1
  130. package/dist/esm/stores/settings/useSettingsStore.js +5 -1
  131. package/dist/esm/stores/settings/useSettingsStore.js.map +1 -1
  132. package/dist/esm/stores/settings/useSplitSubvariantStore.js +2 -1
  133. package/dist/esm/stores/settings/useSplitSubvariantStore.js.map +1 -1
  134. package/dist/esm/themes/createTheme.js +5 -1
  135. package/dist/esm/themes/createTheme.js.map +1 -1
  136. package/dist/esm/types/widget.d.ts +2 -1
  137. package/dist/esm/types/widget.js +1 -0
  138. package/dist/esm/types/widget.js.map +1 -1
  139. package/dist/esm/utils/format.d.ts +4 -0
  140. package/dist/esm/utils/format.js +26 -0
  141. package/dist/esm/utils/format.js.map +1 -1
  142. package/dist/esm/utils/getPriceImpact.d.ts +2 -2
  143. package/dist/esm/utils/getPriceImpact.js.map +1 -1
  144. package/package.json +12 -12
  145. package/package.json.tmp +14 -14
  146. package/src/components/AmountInput/AmountInput.style.tsx +13 -0
  147. package/src/components/AmountInput/AmountInput.tsx +91 -18
  148. package/src/components/AmountInput/AmountInputAdornment.style.tsx +66 -5
  149. package/src/components/AmountInput/AmountInputEndAdornment.tsx +40 -10
  150. package/src/components/AmountInput/PriceFormHelperText.style.tsx +29 -0
  151. package/src/components/AmountInput/PriceFormHelperText.tsx +63 -19
  152. package/src/components/AppContainer.tsx +1 -0
  153. package/src/components/ChainSelect/useChainSelect.ts +2 -4
  154. package/src/components/Chains/VirtualizedChainList.tsx +5 -6
  155. package/src/components/Header/NavigationHeader.tsx +10 -1
  156. package/src/components/Routes/RoutesContent.tsx +6 -2
  157. package/src/components/Routes/RoutesExpanded.style.ts +3 -2
  158. package/src/components/SendToWallet/SendToWalletButton.tsx +1 -1
  159. package/src/components/SendToWallet/SendToWalletExpandButton.tsx +8 -3
  160. package/src/components/Step/StepProcess.tsx +3 -8
  161. package/src/components/TokenList/TokenDetailsSheetContent.tsx +1 -2
  162. package/src/components/TokenList/useTokenSelect.ts +2 -4
  163. package/src/config/version.ts +1 -1
  164. package/src/hooks/useFromAmountThreshold.ts +6 -2
  165. package/src/hooks/useGasSufficiency.ts +4 -4
  166. package/src/hooks/useNavigateBack.ts +26 -17
  167. package/src/hooks/useRouteExecution.ts +1 -3
  168. package/src/hooks/useRoutes.ts +24 -4
  169. package/src/hooks/useSettingMonitor.ts +7 -11
  170. package/src/hooks/useTokenAddressBalance.ts +6 -1
  171. package/src/hooks/useTokenSearch.ts +5 -2
  172. package/src/hooks/useTokens.ts +2 -2
  173. package/src/hooks/useTools.ts +2 -2
  174. package/src/i18n/bn.json +1 -1
  175. package/src/i18n/de.json +1 -1
  176. package/src/i18n/en.json +1 -1
  177. package/src/i18n/es.json +1 -1
  178. package/src/i18n/fr.json +1 -1
  179. package/src/i18n/hi.json +1 -1
  180. package/src/i18n/id.json +1 -1
  181. package/src/i18n/it.json +1 -1
  182. package/src/i18n/ja.json +1 -1
  183. package/src/i18n/ko.json +1 -1
  184. package/src/i18n/pt.json +1 -1
  185. package/src/i18n/th.json +1 -1
  186. package/src/i18n/tr.json +1 -1
  187. package/src/i18n/uk.json +1 -1
  188. package/src/i18n/vi.json +1 -1
  189. package/src/i18n/zh.json +1 -1
  190. package/src/pages/SelectEnabledToolsPage.tsx +4 -5
  191. package/src/pages/SelectTokenPage/SearchTokenInput.tsx +19 -7
  192. package/src/pages/SettingsPage/BridgeAndExchangeSettings.tsx +1 -2
  193. package/src/pages/TransactionPage/TransactionPage.tsx +17 -9
  194. package/src/stores/bookmarks/BookmarkStore.tsx +3 -6
  195. package/src/stores/bookmarks/useBookmarkActions.ts +9 -13
  196. package/src/stores/bookmarks/useBookmarks.ts +1 -3
  197. package/src/stores/chains/ChainOrderStore.tsx +3 -3
  198. package/src/stores/chains/useChainOrder.ts +1 -5
  199. package/src/stores/form/useFieldActions.ts +10 -14
  200. package/src/stores/form/useFieldValues.ts +1 -3
  201. package/src/stores/form/useFormStore.ts +3 -6
  202. package/src/stores/form/useTouchedFields.ts +1 -2
  203. package/src/stores/form/useValidation.ts +5 -5
  204. package/src/stores/form/useValidationActions.ts +5 -9
  205. package/src/stores/header/useHeaderStore.tsx +3 -5
  206. package/src/stores/inputMode/useInputModeStore.ts +29 -0
  207. package/src/stores/routes/RouteExecutionStore.tsx +3 -3
  208. package/src/stores/routes/useExecutingRoutesIds.ts +14 -17
  209. package/src/stores/settings/useSendToWalletStore.ts +11 -8
  210. package/src/stores/settings/useSettings.ts +8 -11
  211. package/src/stores/settings/useSettingsActions.ts +8 -12
  212. package/src/stores/settings/useSettingsStore.ts +8 -1
  213. package/src/stores/settings/useSplitSubvariantStore.tsx +2 -1
  214. package/src/themes/createTheme.ts +5 -1
  215. package/src/types/widget.ts +1 -0
  216. package/src/utils/format.ts +33 -0
  217. package/src/utils/getPriceImpact.ts +2 -2
@@ -0,0 +1,29 @@
1
+ import { Button, styled } from '@mui/material'
2
+
3
+ export const InputPriceButton = styled(Button)(({ theme, onClick }) => ({
4
+ color: theme.vars.palette.text.secondary,
5
+ padding: theme.spacing(0.25, 0.5, 0.25, 0.75),
6
+ maxHeight: 16,
7
+ fontSize: '0.75rem',
8
+ fontWeight: 500,
9
+ borderRadius: `calc(${theme.vars.shape.borderRadius} * 2)`,
10
+ backgroundColor: 'transparent',
11
+ minWidth: 32,
12
+ ...(onClick
13
+ ? {
14
+ '&:hover': {
15
+ backgroundColor: `rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.04)`,
16
+ },
17
+ ...theme.applyStyles('dark', {
18
+ backgroundColor: 'transparent',
19
+ '&:hover': {
20
+ backgroundColor: `rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.04)`,
21
+ },
22
+ }),
23
+ }
24
+ : {
25
+ cursor: 'text',
26
+ userSelect: 'text',
27
+ pointerEvents: 'none',
28
+ }),
29
+ }))
@@ -1,11 +1,14 @@
1
1
  import type { TokenAmount } from '@lifi/sdk'
2
+ import SwapVertIcon from '@mui/icons-material/SwapVert'
2
3
  import { FormHelperText, Skeleton, Typography } from '@mui/material'
3
4
  import { useTranslation } from 'react-i18next'
4
5
  import { useTokenAddressBalance } from '../../hooks/useTokenAddressBalance.js'
5
6
  import type { FormTypeProps } from '../../stores/form/types.js'
6
7
  import { FormKeyHelper } from '../../stores/form/types.js'
7
8
  import { useFieldValues } from '../../stores/form/useFieldValues.js'
9
+ import { useInputModeStore } from '../../stores/inputMode/useInputModeStore.js'
8
10
  import { formatTokenAmount, formatTokenPrice } from '../../utils/format.js'
11
+ import { InputPriceButton } from './PriceFormHelperText.style.js'
9
12
 
10
13
  export const PriceFormHelperText: React.FC<FormTypeProps> = ({ formType }) => {
11
14
  const [chainId, tokenAddress] = useFieldValues(
@@ -33,11 +36,31 @@ export const PriceFormHelperTextBase: React.FC<
33
36
  > = ({ formType, isLoading, tokenAddress, token }) => {
34
37
  const { t } = useTranslation()
35
38
  const [amount] = useFieldValues(FormKeyHelper.getAmountKey(formType))
39
+ const { inputMode, toggleInputMode } = useInputModeStore()
40
+
41
+ const currentInputMode = inputMode[formType]
36
42
 
37
43
  const tokenAmount = token
38
44
  ? formatTokenAmount(token.amount, token.decimals)
39
45
  : '0'
40
- const tokenPrice = formatTokenPrice(amount, token?.priceUSD)
46
+
47
+ const getPriceAmountDisplayValue = () => {
48
+ if (currentInputMode === 'amount') {
49
+ const tokenPrice = formatTokenPrice(
50
+ amount,
51
+ token?.priceUSD,
52
+ token?.decimals
53
+ )
54
+ return t('format.currency', { value: tokenPrice })
55
+ } else {
56
+ return t('format.tokenAmount', { value: amount || '0' })
57
+ }
58
+ }
59
+
60
+ const handleToggleMode = (e: React.MouseEvent) => {
61
+ e.stopPropagation()
62
+ toggleInputMode(formType)
63
+ }
41
64
 
42
65
  return (
43
66
  <FormHelperText
@@ -45,28 +68,49 @@ export const PriceFormHelperTextBase: React.FC<
45
68
  sx={{
46
69
  display: 'flex',
47
70
  justifyContent: 'space-between',
71
+ alignItems: 'center',
48
72
  margin: 0,
49
- marginLeft: 2,
50
- marginTop: 0.75,
73
+ marginLeft: 1.25,
74
+ marginTop: 0.5,
51
75
  }}
52
76
  >
53
- <Typography
54
- sx={{
55
- color: 'text.secondary',
56
- fontWeight: 500,
57
- fontSize: 12,
58
- lineHeight: 1,
59
- flex: 1,
60
- wordBreak: 'break-word',
61
- overflowWrap: 'break-word',
62
- }}
77
+ <InputPriceButton
78
+ onClick={token?.priceUSD ? handleToggleMode : undefined}
63
79
  >
64
- {t('format.currency', {
65
- value: tokenPrice,
66
- })}
67
- </Typography>
80
+ <Typography
81
+ sx={{
82
+ color: 'text.secondary',
83
+ fontWeight: 500,
84
+ fontSize: 12,
85
+ lineHeight: 1,
86
+ marginRight: 0.25,
87
+ maxWidth: 136,
88
+ overflow: 'hidden',
89
+ textOverflow: 'ellipsis',
90
+ whiteSpace: 'nowrap',
91
+ }}
92
+ >
93
+ {getPriceAmountDisplayValue()}
94
+ </Typography>
95
+ {currentInputMode === 'price' && token?.symbol ? (
96
+ <Typography
97
+ sx={{
98
+ color: 'text.secondary',
99
+ fontWeight: 500,
100
+ fontSize: 12,
101
+ lineHeight: 1,
102
+ wordBreak: 'break-word',
103
+ overflowWrap: 'break-word',
104
+ marginRight: 0.25,
105
+ }}
106
+ >
107
+ {token.symbol}
108
+ </Typography>
109
+ ) : null}
110
+ {token?.priceUSD && <SwapVertIcon sx={{ fontSize: 14 }} />}
111
+ </InputPriceButton>
68
112
  {isLoading && tokenAddress ? (
69
- <Skeleton variant="text" width={48} height={12} />
113
+ <Skeleton variant="text" width={56} height={16} />
70
114
  ) : token?.amount ? (
71
115
  <Typography
72
116
  sx={{
@@ -74,7 +118,7 @@ export const PriceFormHelperTextBase: React.FC<
74
118
  fontSize: 12,
75
119
  color: 'text.secondary',
76
120
  lineHeight: 1,
77
- pl: 0.25,
121
+ paddingLeft: 0.25,
78
122
  }}
79
123
  title={tokenAmount}
80
124
  >
@@ -71,6 +71,7 @@ export const RelativeContainer = styled(Box, {
71
71
  maxHeight: 'none',
72
72
  height: '100%',
73
73
  boxShadow: 'none',
74
+ borderRadius: 0,
74
75
  },
75
76
  },
76
77
  ],
@@ -9,13 +9,11 @@ import { useChainOrder } from '../../stores/chains/useChainOrder.js'
9
9
  import type { FormType } from '../../stores/form/types.js'
10
10
  import { FormKeyHelper } from '../../stores/form/types.js'
11
11
  import { useFieldActions } from '../../stores/form/useFieldActions.js'
12
- import { useFieldController } from '../../stores/form/useFieldController.js'
13
12
  import type { DisabledUI } from '../../types/widget.js'
14
13
 
15
14
  export const useChainSelect = (formType: FormType) => {
16
15
  const { disabledUI } = useWidgetConfig()
17
16
  const chainKey = FormKeyHelper.getChainKey(formType)
18
- const { onChange } = useFieldController({ name: chainKey })
19
17
  const { setFieldValue, getFieldValues } = useFieldActions()
20
18
  const { useExternalWalletProvidersOnly, externalChainTypes } =
21
19
  useExternalWalletProvider()
@@ -45,7 +43,7 @@ export const useChainSelect = (formType: FormType) => {
45
43
 
46
44
  const setCurrentChain = useCallback(
47
45
  (chainId: number) => {
48
- onChange(chainId)
46
+ setFieldValue(chainKey, chainId, { isDirty: true, isTouched: true })
49
47
  if (swapOnly) {
50
48
  setFieldValue(FormKeyHelper.getChainKey('to'), chainId, {
51
49
  isTouched: true,
@@ -69,7 +67,7 @@ export const useChainSelect = (formType: FormType) => {
69
67
  setChainOrder(chainId, formType)
70
68
  },
71
69
  [
72
- onChange,
70
+ chainKey,
73
71
  swapOnly,
74
72
  setFieldValue,
75
73
  disabledUI,
@@ -2,7 +2,6 @@ import type { ExtendedChain } from '@lifi/sdk'
2
2
  import { useVirtualizer } from '@tanstack/react-virtual'
3
3
  import type { RefObject } from 'react'
4
4
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react'
5
- import { shallow } from 'zustand/shallow'
6
5
  import { useChainOrderStore } from '../../stores/chains/ChainOrderStore'
7
6
  import { List } from './ChainList.style'
8
7
  import { ChainListItem } from './ChainListItem'
@@ -26,10 +25,10 @@ export const VirtualizedChainList = ({
26
25
  }: VirtualizedChainListProps) => {
27
26
  const selectedChainIdRef = useRef(selectedChainId) // Store the initial selected chain ID to scroll to it once chains are loaded
28
27
  const hasScrolledRef = useRef(false)
29
- const [pinnedChains, setPinnedChain] = useChainOrderStore(
30
- (state) => [state.pinnedChains, state.setPinnedChain],
31
- shallow
32
- )
28
+ const [pinnedChains, setPinnedChain] = useChainOrderStore((state) => [
29
+ state.pinnedChains,
30
+ state.setPinnedChain,
31
+ ])
33
32
  const onPin = useCallback(
34
33
  (chainId: number) => {
35
34
  setPinnedChain(chainId)
@@ -98,9 +97,9 @@ export const VirtualizedChainList = ({
98
97
  behavior: 'smooth',
99
98
  })
100
99
  })
101
- hasScrolledRef.current = true // Mark as scrolled (when needed)
102
100
  }
103
101
  }
102
+ hasScrolledRef.current = true // Mark as scrolled (when needed)
104
103
  }
105
104
  }, [sortedChains, scrollToIndex, range])
106
105
 
@@ -37,7 +37,16 @@ export const NavigationHeader: React.FC = () => {
37
37
  <>
38
38
  <HeaderAppBar elevation={0}>
39
39
  {backButtonRoutes.includes(path) ? (
40
- <BackButton onClick={navigateBack} />
40
+ <BackButton
41
+ onClick={() =>
42
+ navigateBack(
43
+ // From transaction details page, navigate to home page
44
+ path === navigationRoutes.transactionDetails
45
+ ? navigationRoutes.home
46
+ : undefined
47
+ )
48
+ }
49
+ />
41
50
  ) : null}
42
51
  {splitSubvariant ? (
43
52
  <Box
@@ -29,6 +29,8 @@ interface RoutesContentProps {
29
29
  refetch: () => void
30
30
  }
31
31
 
32
+ const headerHeight = '64px'
33
+
32
34
  export const RoutesContent = ({
33
35
  routes,
34
36
  isFetching,
@@ -77,7 +79,7 @@ export const RoutesContent = ({
77
79
 
78
80
  return (
79
81
  <Container enableColorScheme minimumHeight={isLoading}>
80
- <Header>
82
+ <Header sx={{ height: headerHeight }}>
81
83
  <Typography
82
84
  noWrap
83
85
  sx={{
@@ -96,7 +98,9 @@ export const RoutesContent = ({
96
98
  sx={{ marginRight: -1 }}
97
99
  />
98
100
  </Header>
99
- <PageContainer>
101
+ <PageContainer
102
+ sx={{ height: `calc(100% - ${headerHeight})`, overflow: 'auto' }}
103
+ >
100
104
  <Stack
101
105
  direction="column"
102
106
  spacing={2}
@@ -12,11 +12,13 @@ export const Container = styled(ScopedCssBaseline, {
12
12
  shouldForwardProp: (prop) => !['minimumHeight'].includes(prop as string),
13
13
  })<ContainerProps>(({ theme, minimumHeight }) => ({
14
14
  backgroundColor: theme.vars.palette.background.default,
15
- overflow: 'auto',
15
+ overflow: 'hidden',
16
16
  width: routesExpansionWidth,
17
17
  display: 'flex',
18
18
  flexDirection: 'column',
19
19
  whiteSpace: 'normal',
20
+ borderRadius: theme.container?.borderRadius ?? 0,
21
+ boxShadow: theme.container?.boxShadow ?? 'none',
20
22
  ...(theme.container?.display !== 'flex'
21
23
  ? {
22
24
  maxHeight:
@@ -26,7 +28,6 @@ export const Container = styled(ScopedCssBaseline, {
26
28
  ...(minimumHeight ? { '&': { height: 'auto' } } : {}),
27
29
  }
28
30
  : { height: minimumHeight ? 'auto' : '100%' }),
29
- ...theme.container,
30
31
  ...theme.routesContainer,
31
32
  }))
32
33
 
@@ -36,7 +36,7 @@ export const SendToWalletButton: React.FC<CardProps> = (props) => {
36
36
  subvariant,
37
37
  subvariantOptions,
38
38
  } = useWidgetConfig()
39
- const { showSendToWallet } = useSendToWalletStore()
39
+ const { showSendToWallet } = useSendToWalletStore((state) => state)
40
40
  const [toAddressFieldValue, toChainId, toTokenAddress] = useFieldValues(
41
41
  'toAddress',
42
42
  'toChain',
@@ -7,7 +7,10 @@ import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.j
7
7
  import { useBookmarkActions } from '../../stores/bookmarks/useBookmarkActions.js'
8
8
  import { useFieldActions } from '../../stores/form/useFieldActions.js'
9
9
  import { useFieldValues } from '../../stores/form/useFieldValues.js'
10
- import { useSendToWalletStore } from '../../stores/settings/useSendToWalletStore.js'
10
+ import {
11
+ sendToWalletStore,
12
+ useSendToWalletStore,
13
+ } from '../../stores/settings/useSendToWalletStore.js'
11
14
  import { WidgetEvent } from '../../types/events.js'
12
15
  import { DisabledUI, HiddenUI } from '../../types/widget.js'
13
16
 
@@ -17,7 +20,9 @@ export const SendToWalletExpandButton: React.FC = () => {
17
20
  const { setFieldValue } = useFieldActions()
18
21
  const { setSelectedBookmark } = useBookmarkActions()
19
22
  const emitter = useWidgetEvents()
20
- const { showSendToWallet, setSendToWallet } = useSendToWalletStore()
23
+ const { showSendToWallet, setSendToWallet } = useSendToWalletStore(
24
+ (state) => state
25
+ )
21
26
  const [toAddressFieldValue] = useFieldValues('toAddress')
22
27
  const { requiredToAddress } = useToAddressRequirements()
23
28
 
@@ -33,7 +38,7 @@ export const SendToWalletExpandButton: React.FC = () => {
33
38
  setSendToWallet(!showSendToWallet)
34
39
  emitter.emit(
35
40
  WidgetEvent.SendToWalletToggled,
36
- useSendToWalletStore.getState().showSendToWallet
41
+ sendToWalletStore.getState().showSendToWallet
37
42
  )
38
43
  }
39
44
 
@@ -13,17 +13,12 @@ export const StepProcess: React.FC<{
13
13
  const { title, message } = useProcessMessage(step, process)
14
14
  const { getTransactionLink } = useExplorer()
15
15
 
16
- const transactionLink = process.txHash
16
+ const transactionLink = process.txLink
17
17
  ? getTransactionLink({
18
- txHash: process.txHash,
18
+ txLink: process.txLink,
19
19
  chain: process.chainId,
20
20
  })
21
- : process.txLink
22
- ? getTransactionLink({
23
- txLink: process.txLink,
24
- chain: process.chainId,
25
- })
26
- : undefined
21
+ : undefined
27
22
 
28
23
  return (
29
24
  <Box
@@ -7,7 +7,6 @@ import { useTranslation } from 'react-i18next'
7
7
  import { useAvailableChains } from '../../hooks/useAvailableChains.js'
8
8
  import { useExplorer } from '../../hooks/useExplorer.js'
9
9
  import { useTokenSearch } from '../../hooks/useTokenSearch.js'
10
- import { formatTokenPrice } from '../../utils/format.js'
11
10
  import { shortenAddress } from '../../utils/wallet.js'
12
11
  import { TokenAvatar } from '../Avatar/TokenAvatar.js'
13
12
  import { CardIconButton } from '../Card/CardIconButton.js'
@@ -119,7 +118,7 @@ export const TokenDetailsSheetContent = forwardRef<
119
118
  >
120
119
  {token?.priceUSD
121
120
  ? t('format.currency', {
122
- value: formatTokenPrice('1', token.priceUSD, token.decimals),
121
+ value: token.priceUSD,
123
122
  })
124
123
  : noDataLabel}
125
124
  </Typography>
@@ -6,7 +6,6 @@ import { useChainOrderStoreContext } from '../../stores/chains/ChainOrderStore.j
6
6
  import type { FormType } from '../../stores/form/types.js'
7
7
  import { FormKeyHelper } from '../../stores/form/types.js'
8
8
  import { useFieldActions } from '../../stores/form/useFieldActions.js'
9
- import { useFieldController } from '../../stores/form/useFieldController.js'
10
9
  import { WidgetEvent } from '../../types/events.js'
11
10
  import type { DisabledUI } from '../../types/widget.js'
12
11
 
@@ -23,11 +22,10 @@ export const useTokenSelect = (formType: FormType, onClick?: () => void) => {
23
22
  const chainOrderStore = useChainOrderStoreContext()
24
23
 
25
24
  const tokenKey = FormKeyHelper.getTokenKey(formType)
26
- const { onChange } = useFieldController({ name: tokenKey })
27
25
 
28
26
  return useCallback(
29
27
  (tokenAddress: string, chainId?: number) => {
30
- onChange(tokenAddress)
28
+ setFieldValue(tokenKey, tokenAddress, { isDirty: true, isTouched: true })
31
29
  const selectedChainId =
32
30
  chainId ?? getFieldValues(FormKeyHelper.getChainKey(formType))[0]
33
31
  // Set chain again to trigger URL builder update
@@ -105,10 +103,10 @@ export const useTokenSelect = (formType: FormType, onClick?: () => void) => {
105
103
  emitter,
106
104
  formType,
107
105
  getFieldValues,
108
- onChange,
109
106
  onClick,
110
107
  setFieldValue,
111
108
  subvariant,
109
+ tokenKey,
112
110
  ]
113
111
  )
114
112
  }
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/widget'
2
- export const version = '3.25.0'
2
+ export const version = '3.26.0'
@@ -16,13 +16,17 @@ export const useFromAmountThreshold = () => {
16
16
  const { token } = useToken(chainId, tokenAddress)
17
17
 
18
18
  const belowMinFromAmountUSD = useMemo(() => {
19
- const fromAmountUSD = formatTokenPrice(fromAmount, token?.priceUSD)
19
+ const fromAmountUSD = formatTokenPrice(
20
+ fromAmount,
21
+ token?.priceUSD,
22
+ token?.decimals
23
+ )
20
24
 
21
25
  if (!minFromAmountUSD || !fromAmountUSD) {
22
26
  return false
23
27
  }
24
28
  return fromAmountUSD < minFromAmountUSD
25
- }, [minFromAmountUSD, fromAmount, token?.priceUSD])
29
+ }, [minFromAmountUSD, fromAmount, token?.priceUSD, token?.decimals])
26
30
 
27
31
  return {
28
32
  belowMinFromAmountUSD,
@@ -57,7 +57,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
57
57
  EVMAccount.chainType
58
58
  )
59
59
 
60
- const { data: insufficientGas, isLoading } = useQuery({
60
+ const { data: insufficientGas, isLoading } = useQuery<GasSufficiency[]>({
61
61
  queryKey: [
62
62
  getQueryKey('gas-sufficiency-check', keyPrefix),
63
63
  relevantAccountsQueryKey,
@@ -66,7 +66,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
66
66
  ] as const,
67
67
  queryFn: async () => {
68
68
  if (!route) {
69
- return
69
+ return []
70
70
  }
71
71
 
72
72
  // Filter out steps that are relayer steps or have primaryType 'Permit' or 'Order'
@@ -80,7 +80,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
80
80
 
81
81
  // If all steps are filtered out, we don't need to check for gas sufficiency
82
82
  if (!filteredSteps.length) {
83
- return
83
+ return []
84
84
  }
85
85
 
86
86
  // We assume that LI.Fuel protocol always refuels the destination chain
@@ -163,7 +163,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
163
163
  .flatMap((result) => result.value)
164
164
 
165
165
  if (!tokenBalances?.length) {
166
- return
166
+ return []
167
167
  }
168
168
 
169
169
  Object.keys(gasCosts).forEach((chainId) => {
@@ -4,23 +4,32 @@ import { useNavigate } from 'react-router-dom'
4
4
  export const useNavigateBack = () => {
5
5
  const navigate = useNavigate()
6
6
 
7
- const navigateBack = useCallback(() => {
8
- // TODO: find a better router with nested memory routers support
9
- // https://github.com/remix-run/react-router/pull/9112
10
- // https://github.com/remix-run/react-router/discussions/9601
11
- //
12
- // if (window.history.length > 2) {
13
- navigate(-1)
14
- // } else {
15
- // navigate(
16
- // window.location.pathname.substring(
17
- // 0,
18
- // window.location.pathname.lastIndexOf('/'),
19
- // ) || '/',
20
- // { replace: true },
21
- // );
22
- // }
23
- }, [navigate])
7
+ const navigateBack = useCallback(
8
+ (toPathname?: string) => {
9
+ // TODO: find a better router with nested memory routers support
10
+ // https://github.com/remix-run/react-router/pull/9112
11
+ // https://github.com/remix-run/react-router/discussions/9601
12
+ //
13
+ // if (window.history.length > 2) {
14
+ // navigate(-1)
15
+ // } else {
16
+ // navigate(
17
+ // window.location.pathname.substring(
18
+ // 0,
19
+ // window.location.pathname.lastIndexOf('/'),
20
+ // ) || '/',
21
+ // { replace: true },
22
+ // );
23
+ // }
24
+
25
+ if (toPathname) {
26
+ navigate(toPathname)
27
+ } else {
28
+ navigate(-1)
29
+ }
30
+ },
31
+ [navigate]
32
+ )
24
33
 
25
34
  return { navigateBack, navigate }
26
35
  }
@@ -3,7 +3,6 @@ import { executeRoute, resumeRoute, updateRouteExecution } from '@lifi/sdk'
3
3
  import { useAccount } from '@lifi/wallet-management'
4
4
  import { useMutation, useQueryClient } from '@tanstack/react-query'
5
5
  import { useCallback, useEffect, useRef } from 'react'
6
- import { shallow } from 'zustand/shallow'
7
6
  import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
8
7
  import {
9
8
  useRouteExecutionStore,
@@ -43,8 +42,7 @@ export const useRouteExecution = ({
43
42
  (state) => state.routes[routeId]
44
43
  )
45
44
  const [updateRoute, restartRoute, deleteRoute] = useRouteExecutionStore(
46
- (state) => [state.updateRoute, state.restartRoute, state.deleteRoute],
47
- shallow
45
+ (state) => [state.updateRoute, state.restartRoute, state.deleteRoute]
48
46
  )
49
47
 
50
48
  const updateRouteHook = (updatedRoute: Route) => {
@@ -1,4 +1,4 @@
1
- import type { Route, Token } from '@lifi/sdk'
1
+ import type { Route, Token, TokensResponse } from '@lifi/sdk'
2
2
  import {
3
3
  ChainType,
4
4
  convertQuoteToRoute,
@@ -406,6 +406,24 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
406
406
  // Update local tokens cache to keep priceUSD in sync
407
407
  const { fromToken, toToken } = routesResult.routes[0]
408
408
  ;[fromToken, toToken].forEach((token) => {
409
+ queryClient.setQueriesData<TokensResponse>(
410
+ { queryKey: [getQueryKey('tokens', keyPrefix)] },
411
+ (data) => {
412
+ if (data) {
413
+ const clonedData = { ...data }
414
+ const index = clonedData.tokens?.[token.chainId]?.findIndex(
415
+ (dataToken) => dataToken.address === token.address
416
+ )
417
+ if (index >= 0) {
418
+ clonedData.tokens[token.chainId][index] = {
419
+ ...clonedData.tokens[token.chainId][index],
420
+ ...token,
421
+ }
422
+ }
423
+ return clonedData
424
+ }
425
+ }
426
+ )
409
427
  queryClient.setQueriesData<Token[]>(
410
428
  {
411
429
  queryKey: [
@@ -420,9 +438,11 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
420
438
  const index = clonedData.findIndex(
421
439
  (dataToken) => dataToken.address === token.address
422
440
  )
423
- clonedData[index] = {
424
- ...clonedData[index],
425
- ...token,
441
+ if (index >= 0) {
442
+ clonedData[index] = {
443
+ ...clonedData[index],
444
+ ...token,
445
+ }
426
446
  }
427
447
  return clonedData
428
448
  }
@@ -1,4 +1,3 @@
1
- import { shallow } from 'zustand/shallow'
2
1
  import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
3
2
  import { useSettingsActions } from '../stores/settings/useSettingsActions.js'
4
3
  import {
@@ -14,16 +13,13 @@ export const useSettingMonitor = () => {
14
13
  routePriority,
15
14
  slippage,
16
15
  gasPrice,
17
- ] = useSettingsStore(
18
- (state) => [
19
- state.disabledBridges,
20
- state.disabledExchanges,
21
- state.routePriority,
22
- state.slippage,
23
- state.gasPrice,
24
- ],
25
- shallow
26
- )
16
+ ] = useSettingsStore((state) => [
17
+ state.disabledBridges,
18
+ state.disabledExchanges,
19
+ state.routePriority,
20
+ state.slippage,
21
+ state.gasPrice,
22
+ ])
27
23
  const { tools } = useTools()
28
24
  const config = useWidgetConfig()
29
25
  const { setDefaultSettings, resetSettings } = useSettingsActions()
@@ -11,9 +11,14 @@ export const useTokenAddressBalance = (
11
11
 
12
12
  const token = useMemo(() => {
13
13
  if (tokenAddress && chainId) {
14
- const token = (tokensWithBalance ?? tokens)?.find(
14
+ let token = tokensWithBalance?.find(
15
15
  (token) => token.address === tokenAddress && token.chainId === chainId
16
16
  )
17
+ if (!token) {
18
+ token = tokens?.find(
19
+ (token) => token.address === tokenAddress && token.chainId === chainId
20
+ )
21
+ }
17
22
  return token as TokenAmount
18
23
  }
19
24
  }, [chainId, tokenAddress, tokens, tokensWithBalance])
@@ -61,8 +61,11 @@ export const useTokenSearch = (
61
61
  (t) => t.address === token.address
62
62
  )
63
63
  ) {
64
- const clonedData = { ...data }
65
- clonedData.tokens[chainId as number]?.push(token as TokenExtended)
64
+ const clonedData = { ...data, tokens: { ...data.tokens } }
65
+ clonedData.tokens[chainId as number] = [
66
+ ...(clonedData.tokens[chainId as number] ?? []),
67
+ token,
68
+ ]
66
69
  return clonedData
67
70
  }
68
71
  }
@@ -19,8 +19,8 @@ export const useTokens = (selectedChainId?: number) => {
19
19
  ChainType.MVM,
20
20
  ],
21
21
  }),
22
- refetchInterval: 3_600_000,
23
- staleTime: 3_600_000,
22
+ refetchInterval: 300_000,
23
+ staleTime: 300_000,
24
24
  })
25
25
  const {
26
26
  chains,