@lifi/widget 3.25.0 → 3.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/CHANGELOG.md +27 -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/ChainsExpanded.d.ts +1 -1
  22. package/dist/esm/components/Chains/ChainsExpanded.js +3 -2
  23. package/dist/esm/components/Chains/ChainsExpanded.js.map +1 -1
  24. package/dist/esm/components/Chains/ChainsExpanded.style.js +1 -2
  25. package/dist/esm/components/Chains/ChainsExpanded.style.js.map +1 -1
  26. package/dist/esm/components/Chains/SelectChainContent.d.ts +1 -1
  27. package/dist/esm/components/Chains/SelectChainContent.js +3 -2
  28. package/dist/esm/components/Chains/SelectChainContent.js.map +1 -1
  29. package/dist/esm/components/Chains/VirtualizedChainList.js +5 -3
  30. package/dist/esm/components/Chains/VirtualizedChainList.js.map +1 -1
  31. package/dist/esm/components/Expansion/Expansion.js +5 -16
  32. package/dist/esm/components/Expansion/Expansion.js.map +1 -1
  33. package/dist/esm/components/Expansion/Expansion.style.d.ts +32 -0
  34. package/dist/esm/components/Expansion/Expansion.style.js +40 -0
  35. package/dist/esm/components/Expansion/Expansion.style.js.map +1 -0
  36. package/dist/esm/components/Expansion/ExpansionTransition.d.ts +0 -1
  37. package/dist/esm/components/Expansion/ExpansionTransition.js +1 -30
  38. package/dist/esm/components/Expansion/ExpansionTransition.js.map +1 -1
  39. package/dist/esm/components/Header/NavigationHeader.js +5 -1
  40. package/dist/esm/components/Header/NavigationHeader.js.map +1 -1
  41. package/dist/esm/components/Routes/RoutesContent.d.ts +2 -3
  42. package/dist/esm/components/Routes/RoutesContent.js +8 -23
  43. package/dist/esm/components/Routes/RoutesContent.js.map +1 -1
  44. package/dist/esm/components/Routes/RoutesExpanded.d.ts +2 -3
  45. package/dist/esm/components/Routes/RoutesExpanded.js +24 -8
  46. package/dist/esm/components/Routes/RoutesExpanded.js.map +1 -1
  47. package/dist/esm/components/Routes/RoutesExpanded.style.js +2 -2
  48. package/dist/esm/components/Routes/RoutesExpanded.style.js.map +1 -1
  49. package/dist/esm/components/SendToWallet/SendToWalletButton.js +1 -1
  50. package/dist/esm/components/SendToWallet/SendToWalletButton.js.map +1 -1
  51. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js +3 -3
  52. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js.map +1 -1
  53. package/dist/esm/components/Step/StepProcess.js +3 -8
  54. package/dist/esm/components/Step/StepProcess.js.map +1 -1
  55. package/dist/esm/components/TokenList/TokenDetailsSheetContent.js +1 -2
  56. package/dist/esm/components/TokenList/TokenDetailsSheetContent.js.map +1 -1
  57. package/dist/esm/components/TokenList/useTokenSelect.js +2 -4
  58. package/dist/esm/components/TokenList/useTokenSelect.js.map +1 -1
  59. package/dist/esm/config/version.d.ts +1 -1
  60. package/dist/esm/config/version.js +1 -1
  61. package/dist/esm/hooks/useFromAmountThreshold.js +2 -2
  62. package/dist/esm/hooks/useFromAmountThreshold.js.map +1 -1
  63. package/dist/esm/hooks/useGasSufficiency.js +3 -3
  64. package/dist/esm/hooks/useGasSufficiency.js.map +1 -1
  65. package/dist/esm/hooks/useNavigateBack.d.ts +1 -1
  66. package/dist/esm/hooks/useNavigateBack.js +8 -2
  67. package/dist/esm/hooks/useNavigateBack.js.map +1 -1
  68. package/dist/esm/hooks/useRouteExecution.js +1 -2
  69. package/dist/esm/hooks/useRouteExecution.js.map +1 -1
  70. package/dist/esm/hooks/useRoutes.js +51 -8
  71. package/dist/esm/hooks/useRoutes.js.map +1 -1
  72. package/dist/esm/hooks/useSettingMonitor.js +1 -2
  73. package/dist/esm/hooks/useSettingMonitor.js.map +1 -1
  74. package/dist/esm/hooks/useTokenAddressBalance.js +4 -1
  75. package/dist/esm/hooks/useTokenAddressBalance.js.map +1 -1
  76. package/dist/esm/hooks/useTokenSearch.js +5 -2
  77. package/dist/esm/hooks/useTokenSearch.js.map +1 -1
  78. package/dist/esm/hooks/useTokens.js +2 -2
  79. package/dist/esm/hooks/useTokens.js.map +1 -1
  80. package/dist/esm/hooks/useTools.js +2 -2
  81. package/dist/esm/hooks/useTools.js.map +1 -1
  82. package/dist/esm/i18n/bn.json +1 -1
  83. package/dist/esm/i18n/de.json +1 -1
  84. package/dist/esm/i18n/en.json +1 -1
  85. package/dist/esm/i18n/es.json +1 -1
  86. package/dist/esm/i18n/fr.json +1 -1
  87. package/dist/esm/i18n/hi.json +1 -1
  88. package/dist/esm/i18n/id.json +1 -1
  89. package/dist/esm/i18n/it.json +1 -1
  90. package/dist/esm/i18n/ja.json +1 -1
  91. package/dist/esm/i18n/ko.json +1 -1
  92. package/dist/esm/i18n/pt.json +1 -1
  93. package/dist/esm/i18n/th.json +1 -1
  94. package/dist/esm/i18n/tr.json +1 -1
  95. package/dist/esm/i18n/uk.json +1 -1
  96. package/dist/esm/i18n/vi.json +1 -1
  97. package/dist/esm/i18n/zh.json +1 -1
  98. package/dist/esm/pages/SelectEnabledToolsPage.js +4 -2
  99. package/dist/esm/pages/SelectEnabledToolsPage.js.map +1 -1
  100. package/dist/esm/pages/SelectTokenPage/SearchTokenInput.js +14 -7
  101. package/dist/esm/pages/SelectTokenPage/SearchTokenInput.js.map +1 -1
  102. package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js +1 -2
  103. package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js.map +1 -1
  104. package/dist/esm/pages/TransactionPage/TransactionPage.js +5 -3
  105. package/dist/esm/pages/TransactionPage/TransactionPage.js.map +1 -1
  106. package/dist/esm/stores/bookmarks/BookmarkStore.d.ts +1 -2
  107. package/dist/esm/stores/bookmarks/BookmarkStore.js +3 -3
  108. package/dist/esm/stores/bookmarks/BookmarkStore.js.map +1 -1
  109. package/dist/esm/stores/bookmarks/useBookmarkActions.js +1 -2
  110. package/dist/esm/stores/bookmarks/useBookmarkActions.js.map +1 -1
  111. package/dist/esm/stores/bookmarks/useBookmarks.js +1 -2
  112. package/dist/esm/stores/bookmarks/useBookmarks.js.map +1 -1
  113. package/dist/esm/stores/chains/ChainOrderStore.d.ts +1 -1
  114. package/dist/esm/stores/chains/ChainOrderStore.js +3 -2
  115. package/dist/esm/stores/chains/ChainOrderStore.js.map +1 -1
  116. package/dist/esm/stores/chains/useChainOrder.js +1 -2
  117. package/dist/esm/stores/chains/useChainOrder.js.map +1 -1
  118. package/dist/esm/stores/form/useFieldActions.js +1 -2
  119. package/dist/esm/stores/form/useFieldActions.js.map +1 -1
  120. package/dist/esm/stores/form/useFieldValues.js +1 -2
  121. package/dist/esm/stores/form/useFieldValues.js.map +1 -1
  122. package/dist/esm/stores/form/useFormStore.d.ts +1 -2
  123. package/dist/esm/stores/form/useFormStore.js +3 -3
  124. package/dist/esm/stores/form/useFormStore.js.map +1 -1
  125. package/dist/esm/stores/form/useTouchedFields.js +1 -2
  126. package/dist/esm/stores/form/useTouchedFields.js.map +1 -1
  127. package/dist/esm/stores/form/useValidation.js +5 -2
  128. package/dist/esm/stores/form/useValidation.js.map +1 -1
  129. package/dist/esm/stores/form/useValidationActions.js +1 -2
  130. package/dist/esm/stores/form/useValidationActions.js.map +1 -1
  131. package/dist/esm/stores/header/useHeaderStore.d.ts +1 -1
  132. package/dist/esm/stores/header/useHeaderStore.js +3 -2
  133. package/dist/esm/stores/header/useHeaderStore.js.map +1 -1
  134. package/dist/esm/stores/inputMode/useInputModeStore.d.ts +9 -0
  135. package/dist/esm/stores/inputMode/useInputModeStore.js +19 -0
  136. package/dist/esm/stores/inputMode/useInputModeStore.js.map +1 -0
  137. package/dist/esm/stores/routes/RouteExecutionStore.d.ts +1 -1
  138. package/dist/esm/stores/routes/RouteExecutionStore.js +3 -2
  139. package/dist/esm/stores/routes/RouteExecutionStore.js.map +1 -1
  140. package/dist/esm/stores/routes/useExecutingRoutesIds.js +1 -2
  141. package/dist/esm/stores/routes/useExecutingRoutesIds.js.map +1 -1
  142. package/dist/esm/stores/settings/useSendToWalletStore.d.ts +2 -1
  143. package/dist/esm/stores/settings/useSendToWalletStore.js +6 -3
  144. package/dist/esm/stores/settings/useSendToWalletStore.js.map +1 -1
  145. package/dist/esm/stores/settings/useSettings.js +1 -2
  146. package/dist/esm/stores/settings/useSettings.js.map +1 -1
  147. package/dist/esm/stores/settings/useSettingsActions.js +1 -2
  148. package/dist/esm/stores/settings/useSettingsActions.js.map +1 -1
  149. package/dist/esm/stores/settings/useSettingsStore.d.ts +2 -1
  150. package/dist/esm/stores/settings/useSettingsStore.js +5 -1
  151. package/dist/esm/stores/settings/useSettingsStore.js.map +1 -1
  152. package/dist/esm/stores/settings/useSplitSubvariantStore.js +2 -1
  153. package/dist/esm/stores/settings/useSplitSubvariantStore.js.map +1 -1
  154. package/dist/esm/themes/createTheme.js +5 -1
  155. package/dist/esm/themes/createTheme.js.map +1 -1
  156. package/dist/esm/types/widget.d.ts +2 -1
  157. package/dist/esm/types/widget.js +1 -0
  158. package/dist/esm/types/widget.js.map +1 -1
  159. package/dist/esm/utils/format.d.ts +4 -0
  160. package/dist/esm/utils/format.js +26 -0
  161. package/dist/esm/utils/format.js.map +1 -1
  162. package/dist/esm/utils/getPriceImpact.d.ts +2 -2
  163. package/dist/esm/utils/getPriceImpact.js.map +1 -1
  164. package/package.json +12 -12
  165. package/package.json.tmp +14 -14
  166. package/src/components/AmountInput/AmountInput.style.tsx +13 -0
  167. package/src/components/AmountInput/AmountInput.tsx +91 -18
  168. package/src/components/AmountInput/AmountInputAdornment.style.tsx +66 -5
  169. package/src/components/AmountInput/AmountInputEndAdornment.tsx +40 -10
  170. package/src/components/AmountInput/PriceFormHelperText.style.tsx +29 -0
  171. package/src/components/AmountInput/PriceFormHelperText.tsx +63 -19
  172. package/src/components/AppContainer.tsx +1 -0
  173. package/src/components/ChainSelect/useChainSelect.ts +2 -4
  174. package/src/components/Chains/ChainsExpanded.style.tsx +1 -2
  175. package/src/components/Chains/ChainsExpanded.tsx +6 -2
  176. package/src/components/Chains/SelectChainContent.tsx +81 -82
  177. package/src/components/Chains/VirtualizedChainList.tsx +5 -6
  178. package/src/components/Expansion/Expansion.style.tsx +43 -0
  179. package/src/components/Expansion/Expansion.tsx +8 -23
  180. package/src/components/Expansion/ExpansionTransition.tsx +5 -33
  181. package/src/components/Header/NavigationHeader.tsx +10 -1
  182. package/src/components/Routes/RoutesContent.tsx +14 -31
  183. package/src/components/Routes/RoutesExpanded.style.ts +2 -2
  184. package/src/components/Routes/RoutesExpanded.tsx +33 -13
  185. package/src/components/SendToWallet/SendToWalletButton.tsx +1 -1
  186. package/src/components/SendToWallet/SendToWalletExpandButton.tsx +8 -3
  187. package/src/components/Step/StepProcess.tsx +3 -8
  188. package/src/components/TokenList/TokenDetailsSheetContent.tsx +1 -2
  189. package/src/components/TokenList/useTokenSelect.ts +2 -4
  190. package/src/config/version.ts +1 -1
  191. package/src/hooks/useFromAmountThreshold.ts +6 -2
  192. package/src/hooks/useGasSufficiency.ts +4 -4
  193. package/src/hooks/useNavigateBack.ts +26 -17
  194. package/src/hooks/useRouteExecution.ts +1 -3
  195. package/src/hooks/useRoutes.ts +92 -37
  196. package/src/hooks/useSettingMonitor.ts +7 -11
  197. package/src/hooks/useTokenAddressBalance.ts +6 -1
  198. package/src/hooks/useTokenSearch.ts +5 -2
  199. package/src/hooks/useTokens.ts +2 -2
  200. package/src/hooks/useTools.ts +2 -2
  201. package/src/i18n/bn.json +1 -1
  202. package/src/i18n/de.json +1 -1
  203. package/src/i18n/en.json +1 -1
  204. package/src/i18n/es.json +1 -1
  205. package/src/i18n/fr.json +1 -1
  206. package/src/i18n/hi.json +1 -1
  207. package/src/i18n/id.json +1 -1
  208. package/src/i18n/it.json +1 -1
  209. package/src/i18n/ja.json +1 -1
  210. package/src/i18n/ko.json +1 -1
  211. package/src/i18n/pt.json +1 -1
  212. package/src/i18n/th.json +1 -1
  213. package/src/i18n/tr.json +1 -1
  214. package/src/i18n/uk.json +1 -1
  215. package/src/i18n/vi.json +1 -1
  216. package/src/i18n/zh.json +1 -1
  217. package/src/pages/SelectEnabledToolsPage.tsx +4 -5
  218. package/src/pages/SelectTokenPage/SearchTokenInput.tsx +19 -7
  219. package/src/pages/SettingsPage/BridgeAndExchangeSettings.tsx +1 -2
  220. package/src/pages/TransactionPage/TransactionPage.tsx +17 -9
  221. package/src/stores/bookmarks/BookmarkStore.tsx +3 -6
  222. package/src/stores/bookmarks/useBookmarkActions.ts +9 -13
  223. package/src/stores/bookmarks/useBookmarks.ts +1 -3
  224. package/src/stores/chains/ChainOrderStore.tsx +3 -3
  225. package/src/stores/chains/useChainOrder.ts +1 -5
  226. package/src/stores/form/useFieldActions.ts +10 -14
  227. package/src/stores/form/useFieldValues.ts +1 -3
  228. package/src/stores/form/useFormStore.ts +3 -6
  229. package/src/stores/form/useTouchedFields.ts +1 -2
  230. package/src/stores/form/useValidation.ts +5 -5
  231. package/src/stores/form/useValidationActions.ts +5 -9
  232. package/src/stores/header/useHeaderStore.tsx +3 -5
  233. package/src/stores/inputMode/useInputModeStore.ts +29 -0
  234. package/src/stores/routes/RouteExecutionStore.tsx +3 -3
  235. package/src/stores/routes/useExecutingRoutesIds.ts +14 -17
  236. package/src/stores/settings/useSendToWalletStore.ts +11 -8
  237. package/src/stores/settings/useSettings.ts +8 -11
  238. package/src/stores/settings/useSettingsActions.ts +8 -12
  239. package/src/stores/settings/useSettingsStore.ts +8 -1
  240. package/src/stores/settings/useSplitSubvariantStore.tsx +2 -1
  241. package/src/themes/createTheme.ts +5 -1
  242. package/src/types/widget.ts +1 -0
  243. package/src/utils/format.ts +33 -0
  244. package/src/utils/getPriceImpact.ts +2 -2
@@ -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,
@@ -9,14 +9,13 @@ interface SelectChainExpansionContainerProps {
9
9
  export const SelectChainExpansionContainer = styled(Box, {
10
10
  shouldForwardProp: (prop) => prop !== 'expansionHeight',
11
11
  })<SelectChainExpansionContainerProps>(({ theme, expansionHeight }) => ({
12
+ ...theme.container,
12
13
  position: 'relative',
13
14
  boxSizing: 'content-box',
14
15
  width: chainExpansionWidth,
15
16
  background: theme.vars.palette.background.default,
16
17
  overflow: 'hidden',
17
18
  flex: 1,
18
- borderRadius: theme.container?.borderRadius ?? 0,
19
- boxShadow: theme.container?.boxShadow ?? 'none',
20
19
  zIndex: 0,
21
20
  height: expansionHeight,
22
21
  ...theme.chainSidebarContainer,
@@ -1,3 +1,4 @@
1
+ import { memo } from 'react'
1
2
  import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider'
2
3
  import type { FormType } from '../../stores/form/types'
3
4
  import { getWidgetMaxHeight } from '../../utils/widgetSize'
@@ -13,7 +14,10 @@ interface ChainsExpandedProps {
13
14
  open: boolean
14
15
  }
15
16
 
16
- export const ChainsExpanded = ({ formType, open }: ChainsExpandedProps) => {
17
+ export const ChainsExpanded = memo(function ChainsExpanded({
18
+ formType,
19
+ open,
20
+ }: ChainsExpandedProps) {
17
21
  const { theme } = useWidgetConfig()
18
22
 
19
23
  return (
@@ -25,4 +29,4 @@ export const ChainsExpanded = ({ formType, open }: ChainsExpandedProps) => {
25
29
  </SelectChainExpansionContainer>
26
30
  </ExpansionTransition>
27
31
  )
28
- }
32
+ })
@@ -19,95 +19,94 @@ interface SelectChainContentProps {
19
19
 
20
20
  const searchHeaderHeight = '80px'
21
21
 
22
- export const SelectChainContent: React.FC<SelectChainContentProps> = memo(
23
- ({ formType, onSelect, inExpansion }) => {
24
- const theme = useTheme()
25
- const { chains, isLoading, setCurrentChain } = useChainSelect(formType)
26
- const elementId = useDefaultElementId()
27
- const scrollableContainer = useScrollableContainer(elementId)
28
- const [selectedChainId] = useFieldValues(
29
- FormKeyHelper.getChainKey(formType)
30
- )
31
- const inputRef = useRef<HTMLInputElement>(null)
32
- const listRef = useRef<HTMLDivElement>(null)
33
- const [debouncedSearchValue, setDebouncedSearchValue] = useState('')
22
+ export const SelectChainContent = memo(function SelectChainContent({
23
+ formType,
24
+ onSelect,
25
+ inExpansion,
26
+ }: SelectChainContentProps) {
27
+ const theme = useTheme()
28
+ const { chains, isLoading, setCurrentChain } = useChainSelect(formType)
29
+ const elementId = useDefaultElementId()
30
+ const scrollableContainer = useScrollableContainer(elementId)
31
+ const [selectedChainId] = useFieldValues(FormKeyHelper.getChainKey(formType))
32
+ const inputRef = useRef<HTMLInputElement>(null)
33
+ const listRef = useRef<HTMLDivElement>(null)
34
+ const [debouncedSearchValue, setDebouncedSearchValue] = useState('')
34
35
 
35
- const filteredChains = useMemo(() => {
36
- const value = debouncedSearchValue.toLowerCase()
37
- return value
38
- ? (chains?.filter((chain) =>
39
- chain.name.toLowerCase().includes(value)
40
- ) ?? [])
41
- : (chains ?? [])
42
- }, [chains, debouncedSearchValue])
36
+ const filteredChains = useMemo(() => {
37
+ const value = debouncedSearchValue.toLowerCase()
38
+ return value
39
+ ? (chains?.filter((chain) => chain.name.toLowerCase().includes(value)) ??
40
+ [])
41
+ : (chains ?? [])
42
+ }, [chains, debouncedSearchValue])
43
43
 
44
- const scrollToTop = useCallback(() => {
45
- // Scroll widget container to top
46
- if (!inExpansion && scrollableContainer) {
47
- scrollableContainer.scrollTop = 0
48
- }
49
- }, [inExpansion, scrollableContainer])
44
+ const scrollToTop = useCallback(() => {
45
+ // Scroll widget container to top
46
+ if (!inExpansion && scrollableContainer) {
47
+ scrollableContainer.scrollTop = 0
48
+ }
49
+ }, [inExpansion, scrollableContainer])
50
50
 
51
- const debouncedFilterChains = useMemo(
52
- () =>
53
- debounce((value: string) => {
54
- setDebouncedSearchValue(value)
55
- scrollToTop()
56
- }, 250),
57
- [scrollToTop]
58
- )
51
+ const debouncedFilterChains = useMemo(
52
+ () =>
53
+ debounce((value: string) => {
54
+ setDebouncedSearchValue(value)
55
+ scrollToTop()
56
+ }, 250),
57
+ [scrollToTop]
58
+ )
59
59
 
60
- const onSelectChainFallback = useCallback(
61
- (chain: ExtendedChain) => {
62
- setCurrentChain(chain.id)
63
- },
64
- [setCurrentChain]
65
- )
60
+ const onSelectChainFallback = useCallback(
61
+ (chain: ExtendedChain) => {
62
+ setCurrentChain(chain.id)
63
+ },
64
+ [setCurrentChain]
65
+ )
66
66
 
67
- const onChange = useCallback(() => {
68
- const value = inputRef.current?.value || ''
69
- debouncedFilterChains(value)
70
- }, [debouncedFilterChains])
67
+ const onChange = useCallback(() => {
68
+ const value = inputRef.current?.value || ''
69
+ debouncedFilterChains(value)
70
+ }, [debouncedFilterChains])
71
71
 
72
- const onClear = useCallback(() => {
73
- setDebouncedSearchValue('')
74
- scrollToTop()
75
- }, [scrollToTop])
72
+ const onClear = useCallback(() => {
73
+ setDebouncedSearchValue('')
74
+ scrollToTop()
75
+ }, [scrollToTop])
76
76
 
77
- const listContainerHeight = useMemo(() => {
78
- const fullContainerHeight = getWidgetMaxHeight(theme)
79
- const heightValue =
80
- typeof fullContainerHeight === 'number'
81
- ? `${fullContainerHeight}px`
82
- : fullContainerHeight
83
- return `calc(${heightValue} - ${searchHeaderHeight})`
84
- }, [theme])
77
+ const listContainerHeight = useMemo(() => {
78
+ const fullContainerHeight = getWidgetMaxHeight(theme)
79
+ const heightValue =
80
+ typeof fullContainerHeight === 'number'
81
+ ? `${fullContainerHeight}px`
82
+ : fullContainerHeight
83
+ return `calc(${heightValue} - ${searchHeaderHeight})`
84
+ }, [theme])
85
85
 
86
- return (
87
- <FullPageContainer disableGutters>
88
- <ChainSearchInput
89
- inputRef={inputRef}
86
+ return (
87
+ <FullPageContainer disableGutters>
88
+ <ChainSearchInput
89
+ inputRef={inputRef}
90
+ inExpansion={inExpansion}
91
+ onChange={onChange}
92
+ onClear={onClear}
93
+ searchHeaderHeight={searchHeaderHeight}
94
+ />
95
+ <Box
96
+ ref={listRef}
97
+ sx={
98
+ inExpansion ? { height: listContainerHeight, overflow: 'auto' } : {}
99
+ }
100
+ >
101
+ <ChainList
102
+ parentRef={listRef}
103
+ chains={filteredChains}
104
+ isLoading={isLoading}
105
+ onSelect={onSelect ?? onSelectChainFallback}
106
+ selectedChainId={selectedChainId}
90
107
  inExpansion={inExpansion}
91
- onChange={onChange}
92
- onClear={onClear}
93
- searchHeaderHeight={searchHeaderHeight}
94
108
  />
95
- <Box
96
- ref={listRef}
97
- sx={
98
- inExpansion ? { height: listContainerHeight, overflow: 'auto' } : {}
99
- }
100
- >
101
- <ChainList
102
- parentRef={listRef}
103
- chains={filteredChains}
104
- isLoading={isLoading}
105
- onSelect={onSelect ?? onSelectChainFallback}
106
- selectedChainId={selectedChainId}
107
- inExpansion={inExpansion}
108
- />
109
- </Box>
110
- </FullPageContainer>
111
- )
112
- }
113
- )
109
+ </Box>
110
+ </FullPageContainer>
111
+ )
112
+ })
@@ -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
 
@@ -0,0 +1,43 @@
1
+ import { Box, styled } from '@mui/material'
2
+
3
+ export const animationDuration = 225
4
+
5
+ export const defaultStyle = {
6
+ opacity: 0,
7
+ whiteSpace: 'nowrap',
8
+ transform: 'translateX(-100%)',
9
+ display: 'inline-block',
10
+ position: 'absolute' as const,
11
+ top: 0,
12
+ left: 0,
13
+ transition: `opacity ${animationDuration}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${animationDuration}ms cubic-bezier(0.4, 0, 0.2, 1)`,
14
+ }
15
+
16
+ export const transitionStyles = {
17
+ entering: {
18
+ opacity: 1,
19
+ transform: 'translateX(0)',
20
+ },
21
+ entered: {
22
+ opacity: 1,
23
+ transform: 'translateX(0)',
24
+ },
25
+ exiting: {
26
+ opacity: 0,
27
+ transform: 'translateX(-100%)',
28
+ },
29
+ exited: {
30
+ opacity: 0,
31
+ transform: 'translateX(-100%)',
32
+ },
33
+ }
34
+
35
+ export const ExpansionContainer = styled(Box, {
36
+ shouldForwardProp: (prop) => prop !== 'width',
37
+ })<{ width: string | number }>(({ width }) => ({
38
+ position: 'relative',
39
+ display: 'flex',
40
+ transition: `width ${animationDuration}ms cubic-bezier(0.4, 0, 0.2, 1)`,
41
+ width: width,
42
+ marginLeft: width ? '24px' : 0,
43
+ }))
@@ -1,23 +1,17 @@
1
- import { Box } from '@mui/material'
2
- import { useCallback, useMemo, useRef, useState } from 'react'
1
+ import { useMemo, useRef, useState } from 'react'
3
2
  import { useHasChainExpansion } from '../../hooks/useHasChainExpansion'
4
3
  import { ExpansionType } from '../../types/widget'
5
4
  import { ChainsExpanded } from '../Chains/ChainsExpanded'
6
5
  import { chainExpansionWidth } from '../Chains/ChainsExpanded.style'
7
6
  import { RoutesExpanded } from '../Routes/RoutesExpanded'
8
7
  import { routesExpansionWidth } from '../Routes/RoutesExpanded.style'
9
- import { animationDuration } from './ExpansionTransition'
8
+ import { ExpansionContainer } from './Expansion.style'
10
9
 
11
10
  export function Expansion() {
12
11
  const [withChainExpansion, expansionType] = useHasChainExpansion()
13
12
  const chainExpansionTypeRef = useRef<ExpansionType>(expansionType)
14
-
15
13
  const [routesOpen, setRoutesOpen] = useState(false)
16
14
 
17
- const handleSetRoutesOpen = useCallback((open: boolean) => {
18
- setRoutesOpen(open)
19
- }, [])
20
-
21
15
  // Track the previous chain expansion type to avoid re-renders when transitioning to Routes
22
16
  if (
23
17
  expansionType === ExpansionType.FromChain ||
@@ -26,28 +20,19 @@ export function Expansion() {
26
20
  chainExpansionTypeRef.current = expansionType
27
21
  }
28
22
 
29
- const boxWidth = useMemo(() => {
23
+ const containerWidth = useMemo(() => {
30
24
  return routesOpen
31
25
  ? routesExpansionWidth
32
26
  : withChainExpansion
33
27
  ? chainExpansionWidth
34
- : '0px'
28
+ : 0
35
29
  }, [routesOpen, withChainExpansion])
36
30
 
37
31
  return (
38
- <Box
39
- sx={{
40
- position: 'relative',
41
- display: 'flex',
42
- transition: `width ${animationDuration}ms cubic-bezier(0.4, 0, 0.2, 1)`,
43
- width: boxWidth,
44
- willChange: 'width',
45
- marginLeft: boxWidth !== '0px' ? '24px' : '0px',
46
- }}
47
- >
32
+ <ExpansionContainer width={containerWidth}>
48
33
  <RoutesExpanded
49
- expansionType={expansionType}
50
- setOpenExpansion={handleSetRoutesOpen}
34
+ canOpen={expansionType === ExpansionType.Routes}
35
+ setOpenExpansion={setRoutesOpen}
51
36
  />
52
37
  <ChainsExpanded
53
38
  formType={
@@ -57,6 +42,6 @@ export function Expansion() {
57
42
  }
58
43
  open={withChainExpansion}
59
44
  />
60
- </Box>
45
+ </ExpansionContainer>
61
46
  )
62
47
  }
@@ -1,39 +1,11 @@
1
1
  import { Box } from '@mui/material'
2
2
  import { type PropsWithChildren, useRef } from 'react'
3
3
  import { Transition } from 'react-transition-group'
4
-
5
- export const animationDuration = 225
6
-
7
- const defaultStyle = {
8
- opacity: 0,
9
- whiteSpace: 'nowrap',
10
- transform: 'translateX(-100%)',
11
- display: 'inline-block',
12
- position: 'absolute' as const,
13
- top: 0,
14
- left: 0,
15
- willChange: 'opacity, transform',
16
- transition: `opacity ${animationDuration}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${animationDuration}ms cubic-bezier(0.4, 0, 0.2, 1)`,
17
- }
18
-
19
- const transitionStyles = {
20
- entering: {
21
- opacity: 1,
22
- transform: 'translateX(0)',
23
- },
24
- entered: {
25
- opacity: 1,
26
- transform: 'translateX(0)',
27
- },
28
- exiting: {
29
- opacity: 0,
30
- transform: 'translateX(-100%)',
31
- },
32
- exited: {
33
- opacity: 0,
34
- transform: 'translateX(-100%)',
35
- },
36
- }
4
+ import {
5
+ animationDuration,
6
+ defaultStyle,
7
+ transitionStyles,
8
+ } from './Expansion.style'
37
9
 
38
10
  interface ExpansionTransitionProps {
39
11
  in: boolean
@@ -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
@@ -1,15 +1,11 @@
1
1
  import type { ExtendedChain, Route } from '@lifi/sdk'
2
2
  import { useAccount } from '@lifi/wallet-management'
3
3
  import { Stack, Typography } from '@mui/material'
4
- import { useEffect } from 'react'
4
+ import { memo } from 'react'
5
5
  import { useTranslation } from 'react-i18next'
6
- import { useNavigate } from 'react-router-dom'
7
6
  import { useToAddressRequirements } from '../../hooks/useToAddressRequirements.js'
8
- import { useWidgetEvents } from '../../hooks/useWidgetEvents.js'
9
7
  import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'
10
8
  import { useFieldValues } from '../../stores/form/useFieldValues.js'
11
- import { WidgetEvent } from '../../types/events.js'
12
- import { navigationRoutes } from '../../utils/navigationRoutes.js'
13
9
  import { PageContainer } from '../PageContainer.js'
14
10
  import { ProgressToNextUpdate } from '../ProgressToNextUpdate.js'
15
11
  import { RouteCard } from '../RouteCard/RouteCard.js'
@@ -21,53 +17,38 @@ interface RoutesContentProps {
21
17
  routes: Route[]
22
18
  isFetching: boolean
23
19
  isLoading: boolean
24
- expanded: boolean
25
- setReviewableRoute: (route: Route) => void
26
20
  dataUpdatedAt: number
27
21
  refetchTime: number
28
22
  fromChain: ExtendedChain | undefined
29
23
  refetch: () => void
24
+ onRouteClick: (route: Route) => void
30
25
  }
31
26
 
32
- export const RoutesContent = ({
27
+ const headerHeight = '64px'
28
+
29
+ export const RoutesContent = memo(function RoutesContent({
33
30
  routes,
34
31
  isFetching,
35
32
  isLoading,
36
- expanded,
37
- setReviewableRoute,
38
33
  dataUpdatedAt,
39
34
  refetchTime,
40
35
  fromChain,
41
36
  refetch,
42
- }: RoutesContentProps) => {
37
+ onRouteClick,
38
+ }: RoutesContentProps) {
43
39
  const { t } = useTranslation()
44
-
45
- const navigate = useNavigate()
46
40
  const { subvariant, subvariantOptions } = useWidgetConfig()
47
41
 
48
42
  const { account } = useAccount({ chainType: fromChain?.chainType })
49
43
  const [toAddress] = useFieldValues('toAddress')
50
44
  const { requiredToAddress } = useToAddressRequirements()
51
45
 
52
- const emitter = useWidgetEvents()
53
-
54
- const handleRouteClick = (route: Route) => {
55
- setReviewableRoute(route)
56
- navigate(navigationRoutes.transactionExecution, {
57
- state: { routeId: route.id },
58
- })
59
- emitter.emit(WidgetEvent.RouteSelected, { route, routes: routes! })
60
- }
61
46
  const currentRoute = routes?.[0]
62
47
 
63
- const routeNotFound = !currentRoute && !isLoading && !isFetching && expanded
48
+ const routeNotFound = !currentRoute && !isLoading && !isFetching
64
49
  const toAddressUnsatisfied = currentRoute && requiredToAddress && !toAddress
65
50
  const allowInteraction = account.isConnected && !toAddressUnsatisfied
66
51
 
67
- useEffect(() => {
68
- emitter.emit(WidgetEvent.WidgetExpanded, expanded)
69
- }, [emitter, expanded])
70
-
71
52
  const title =
72
53
  subvariant === 'custom'
73
54
  ? subvariantOptions?.custom === 'deposit'
@@ -77,7 +58,7 @@ export const RoutesContent = ({
77
58
 
78
59
  return (
79
60
  <Container enableColorScheme minimumHeight={isLoading}>
80
- <Header>
61
+ <Header sx={{ height: headerHeight }}>
81
62
  <Typography
82
63
  noWrap
83
64
  sx={{
@@ -96,7 +77,9 @@ export const RoutesContent = ({
96
77
  sx={{ marginRight: -1 }}
97
78
  />
98
79
  </Header>
99
- <PageContainer>
80
+ <PageContainer
81
+ sx={{ height: `calc(100% - ${headerHeight})`, overflow: 'auto' }}
82
+ >
100
83
  <Stack
101
84
  direction="column"
102
85
  spacing={2}
@@ -117,7 +100,7 @@ export const RoutesContent = ({
117
100
  key={index}
118
101
  route={route}
119
102
  onClick={
120
- allowInteraction ? () => handleRouteClick(route) : undefined
103
+ allowInteraction ? () => onRouteClick(route) : undefined
121
104
  }
122
105
  active={index === 0}
123
106
  expanded={routes?.length === 1}
@@ -128,4 +111,4 @@ export const RoutesContent = ({
128
111
  </PageContainer>
129
112
  </Container>
130
113
  )
131
- }
114
+ })
@@ -11,8 +11,9 @@ interface ContainerProps extends ScopedCssBaselineProps {
11
11
  export const Container = styled(ScopedCssBaseline, {
12
12
  shouldForwardProp: (prop) => !['minimumHeight'].includes(prop as string),
13
13
  })<ContainerProps>(({ theme, minimumHeight }) => ({
14
+ ...theme.container,
14
15
  backgroundColor: theme.vars.palette.background.default,
15
- overflow: 'auto',
16
+ overflow: 'hidden',
16
17
  width: routesExpansionWidth,
17
18
  display: 'flex',
18
19
  flexDirection: 'column',
@@ -26,7 +27,6 @@ export const Container = styled(ScopedCssBaseline, {
26
27
  ...(minimumHeight ? { '&': { height: 'auto' } } : {}),
27
28
  }
28
29
  : { height: minimumHeight ? 'auto' : '100%' }),
29
- ...theme.container,
30
30
  ...theme.routesContainer,
31
31
  }))
32
32
 
@@ -1,23 +1,28 @@
1
1
  import type { Route } from '@lifi/sdk'
2
- import { useEffect, useRef } from 'react'
2
+ import { memo, useCallback, useEffect, useLayoutEffect, useRef } from 'react'
3
+ import { useNavigate } from 'react-router-dom'
3
4
  import { useRoutes } from '../../hooks/useRoutes.js'
4
- import { ExpansionType } from '../../types/widget.js'
5
+ import { useWidgetEvents } from '../../hooks/useWidgetEvents.js'
6
+ import { WidgetEvent } from '../../types/events.js'
7
+ import { navigationRoutes } from '../../utils/navigationRoutes.js'
5
8
  import { ExpansionTransition } from '../Expansion/ExpansionTransition.js'
6
9
  import { RoutesContent } from './RoutesContent.js'
7
10
  import { routesExpansionWidth } from './RoutesExpanded.style.js'
8
11
 
9
12
  interface RoutesExpandedProps {
10
- expansionType: ExpansionType
13
+ canOpen: boolean
11
14
  setOpenExpansion: (open: boolean) => void
12
15
  }
13
16
 
14
- export const RoutesExpanded = ({
15
- expansionType,
17
+ export const RoutesExpanded = memo(function RoutesExpanded({
18
+ canOpen,
16
19
  setOpenExpansion,
17
- }: RoutesExpandedProps) => {
20
+ }: RoutesExpandedProps) {
21
+ const emitter = useWidgetEvents()
22
+ const navigate = useNavigate()
18
23
  const routesRef = useRef<Route[]>(undefined)
19
-
20
24
  const routesActiveRef = useRef(false)
25
+
21
26
  const {
22
27
  routes,
23
28
  isLoading,
@@ -45,13 +50,29 @@ export const RoutesExpanded = ({
45
50
 
46
51
  const expanded =
47
52
  Boolean(routesActiveRef.current || isLoading || isFetching || isFetched) &&
48
- expansionType === ExpansionType.Routes
53
+ canOpen
49
54
 
50
- useEffect(() => {
51
- // To update parent's width when expansion changes
55
+ // biome-ignore lint/correctness/useExhaustiveDependencies: stable navigation callback that won't cause rerenders in RoutesContent
56
+ const onRouteClick = useCallback(
57
+ (route: Route) => {
58
+ setReviewableRoute(route)
59
+ navigate(navigationRoutes.transactionExecution, {
60
+ state: { routeId: route.id },
61
+ })
62
+ emitter.emit(WidgetEvent.RouteSelected, { route, routes: routes! })
63
+ },
64
+ [emitter, routes, setReviewableRoute]
65
+ )
66
+
67
+ // Use layout effect to update parent's width when expansion changes
68
+ useLayoutEffect(() => {
52
69
  setOpenExpansion(expanded)
53
70
  }, [expanded, setOpenExpansion])
54
71
 
72
+ useEffect(() => {
73
+ emitter.emit(WidgetEvent.WidgetExpanded, expanded)
74
+ }, [emitter, expanded])
75
+
55
76
  return (
56
77
  <ExpansionTransition
57
78
  in={expanded}
@@ -62,13 +83,12 @@ export const RoutesExpanded = ({
62
83
  routes={routesRef.current || []}
63
84
  isFetching={isFetching}
64
85
  isLoading={isLoading}
65
- expanded={expanded}
66
- setReviewableRoute={setReviewableRoute}
67
86
  dataUpdatedAt={dataUpdatedAt}
68
87
  refetchTime={refetchTime}
69
88
  fromChain={fromChain}
70
89
  refetch={refetch}
90
+ onRouteClick={onRouteClick}
71
91
  />
72
92
  </ExpansionTransition>
73
93
  )
74
- }
94
+ })