@lifi/widget 4.5.0 → 4.6.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 (199) hide show
  1. package/dist/esm/AppDrawer.js +2 -1
  2. package/dist/esm/AppDrawer.js.map +1 -1
  3. package/dist/esm/components/AmountInput/AmountInput.js +13 -7
  4. package/dist/esm/components/AmountInput/AmountInput.js.map +1 -1
  5. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +2 -13
  6. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
  7. package/dist/esm/components/AmountInputCard/PercentageChips.js +2 -13
  8. package/dist/esm/components/AmountInputCard/PercentageChips.js.map +1 -1
  9. package/dist/esm/components/AmountInputCard/PercentageChips.style.js +1 -1
  10. package/dist/esm/components/AmountInputCard/PercentageChips.style.js.map +1 -1
  11. package/dist/esm/components/AmountInputCard/SendAmountCard.js +13 -6
  12. package/dist/esm/components/AmountInputCard/SendAmountCard.js.map +1 -1
  13. package/dist/esm/components/Chains/AllChainsAvatar.js +7 -1
  14. package/dist/esm/components/Chains/AllChainsAvatar.js.map +1 -1
  15. package/dist/esm/components/Dialog/Dialog.js +2 -1
  16. package/dist/esm/components/Dialog/Dialog.js.map +1 -1
  17. package/dist/esm/components/Expansion/Expansion.js +4 -3
  18. package/dist/esm/components/Expansion/Expansion.js.map +1 -1
  19. package/dist/esm/components/Header/SettingsButton.js +2 -1
  20. package/dist/esm/components/Header/SettingsButton.js.map +1 -1
  21. package/dist/esm/components/IconCircle/IconCircle.js +2 -1
  22. package/dist/esm/components/IconCircle/IconCircle.js.map +1 -1
  23. package/dist/esm/components/Messages/UnsupportedToAddressMessage.js +27 -0
  24. package/dist/esm/components/Messages/UnsupportedToAddressMessage.js.map +1 -0
  25. package/dist/esm/components/Messages/WarningMessages.d.ts.map +1 -1
  26. package/dist/esm/components/Messages/WarningMessages.js +2 -0
  27. package/dist/esm/components/Messages/WarningMessages.js.map +1 -1
  28. package/dist/esm/components/Messages/useMessageQueue.js +6 -1
  29. package/dist/esm/components/Messages/useMessageQueue.js.map +1 -1
  30. package/dist/esm/components/RouteCard/RouteDetails.js +2 -1
  31. package/dist/esm/components/RouteCard/RouteDetails.js.map +1 -1
  32. package/dist/esm/components/Routes/LimitOrderRoutes.js +2 -2
  33. package/dist/esm/components/Routes/LimitOrderRoutes.js.map +1 -1
  34. package/dist/esm/components/Routes/RoutesContent.js +2 -2
  35. package/dist/esm/components/Routes/RoutesContent.js.map +1 -1
  36. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js +2 -2
  37. package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js.map +1 -1
  38. package/dist/esm/components/Skeleton/WidgetSkeleton.js +2 -1
  39. package/dist/esm/components/Skeleton/WidgetSkeleton.js.map +1 -1
  40. package/dist/esm/components/Step/StepActions.js +18 -16
  41. package/dist/esm/components/Step/StepActions.js.map +1 -1
  42. package/dist/esm/components/StepActions/StepActionRow.js +2 -1
  43. package/dist/esm/components/StepActions/StepActionRow.js.map +1 -1
  44. package/dist/esm/components/Switch.js +1 -1
  45. package/dist/esm/components/Switch.js.map +1 -1
  46. package/dist/esm/components/Tabs/Tabs.style.js +4 -2
  47. package/dist/esm/components/Tabs/Tabs.style.js.map +1 -1
  48. package/dist/esm/components/TokenList/TokenListItem.js +46 -8
  49. package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
  50. package/dist/esm/components/TokenList/VirtualizedTokenList.js +22 -9
  51. package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
  52. package/dist/esm/components/TokenRate/TokenRate.js +2 -1
  53. package/dist/esm/components/TokenRate/TokenRate.js.map +1 -1
  54. package/dist/esm/components/TransactionCard/ActiveTransactionCard.js +22 -21
  55. package/dist/esm/components/TransactionCard/ActiveTransactionCard.js.map +1 -1
  56. package/dist/esm/config/version.d.ts +1 -1
  57. package/dist/esm/config/version.js +1 -1
  58. package/dist/esm/config/version.js.map +1 -1
  59. package/dist/esm/hooks/timer/time.js +2 -2
  60. package/dist/esm/hooks/timer/time.js.map +1 -1
  61. package/dist/esm/hooks/useAvailableChains.d.ts.map +1 -1
  62. package/dist/esm/hooks/useAvailableChains.js +2 -1
  63. package/dist/esm/hooks/useAvailableChains.js.map +1 -1
  64. package/dist/esm/hooks/useExplorer.d.ts.map +1 -1
  65. package/dist/esm/hooks/useExplorer.js +4 -0
  66. package/dist/esm/hooks/useExplorer.js.map +1 -1
  67. package/dist/esm/hooks/useFlaggedTokenGuard.js +28 -0
  68. package/dist/esm/hooks/useFlaggedTokenGuard.js.map +1 -0
  69. package/dist/esm/hooks/useGasSufficiency.js +3 -1
  70. package/dist/esm/hooks/useGasSufficiency.js.map +1 -1
  71. package/dist/esm/hooks/useMaxSendAmount.js +15 -0
  72. package/dist/esm/hooks/useMaxSendAmount.js.map +1 -0
  73. package/dist/esm/hooks/usePacedRouteExecution.js +3 -2
  74. package/dist/esm/hooks/usePacedRouteExecution.js.map +1 -1
  75. package/dist/esm/hooks/useRouteExecutionMessage.js +3 -2
  76. package/dist/esm/hooks/useRouteExecutionMessage.js.map +1 -1
  77. package/dist/esm/hooks/useRoutes.d.ts.map +1 -1
  78. package/dist/esm/hooks/useRoutes.js +3 -1
  79. package/dist/esm/hooks/useRoutes.js.map +1 -1
  80. package/dist/esm/hooks/useToAddressRequirements.d.ts +2 -0
  81. package/dist/esm/hooks/useToAddressRequirements.d.ts.map +1 -1
  82. package/dist/esm/hooks/useToAddressRequirements.js +7 -1
  83. package/dist/esm/hooks/useToAddressRequirements.js.map +1 -1
  84. package/dist/esm/hooks/useTokenBalances.d.ts.map +1 -1
  85. package/dist/esm/hooks/useTokenBalances.js +7 -2
  86. package/dist/esm/hooks/useTokenBalances.js.map +1 -1
  87. package/dist/esm/hooks/useTokenBalancesQueries.js +29 -28
  88. package/dist/esm/hooks/useTokenBalancesQueries.js.map +1 -1
  89. package/dist/esm/hooks/useTokenSearch.js +3 -5
  90. package/dist/esm/hooks/useTokenSearch.js.map +1 -1
  91. package/dist/esm/hooks/useTokens.js +14 -10
  92. package/dist/esm/hooks/useTokens.js.map +1 -1
  93. package/dist/esm/hooks/useWideVariant.js +2 -1
  94. package/dist/esm/hooks/useWideVariant.js.map +1 -1
  95. package/dist/esm/i18n/bn.json +3 -1
  96. package/dist/esm/i18n/de.json +3 -1
  97. package/dist/esm/i18n/en.json +12 -3
  98. package/dist/esm/i18n/es.json +3 -1
  99. package/dist/esm/i18n/fr.json +3 -1
  100. package/dist/esm/i18n/hi.json +3 -1
  101. package/dist/esm/i18n/id.json +3 -1
  102. package/dist/esm/i18n/it.json +3 -1
  103. package/dist/esm/i18n/ja.json +3 -1
  104. package/dist/esm/i18n/ko.json +3 -1
  105. package/dist/esm/i18n/pl.json +3 -1
  106. package/dist/esm/i18n/pt.json +3 -1
  107. package/dist/esm/i18n/th.json +3 -1
  108. package/dist/esm/i18n/tr.json +3 -1
  109. package/dist/esm/i18n/uk.json +3 -1
  110. package/dist/esm/i18n/vi.json +3 -1
  111. package/dist/esm/i18n/zh.json +3 -1
  112. package/dist/esm/pages/MainPage/MainPage.js +2 -1
  113. package/dist/esm/pages/MainPage/MainPage.js.map +1 -1
  114. package/dist/esm/pages/MainPage/ReviewButton.js +2 -2
  115. package/dist/esm/pages/MainPage/ReviewButton.js.map +1 -1
  116. package/dist/esm/pages/RoutesPage/RoutesPage.js +2 -2
  117. package/dist/esm/pages/RoutesPage/RoutesPage.js.map +1 -1
  118. package/dist/esm/pages/SelectChainPage/SelectChainPage.js +13 -12
  119. package/dist/esm/pages/SelectChainPage/SelectChainPage.js.map +1 -1
  120. package/dist/esm/pages/SelectEnabledToolsPage.js +8 -5
  121. package/dist/esm/pages/SelectEnabledToolsPage.js.map +1 -1
  122. package/dist/esm/pages/SelectTokenPage/SelectTokenPage.js +2 -1
  123. package/dist/esm/pages/SelectTokenPage/SelectTokenPage.js.map +1 -1
  124. package/dist/esm/pages/SettingsPage/SmallBalanceFilterSettings.js +2 -1
  125. package/dist/esm/pages/SettingsPage/SmallBalanceFilterSettings.js.map +1 -1
  126. package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.js +2 -1
  127. package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.js.map +1 -1
  128. package/dist/esm/pages/TransactionDetailsPage/TransactionDetailsPage.js +2 -1
  129. package/dist/esm/pages/TransactionDetailsPage/TransactionDetailsPage.js.map +1 -1
  130. package/dist/esm/pages/TransactionPage/StartTransactionButton.js +4 -3
  131. package/dist/esm/pages/TransactionPage/StartTransactionButton.js.map +1 -1
  132. package/dist/esm/pages/TransactionPage/TokenVerificationBottomSheet.js +64 -0
  133. package/dist/esm/pages/TransactionPage/TokenVerificationBottomSheet.js.map +1 -0
  134. package/dist/esm/pages/TransactionPage/TransactionExecutionContent.js +19 -16
  135. package/dist/esm/pages/TransactionPage/TransactionExecutionContent.js.map +1 -1
  136. package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js +3 -1
  137. package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js.map +1 -1
  138. package/dist/esm/pages/TransactionPage/TransactionReview.js +24 -2
  139. package/dist/esm/pages/TransactionPage/TransactionReview.js.map +1 -1
  140. package/dist/esm/providers/I18nProvider/I18nProvider.js +37 -36
  141. package/dist/esm/providers/I18nProvider/I18nProvider.js.map +1 -1
  142. package/dist/esm/providers/ThemeProvider/ThemeProvider.js +2 -1
  143. package/dist/esm/providers/ThemeProvider/ThemeProvider.js.map +1 -1
  144. package/dist/esm/providers/WalletProvider/WalletProvider.js +10 -9
  145. package/dist/esm/providers/WalletProvider/WalletProvider.js.map +1 -1
  146. package/dist/esm/providers/WalletProvider/useExternalWalletProvider.js +7 -3
  147. package/dist/esm/providers/WalletProvider/useExternalWalletProvider.js.map +1 -1
  148. package/dist/esm/stores/routes/useRouteExecutionIndicator.js +4 -3
  149. package/dist/esm/stores/routes/useRouteExecutionIndicator.js.map +1 -1
  150. package/dist/esm/types/token.d.ts +4 -1
  151. package/dist/esm/types/token.d.ts.map +1 -1
  152. package/dist/esm/utils/compactNumberFormatter.js +1 -3
  153. package/dist/esm/utils/compactNumberFormatter.js.map +1 -1
  154. package/dist/esm/utils/customReceiver.js +7 -0
  155. package/dist/esm/utils/customReceiver.js.map +1 -0
  156. package/dist/esm/utils/gas.js +24 -0
  157. package/dist/esm/utils/gas.js.map +1 -0
  158. package/dist/esm/utils/getErrorMessage.js +0 -1
  159. package/dist/esm/utils/getErrorMessage.js.map +1 -1
  160. package/dist/esm/utils/limitOrder.js +1 -1
  161. package/dist/esm/utils/limitOrder.js.map +1 -1
  162. package/dist/esm/utils/token.js +21 -4
  163. package/dist/esm/utils/token.js.map +1 -1
  164. package/dist/esm/utils/tokenList.js +38 -21
  165. package/dist/esm/utils/tokenList.js.map +1 -1
  166. package/package.json +15 -15
  167. package/src/components/AmountInput/AmountInputEndAdornment.tsx +2 -21
  168. package/src/components/AmountInputCard/PercentageChips.tsx +2 -18
  169. package/src/components/Chains/AllChainsAvatar.tsx +7 -1
  170. package/src/components/Messages/UnsupportedToAddressMessage.tsx +24 -0
  171. package/src/components/Messages/WarningMessages.tsx +3 -0
  172. package/src/components/Messages/useMessageQueue.ts +9 -0
  173. package/src/components/Routes/LimitOrderRoutes.tsx +5 -2
  174. package/src/components/Routes/RoutesContent.tsx +5 -2
  175. package/src/components/SendToWallet/SendToWalletExpandButton.tsx +2 -1
  176. package/src/components/TokenList/TokenListItem.tsx +68 -9
  177. package/src/components/TokenList/VirtualizedTokenList.tsx +33 -9
  178. package/src/components/TokenList/types.ts +4 -0
  179. package/src/config/version.ts +1 -1
  180. package/src/hooks/useAvailableChains.ts +1 -0
  181. package/src/hooks/useExplorer.ts +2 -0
  182. package/src/hooks/useFlaggedTokenGuard.ts +33 -0
  183. package/src/hooks/useGasSufficiency.ts +9 -1
  184. package/src/hooks/useMaxSendAmount.ts +21 -0
  185. package/src/hooks/useRoutes.ts +7 -0
  186. package/src/hooks/useToAddressRequirements.ts +17 -1
  187. package/src/hooks/useTokenBalances.ts +18 -2
  188. package/src/hooks/useTokenSearch.ts +1 -5
  189. package/src/hooks/useTokens.ts +28 -13
  190. package/src/pages/MainPage/ReviewButton.tsx +6 -2
  191. package/src/pages/RoutesPage/RoutesPage.tsx +5 -2
  192. package/src/pages/TransactionPage/TokenVerificationBottomSheet.tsx +93 -0
  193. package/src/pages/TransactionPage/TransactionReview.tsx +28 -1
  194. package/src/providers/WalletProvider/useExternalWalletProvider.ts +9 -1
  195. package/src/types/token.ts +6 -3
  196. package/src/utils/customReceiver.ts +7 -0
  197. package/src/utils/gas.ts +41 -0
  198. package/src/utils/token.ts +53 -9
  199. package/src/utils/tokenList.ts +28 -0
@@ -32,8 +32,9 @@ const AppDrawer = ({ elementRef, open, onClose, children, ref }) => {
32
32
  openDrawer,
33
33
  toggleDrawer
34
34
  ]);
35
+ const drawerContext = useMemo(() => ({ closeDrawer }), [closeDrawer]);
35
36
  return /* @__PURE__ */ jsx(DrawerContext, {
36
- value: useMemo(() => ({ closeDrawer }), [closeDrawer]),
37
+ value: drawerContext,
37
38
  children: /* @__PURE__ */ jsx(Drawer, {
38
39
  ref: elementRef,
39
40
  anchor: "right",
@@ -1 +1 @@
1
- {"version":3,"file":"AppDrawer.js","names":[],"sources":["../../src/AppDrawer.tsx"],"sourcesContent":["import { Drawer } from '@mui/material'\nimport type { JSX, PropsWithChildren, Ref } from 'react'\nimport {\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport type { WidgetDrawerContext } from './AppDrawerContext.js'\nimport { DrawerContext } from './AppDrawerContext.js'\nimport type { WidgetDrawerProps } from './types/widget.js'\n\nexport interface WidgetDrawer {\n isOpen(): void\n toggleDrawer(): void\n openDrawer(): void\n closeDrawer(): void\n}\n\nexport const AppDrawer = ({\n elementRef,\n open,\n onClose,\n children,\n ref,\n}: PropsWithChildren<WidgetDrawerProps> & {\n ref?: Ref<WidgetDrawer>\n}): JSX.Element => {\n const openRef = useRef(Boolean(open))\n const [drawerOpen, setDrawerOpen] = useState(Boolean(open))\n\n const toggleDrawer = useCallback(() => {\n setDrawerOpen((open) => {\n openRef.current = !open\n return openRef.current\n })\n if (!openRef.current) {\n onClose?.()\n }\n }, [onClose])\n\n const openDrawer = useCallback(() => {\n setDrawerOpen(true)\n openRef.current = true\n }, [])\n\n const closeDrawer = useCallback(() => {\n setDrawerOpen(false)\n openRef.current = false\n onClose?.()\n }, [onClose])\n\n useImperativeHandle(\n ref,\n () => ({\n isOpen: () => openRef.current,\n toggleDrawer,\n openDrawer,\n closeDrawer,\n }),\n [closeDrawer, openDrawer, toggleDrawer]\n )\n\n const drawerContext: WidgetDrawerContext = useMemo(\n () => ({\n closeDrawer,\n }),\n [closeDrawer]\n )\n\n return (\n <DrawerContext value={drawerContext}>\n <Drawer\n ref={elementRef}\n anchor=\"right\"\n open={drawerOpen}\n onClose={closeDrawer}\n slotProps={{\n paper: {\n sx: (theme) => ({\n background: theme.vars.palette.background.default,\n width: theme?.container?.width ?? '100%',\n minWidth:\n theme?.container?.minWidth ?? theme.breakpoints.values.xs,\n maxWidth:\n theme?.container?.maxWidth ?? theme.breakpoints.values.sm,\n }),\n },\n backdrop: {\n sx: {\n backgroundColor: 'rgb(0 0 0 / 48%)',\n backdropFilter: 'blur(3px)',\n },\n },\n }}\n keepMounted\n >\n {children}\n </Drawer>\n </DrawerContext>\n )\n}\n"],"mappings":";;;;;AAoBA,MAAa,aAAa,EACxB,YACA,MACA,SACA,UACA,UAGiB;CACjB,MAAM,UAAU,OAAO,QAAQ,IAAI,CAAC;CACpC,MAAM,CAAC,YAAY,iBAAiB,SAAS,QAAQ,IAAI,CAAC;CAE1D,MAAM,eAAe,kBAAkB;EACrC,eAAe,SAAS;GACtB,QAAQ,UAAU,CAAC;GACnB,OAAO,QAAQ;EACjB,CAAC;EACD,IAAI,CAAC,QAAQ,SACX,UAAU;CAEd,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,aAAa,kBAAkB;EACnC,cAAc,IAAI;EAClB,QAAQ,UAAU;CACpB,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,kBAAkB;EACpC,cAAc,KAAK;EACnB,QAAQ,UAAU;EAClB,UAAU;CACZ,GAAG,CAAC,OAAO,CAAC;CAEZ,oBACE,YACO;EACL,cAAc,QAAQ;EACtB;EACA;EACA;CACF,IACA;EAAC;EAAa;EAAY;CAAY,CACxC;CASA,OACE,oBAAC,eAAD;EAAe,OAR0B,eAClC,EACL,YACF,IACA,CAAC,WAAW,CAIsB;EAChC,UAAA,oBAAC,QAAD;GACE,KAAK;GACL,QAAO;GACP,MAAM;GACN,SAAS;GACT,WAAW;IACT,OAAO,EACL,KAAK,WAAW;KACd,YAAY,MAAM,KAAK,QAAQ,WAAW;KAC1C,OAAO,OAAO,WAAW,SAAS;KAClC,UACE,OAAO,WAAW,YAAY,MAAM,YAAY,OAAO;KACzD,UACE,OAAO,WAAW,YAAY,MAAM,YAAY,OAAO;IAC3D,GACF;IACA,UAAU,EACR,IAAI;KACF,iBAAiB;KACjB,gBAAgB;IAClB,EACF;GACF;GACA,aAAA;GAEC;EACK,CAAA;CACK,CAAA;AAEnB"}
1
+ {"version":3,"file":"AppDrawer.js","names":[],"sources":["../../src/AppDrawer.tsx"],"sourcesContent":["import { Drawer } from '@mui/material'\nimport type { JSX, PropsWithChildren, Ref } from 'react'\nimport {\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport type { WidgetDrawerContext } from './AppDrawerContext.js'\nimport { DrawerContext } from './AppDrawerContext.js'\nimport type { WidgetDrawerProps } from './types/widget.js'\n\nexport interface WidgetDrawer {\n isOpen(): void\n toggleDrawer(): void\n openDrawer(): void\n closeDrawer(): void\n}\n\nexport const AppDrawer = ({\n elementRef,\n open,\n onClose,\n children,\n ref,\n}: PropsWithChildren<WidgetDrawerProps> & {\n ref?: Ref<WidgetDrawer>\n}): JSX.Element => {\n const openRef = useRef(Boolean(open))\n const [drawerOpen, setDrawerOpen] = useState(Boolean(open))\n\n const toggleDrawer = useCallback(() => {\n setDrawerOpen((open) => {\n openRef.current = !open\n return openRef.current\n })\n if (!openRef.current) {\n onClose?.()\n }\n }, [onClose])\n\n const openDrawer = useCallback(() => {\n setDrawerOpen(true)\n openRef.current = true\n }, [])\n\n const closeDrawer = useCallback(() => {\n setDrawerOpen(false)\n openRef.current = false\n onClose?.()\n }, [onClose])\n\n useImperativeHandle(\n ref,\n () => ({\n isOpen: () => openRef.current,\n toggleDrawer,\n openDrawer,\n closeDrawer,\n }),\n [closeDrawer, openDrawer, toggleDrawer]\n )\n\n const drawerContext: WidgetDrawerContext = useMemo(\n () => ({\n closeDrawer,\n }),\n [closeDrawer]\n )\n\n return (\n <DrawerContext value={drawerContext}>\n <Drawer\n ref={elementRef}\n anchor=\"right\"\n open={drawerOpen}\n onClose={closeDrawer}\n slotProps={{\n paper: {\n sx: (theme) => ({\n background: theme.vars.palette.background.default,\n width: theme?.container?.width ?? '100%',\n minWidth:\n theme?.container?.minWidth ?? theme.breakpoints.values.xs,\n maxWidth:\n theme?.container?.maxWidth ?? theme.breakpoints.values.sm,\n }),\n },\n backdrop: {\n sx: {\n backgroundColor: 'rgb(0 0 0 / 48%)',\n backdropFilter: 'blur(3px)',\n },\n },\n }}\n keepMounted\n >\n {children}\n </Drawer>\n </DrawerContext>\n )\n}\n"],"mappings":";;;;;AAoBA,MAAa,aAAa,EACxB,YACA,MACA,SACA,UACA,UAGiB;CACjB,MAAM,UAAU,OAAO,QAAQ,IAAI,CAAC;CACpC,MAAM,CAAC,YAAY,iBAAiB,SAAS,QAAQ,IAAI,CAAC;CAE1D,MAAM,eAAe,kBAAkB;EACrC,eAAe,SAAS;GACtB,QAAQ,UAAU,CAAC;GACnB,OAAO,QAAQ;EACjB,CAAC;EACD,IAAI,CAAC,QAAQ,SACX,UAAU;CAEd,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,aAAa,kBAAkB;EACnC,cAAc,IAAI;EAClB,QAAQ,UAAU;CACpB,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,kBAAkB;EACpC,cAAc,KAAK;EACnB,QAAQ,UAAU;EAClB,UAAU;CACZ,GAAG,CAAC,OAAO,CAAC;CAEZ,oBACE,YACO;EACL,cAAc,QAAQ;EACtB;EACA;EACA;CACF,IACA;EAAC;EAAa;EAAY;CAAY,CACxC;CAEA,MAAM,gBAAqC,eAClC,EACL,YACF,IACA,CAAC,WAAW,CACd;CAEA,OACE,oBAAC,eAAD;EAAe,OAAO;EACpB,UAAA,oBAAC,QAAD;GACE,KAAK;GACL,QAAO;GACP,MAAM;GACN,SAAS;GACT,WAAW;IACT,OAAO,EACL,KAAK,WAAW;KACd,YAAY,MAAM,KAAK,QAAQ,WAAW;KAC1C,OAAO,OAAO,WAAW,SAAS;KAClC,UACE,OAAO,WAAW,YAAY,MAAM,YAAY,OAAO;KACzD,UACE,OAAO,WAAW,YAAY,MAAM,YAAY,OAAO;IAC3D,GACF;IACA,UAAU,EACR,IAAI;KACF,iBAAiB;KACjB,gBAAgB;IAClB,EACF;GACF;GACA,aAAA;GAEC;EACK,CAAA;CACK,CAAA;AAEnB"}
@@ -40,16 +40,20 @@ const AmountInputBase = ({ formType, token, startAdornment, bottomAdornment, dis
40
40
  const { inputMode } = useInputModeStore();
41
41
  const currentInputMode = inputMode[formType];
42
42
  let displayValue;
43
- if (isEditingRef.current) if (currentInputMode === "price") displayValue = formattedPriceInput;
44
- else displayValue = value;
45
- else if (currentInputMode === "price") displayValue = formatInputAmount(formatTokenPrice(value, token?.priceUSD).toFixed(2), 2);
46
- else displayValue = value;
43
+ if (isEditingRef.current) {
44
+ if (currentInputMode === "price") displayValue = formattedPriceInput;
45
+ else displayValue = value;
46
+ } else if (currentInputMode === "price") {
47
+ const priceValue = formatTokenPrice(value, token?.priceUSD);
48
+ displayValue = formatInputAmount(priceValue.toFixed(2), 2);
49
+ } else displayValue = value;
47
50
  const handleChange = (event) => {
48
51
  const { value: inputValue } = event.target;
49
52
  isEditingRef.current = true;
50
53
  let formattedValue;
51
54
  if (currentInputMode === "price") {
52
- formattedValue = formatInputAmount(inputValue.replace("$", ""), 2, true);
55
+ const cleanInputValue = inputValue.replace("$", "");
56
+ formattedValue = formatInputAmount(cleanInputValue, 2, true);
53
57
  const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD);
54
58
  setFormattedPriceInput(formattedValue);
55
59
  setFieldValue(amountKey, tokenValue, {
@@ -69,8 +73,10 @@ const AmountInputBase = ({ formType, token, startAdornment, bottomAdornment, dis
69
73
  isEditingRef.current = false;
70
74
  let formattedValue;
71
75
  if (currentInputMode === "price") {
72
- formattedValue = formatInputAmount(inputValue.replace("$", ""), 2);
73
- const formattedAmount = formatInputAmount(priceToTokenAmount(formattedValue, token?.priceUSD), token?.decimals);
76
+ const cleanInputValue = inputValue.replace("$", "");
77
+ formattedValue = formatInputAmount(cleanInputValue, 2);
78
+ const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD);
79
+ const formattedAmount = formatInputAmount(tokenValue, token?.decimals);
74
80
  setFieldValue(amountKey, formattedAmount, {
75
81
  isDirty: true,
76
82
  isTouched: true
@@ -1 +1 @@
1
- {"version":3,"file":"AmountInput.js","names":[],"sources":["../../../../src/components/AmountInput/AmountInput.tsx"],"sourcesContent":["import type { Token } from '@lifi/sdk'\nimport type { CardProps } from '@mui/material'\nimport type { ChangeEvent, ReactNode } from 'react'\nimport { useLayoutEffect, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useToken } from '../../hooks/useToken.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport { FormKeyHelper, type FormTypeProps } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { useInputModeStore } from '../../stores/inputMode/useInputModeStore.js'\nimport {\n formatInputAmount,\n formatTokenPrice,\n priceToTokenAmount,\n usdDecimals,\n} from '../../utils/format.js'\nimport { fitInputText } from '../../utils/input.js'\nimport { InputCard } from '../Card/InputCard.js'\nimport {\n AmountInputCardHeader,\n AmountInputCardTitle,\n FormContainer,\n FormControl,\n Input,\n maxInputFontSize,\n minInputFontSize,\n} from './AmountInput.style.js'\nimport { AmountInputEndAdornment } from './AmountInputEndAdornment.js'\nimport { AmountInputStartAdornment } from './AmountInputStartAdornment.js'\nimport { PriceFormHelperText } from './PriceFormHelperText.js'\n\nexport const AmountInput: React.FC<FormTypeProps & CardProps> = ({\n formType,\n ...props\n}) => {\n const { disabledUI } = useWidgetConfig()\n\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const { token } = useToken(chainId, tokenAddress)\n\n const disabled = disabledUI?.fromAmount\n return (\n <AmountInputBase\n formType={formType}\n token={token}\n bottomAdornment={<PriceFormHelperText formType={formType} />}\n disabled={disabled}\n {...props}\n />\n )\n}\n\nconst AmountInputBase: React.FC<\n FormTypeProps &\n CardProps & {\n token?: Token\n startAdornment?: ReactNode\n bottomAdornment?: ReactNode\n disabled?: boolean\n }\n> = ({\n formType,\n token,\n startAdornment,\n bottomAdornment,\n disabled,\n ...props\n}) => {\n const { t } = useTranslation()\n const { mode, modeOptions } = useWidgetConfig()\n const ref = useRef<HTMLInputElement>(null)\n\n const isEditingRef = useRef(false)\n const [formattedPriceInput, setFormattedPriceInput] = useState('')\n\n const amountKey = FormKeyHelper.getAmountKey(formType)\n const [value] = useFieldValues(amountKey)\n const { setFieldValue } = useFieldActions()\n const { inputMode } = useInputModeStore()\n\n const currentInputMode = inputMode[formType]\n let displayValue: string\n if (isEditingRef.current) {\n if (currentInputMode === 'price') {\n displayValue = formattedPriceInput\n } else {\n displayValue = value as string\n }\n } else {\n if (currentInputMode === 'price') {\n const priceValue = formatTokenPrice(value as string, token?.priceUSD)\n displayValue = formatInputAmount(\n priceValue.toFixed(usdDecimals),\n usdDecimals\n )\n } else {\n displayValue = value as string\n }\n }\n\n const handleChange = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ) => {\n const { value: inputValue } = event.target\n isEditingRef.current = true\n\n let formattedValue: string\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n formattedValue = formatInputAmount(cleanInputValue, usdDecimals, true)\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n setFormattedPriceInput(formattedValue)\n setFieldValue(amountKey, tokenValue, { isDirty: true, isTouched: true })\n } else {\n formattedValue = formatInputAmount(inputValue, token?.decimals, true)\n setFieldValue(amountKey, formattedValue, {\n isDirty: true,\n isTouched: true,\n })\n }\n }\n\n const handleBlur = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ) => {\n const { value: inputValue } = event.target\n isEditingRef.current = false\n\n let formattedValue: string\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n formattedValue = formatInputAmount(cleanInputValue, usdDecimals)\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n const formattedAmount = formatInputAmount(tokenValue, token?.decimals)\n setFieldValue(amountKey, formattedAmount, {\n isDirty: true,\n isTouched: true,\n })\n } else {\n formattedValue = formatInputAmount(inputValue, token?.decimals)\n setFieldValue(amountKey, formattedValue, {\n isDirty: true,\n isTouched: true,\n })\n }\n }\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: we need run effect on value change\n useLayoutEffect(() => {\n if (ref.current) {\n fitInputText(maxInputFontSize, minInputFontSize, ref.current)\n }\n }, [displayValue])\n\n const title =\n mode === 'custom'\n ? modeOptions?.custom?.type === 'deposit'\n ? t('header.amount')\n : t('header.youPay')\n : t('header.send')\n\n return (\n <InputCard {...props}>\n <AmountInputCardHeader>\n <AmountInputCardTitle>{title}</AmountInputCardTitle>\n </AmountInputCardHeader>\n <FormContainer>\n <AmountInputStartAdornment formType={formType} />\n <FormControl fullWidth>\n <Input\n inputRef={ref}\n size=\"small\"\n autoComplete=\"off\"\n placeholder={currentInputMode === 'price' ? '$0' : '0'}\n startAdornment={startAdornment}\n inputProps={{\n inputMode: 'decimal',\n }}\n onChange={handleChange}\n onBlur={handleBlur}\n value={\n currentInputMode === 'price'\n ? displayValue\n ? `$${displayValue}`\n : ''\n : displayValue\n }\n name={amountKey}\n disabled={disabled}\n required\n />\n {bottomAdornment}\n </FormControl>\n </FormContainer>\n {!disabled && <AmountInputEndAdornment formType={formType} />}\n </InputCard>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AmountInput.js","names":[],"sources":["../../../../src/components/AmountInput/AmountInput.tsx"],"sourcesContent":["import type { Token } from '@lifi/sdk'\nimport type { CardProps } from '@mui/material'\nimport type { ChangeEvent, ReactNode } from 'react'\nimport { useLayoutEffect, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useToken } from '../../hooks/useToken.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport { FormKeyHelper, type FormTypeProps } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { useInputModeStore } from '../../stores/inputMode/useInputModeStore.js'\nimport {\n formatInputAmount,\n formatTokenPrice,\n priceToTokenAmount,\n usdDecimals,\n} from '../../utils/format.js'\nimport { fitInputText } from '../../utils/input.js'\nimport { InputCard } from '../Card/InputCard.js'\nimport {\n AmountInputCardHeader,\n AmountInputCardTitle,\n FormContainer,\n FormControl,\n Input,\n maxInputFontSize,\n minInputFontSize,\n} from './AmountInput.style.js'\nimport { AmountInputEndAdornment } from './AmountInputEndAdornment.js'\nimport { AmountInputStartAdornment } from './AmountInputStartAdornment.js'\nimport { PriceFormHelperText } from './PriceFormHelperText.js'\n\nexport const AmountInput: React.FC<FormTypeProps & CardProps> = ({\n formType,\n ...props\n}) => {\n const { disabledUI } = useWidgetConfig()\n\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const { token } = useToken(chainId, tokenAddress)\n\n const disabled = disabledUI?.fromAmount\n return (\n <AmountInputBase\n formType={formType}\n token={token}\n bottomAdornment={<PriceFormHelperText formType={formType} />}\n disabled={disabled}\n {...props}\n />\n )\n}\n\nconst AmountInputBase: React.FC<\n FormTypeProps &\n CardProps & {\n token?: Token\n startAdornment?: ReactNode\n bottomAdornment?: ReactNode\n disabled?: boolean\n }\n> = ({\n formType,\n token,\n startAdornment,\n bottomAdornment,\n disabled,\n ...props\n}) => {\n const { t } = useTranslation()\n const { mode, modeOptions } = useWidgetConfig()\n const ref = useRef<HTMLInputElement>(null)\n\n const isEditingRef = useRef(false)\n const [formattedPriceInput, setFormattedPriceInput] = useState('')\n\n const amountKey = FormKeyHelper.getAmountKey(formType)\n const [value] = useFieldValues(amountKey)\n const { setFieldValue } = useFieldActions()\n const { inputMode } = useInputModeStore()\n\n const currentInputMode = inputMode[formType]\n let displayValue: string\n if (isEditingRef.current) {\n if (currentInputMode === 'price') {\n displayValue = formattedPriceInput\n } else {\n displayValue = value as string\n }\n } else {\n if (currentInputMode === 'price') {\n const priceValue = formatTokenPrice(value as string, token?.priceUSD)\n displayValue = formatInputAmount(\n priceValue.toFixed(usdDecimals),\n usdDecimals\n )\n } else {\n displayValue = value as string\n }\n }\n\n const handleChange = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ) => {\n const { value: inputValue } = event.target\n isEditingRef.current = true\n\n let formattedValue: string\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n formattedValue = formatInputAmount(cleanInputValue, usdDecimals, true)\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n setFormattedPriceInput(formattedValue)\n setFieldValue(amountKey, tokenValue, { isDirty: true, isTouched: true })\n } else {\n formattedValue = formatInputAmount(inputValue, token?.decimals, true)\n setFieldValue(amountKey, formattedValue, {\n isDirty: true,\n isTouched: true,\n })\n }\n }\n\n const handleBlur = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ) => {\n const { value: inputValue } = event.target\n isEditingRef.current = false\n\n let formattedValue: string\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n formattedValue = formatInputAmount(cleanInputValue, usdDecimals)\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n const formattedAmount = formatInputAmount(tokenValue, token?.decimals)\n setFieldValue(amountKey, formattedAmount, {\n isDirty: true,\n isTouched: true,\n })\n } else {\n formattedValue = formatInputAmount(inputValue, token?.decimals)\n setFieldValue(amountKey, formattedValue, {\n isDirty: true,\n isTouched: true,\n })\n }\n }\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: we need run effect on value change\n useLayoutEffect(() => {\n if (ref.current) {\n fitInputText(maxInputFontSize, minInputFontSize, ref.current)\n }\n }, [displayValue])\n\n const title =\n mode === 'custom'\n ? modeOptions?.custom?.type === 'deposit'\n ? t('header.amount')\n : t('header.youPay')\n : t('header.send')\n\n return (\n <InputCard {...props}>\n <AmountInputCardHeader>\n <AmountInputCardTitle>{title}</AmountInputCardTitle>\n </AmountInputCardHeader>\n <FormContainer>\n <AmountInputStartAdornment formType={formType} />\n <FormControl fullWidth>\n <Input\n inputRef={ref}\n size=\"small\"\n autoComplete=\"off\"\n placeholder={currentInputMode === 'price' ? '$0' : '0'}\n startAdornment={startAdornment}\n inputProps={{\n inputMode: 'decimal',\n }}\n onChange={handleChange}\n onBlur={handleBlur}\n value={\n currentInputMode === 'price'\n ? displayValue\n ? `$${displayValue}`\n : ''\n : displayValue\n }\n name={amountKey}\n disabled={disabled}\n required\n />\n {bottomAdornment}\n </FormControl>\n </FormContainer>\n {!disabled && <AmountInputEndAdornment formType={formType} />}\n </InputCard>\n )\n}\n"],"mappings":"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"}
@@ -2,8 +2,8 @@ import { useAvailableChains } from "../../hooks/useAvailableChains.js";
2
2
  import { useFieldActions } from "../../stores/form/useFieldActions.js";
3
3
  import { FormKeyHelper } from "../../stores/form/types.js";
4
4
  import { useFieldValues } from "../../stores/form/useFieldValues.js";
5
- import { useGasRecommendation } from "../../hooks/useGasRecommendation.js";
6
5
  import { useTokenAddressBalance } from "../../hooks/useTokenAddressBalance.js";
6
+ import { useMaxSendAmount } from "../../hooks/useMaxSendAmount.js";
7
7
  import { AmountInputButton, ButtonContainer } from "./AmountInputEndAdornment.style.js";
8
8
  import { formatUnits } from "@lifi/sdk";
9
9
  import { memo } from "react";
@@ -18,26 +18,15 @@ const AmountInputEndAdornment = memo(({ formType }) => {
18
18
  const [chainId, tokenAddress] = useFieldValues(FormKeyHelper.getChainKey(formType), FormKeyHelper.getTokenKey(formType));
19
19
  const chain = getChainById(chainId);
20
20
  const { account } = useAccount({ chainType: chain?.chainType });
21
- const { data } = useGasRecommendation(chainId);
22
21
  const { token } = useTokenAddressBalance(chainId, tokenAddress);
23
- const getMaxAmount = () => {
24
- if (!token?.amount) return 0n;
25
- let maxAmount = token.amount;
26
- if (chain?.nativeToken.address === tokenAddress && data?.recommended) {
27
- const recommendedAmount = BigInt(data.recommended.amount);
28
- if (token.amount > recommendedAmount) maxAmount = token.amount - recommendedAmount;
29
- }
30
- return maxAmount;
31
- };
22
+ const maxAmount = useMaxSendAmount(chainId, tokenAddress);
32
23
  const handlePercentage = (percentage) => {
33
- const maxAmount = getMaxAmount();
34
24
  if (maxAmount && token?.decimals) {
35
25
  const percentageAmount = maxAmount * BigInt(percentage) / 100n;
36
26
  setFieldValue(FormKeyHelper.getAmountKey(formType), formatUnits(percentageAmount, token.decimals), { isTouched: true });
37
27
  }
38
28
  };
39
29
  const handleMax = () => {
40
- const maxAmount = getMaxAmount();
41
30
  if (maxAmount && token?.decimals) setFieldValue(FormKeyHelper.getAmountKey(formType), formatUnits(maxAmount, token.decimals), { isTouched: true });
42
31
  };
43
32
  if (formType !== "from" || !token || !account?.isConnected) return null;
@@ -1 +1 @@
1
- {"version":3,"file":"AmountInputEndAdornment.js","names":[],"sources":["../../../../src/components/AmountInput/AmountInputEndAdornment.tsx"],"sourcesContent":["import { formatUnits } from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport type React from 'react'\nimport { type JSX, memo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport { useGasRecommendation } from '../../hooks/useGasRecommendation.js'\nimport { useTokenAddressBalance } from '../../hooks/useTokenAddressBalance.js'\nimport type { FormTypeProps } from '../../stores/form/types.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport {\n AmountInputButton,\n ButtonContainer,\n} from './AmountInputEndAdornment.style.js'\n\nexport const AmountInputEndAdornment: React.NamedExoticComponent<FormTypeProps> =\n memo(({ formType }: FormTypeProps): JSX.Element | null => {\n const { t } = useTranslation()\n const { getChainById } = useAvailableChains()\n const { setFieldValue } = useFieldActions()\n\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const chain = getChainById(chainId)\n const { account } = useAccount({ chainType: chain?.chainType })\n\n // We get gas recommendations for the source chain to make sure that after pressing the Max button\n // the user will have enough funds remaining to cover gas costs\n const { data } = useGasRecommendation(chainId)\n\n const { token } = useTokenAddressBalance(chainId, tokenAddress)\n\n const getMaxAmount = () => {\n if (!token?.amount) {\n return 0n\n }\n let maxAmount = token.amount\n if (chain?.nativeToken.address === tokenAddress && data?.recommended) {\n const recommendedAmount = BigInt(data.recommended.amount)\n if (token.amount > recommendedAmount) {\n maxAmount = token.amount - recommendedAmount\n }\n }\n return maxAmount\n }\n\n const handlePercentage = (percentage: number) => {\n const maxAmount = getMaxAmount()\n if (maxAmount && token?.decimals) {\n const percentageAmount = (maxAmount * BigInt(percentage)) / 100n\n setFieldValue(\n FormKeyHelper.getAmountKey(formType),\n formatUnits(percentageAmount, token.decimals),\n {\n isTouched: true,\n }\n )\n }\n }\n\n const handleMax = () => {\n const maxAmount = getMaxAmount()\n if (maxAmount && token?.decimals) {\n setFieldValue(\n FormKeyHelper.getAmountKey(formType),\n formatUnits(maxAmount, token.decimals),\n {\n isTouched: true,\n }\n )\n }\n }\n\n if (formType !== 'from' || !token || !account?.isConnected) {\n return null\n }\n\n return (\n <ButtonContainer>\n <AmountInputButton onClick={() => handlePercentage(25)}>\n 25%\n </AmountInputButton>\n <AmountInputButton onClick={() => handlePercentage(50)}>\n 50%\n </AmountInputButton>\n <AmountInputButton onClick={() => handlePercentage(75)}>\n 75%\n </AmountInputButton>\n <AmountInputButton onClick={handleMax}>\n {t('button.max')}\n </AmountInputButton>\n </ButtonContainer>\n )\n })\n"],"mappings":";;;;;;;;;;;;;AAiBA,MAAa,0BACX,MAAM,EAAE,eAAkD;CACxD,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,iBAAiB,mBAAmB;CAC5C,MAAM,EAAE,kBAAkB,gBAAgB;CAE1C,MAAM,CAAC,SAAS,gBAAgB,eAC9B,cAAc,YAAY,QAAQ,GAClC,cAAc,YAAY,QAAQ,CACpC;CAEA,MAAM,QAAQ,aAAa,OAAO;CAClC,MAAM,EAAE,YAAY,WAAW,EAAE,WAAW,OAAO,UAAU,CAAC;CAI9D,MAAM,EAAE,SAAS,qBAAqB,OAAO;CAE7C,MAAM,EAAE,UAAU,uBAAuB,SAAS,YAAY;CAE9D,MAAM,qBAAqB;EACzB,IAAI,CAAC,OAAO,QACV,OAAO;EAET,IAAI,YAAY,MAAM;EACtB,IAAI,OAAO,YAAY,YAAY,gBAAgB,MAAM,aAAa;GACpE,MAAM,oBAAoB,OAAO,KAAK,YAAY,MAAM;GACxD,IAAI,MAAM,SAAS,mBACjB,YAAY,MAAM,SAAS;EAE/B;EACA,OAAO;CACT;CAEA,MAAM,oBAAoB,eAAuB;EAC/C,MAAM,YAAY,aAAa;EAC/B,IAAI,aAAa,OAAO,UAAU;GAChC,MAAM,mBAAoB,YAAY,OAAO,UAAU,IAAK;GAC5D,cACE,cAAc,aAAa,QAAQ,GACnC,YAAY,kBAAkB,MAAM,QAAQ,GAC5C,EACE,WAAW,KACb,CACF;EACF;CACF;CAEA,MAAM,kBAAkB;EACtB,MAAM,YAAY,aAAa;EAC/B,IAAI,aAAa,OAAO,UACtB,cACE,cAAc,aAAa,QAAQ,GACnC,YAAY,WAAW,MAAM,QAAQ,GACrC,EACE,WAAW,KACb,CACF;CAEJ;CAEA,IAAI,aAAa,UAAU,CAAC,SAAS,CAAC,SAAS,aAC7C,OAAO;CAGT,OACE,qBAAC,iBAAD,EAAA,UAAA;EACE,oBAAC,mBAAD;GAAmB,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAErC,CAAA;EACnB,oBAAC,mBAAD;GAAmB,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAErC,CAAA;EACnB,oBAAC,mBAAD;GAAmB,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAErC,CAAA;EACnB,oBAAC,mBAAD;GAAmB,SAAS;GACzB,UAAA,EAAE,YAAY;EACE,CAAA;CACJ,EAAA,CAAA;AAErB,CAAC"}
1
+ {"version":3,"file":"AmountInputEndAdornment.js","names":[],"sources":["../../../../src/components/AmountInput/AmountInputEndAdornment.tsx"],"sourcesContent":["import { formatUnits } from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport type React from 'react'\nimport { type JSX, memo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport { useMaxSendAmount } from '../../hooks/useMaxSendAmount.js'\nimport { useTokenAddressBalance } from '../../hooks/useTokenAddressBalance.js'\nimport type { FormTypeProps } from '../../stores/form/types.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport {\n AmountInputButton,\n ButtonContainer,\n} from './AmountInputEndAdornment.style.js'\n\nexport const AmountInputEndAdornment: React.NamedExoticComponent<FormTypeProps> =\n memo(({ formType }: FormTypeProps): JSX.Element | null => {\n const { t } = useTranslation()\n const { getChainById } = useAvailableChains()\n const { setFieldValue } = useFieldActions()\n\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const chain = getChainById(chainId)\n const { account } = useAccount({ chainType: chain?.chainType })\n\n const { token } = useTokenAddressBalance(chainId, tokenAddress)\n const maxAmount = useMaxSendAmount(chainId, tokenAddress)\n\n const handlePercentage = (percentage: number) => {\n if (maxAmount && token?.decimals) {\n const percentageAmount = (maxAmount * BigInt(percentage)) / 100n\n setFieldValue(\n FormKeyHelper.getAmountKey(formType),\n formatUnits(percentageAmount, token.decimals),\n {\n isTouched: true,\n }\n )\n }\n }\n\n const handleMax = () => {\n if (maxAmount && token?.decimals) {\n setFieldValue(\n FormKeyHelper.getAmountKey(formType),\n formatUnits(maxAmount, token.decimals),\n {\n isTouched: true,\n }\n )\n }\n }\n\n if (formType !== 'from' || !token || !account?.isConnected) {\n return null\n }\n\n return (\n <ButtonContainer>\n <AmountInputButton onClick={() => handlePercentage(25)}>\n 25%\n </AmountInputButton>\n <AmountInputButton onClick={() => handlePercentage(50)}>\n 50%\n </AmountInputButton>\n <AmountInputButton onClick={() => handlePercentage(75)}>\n 75%\n </AmountInputButton>\n <AmountInputButton onClick={handleMax}>\n {t('button.max')}\n </AmountInputButton>\n </ButtonContainer>\n )\n })\n"],"mappings":";;;;;;;;;;;;;AAiBA,MAAa,0BACX,MAAM,EAAE,eAAkD;CACxD,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,iBAAiB,mBAAmB;CAC5C,MAAM,EAAE,kBAAkB,gBAAgB;CAE1C,MAAM,CAAC,SAAS,gBAAgB,eAC9B,cAAc,YAAY,QAAQ,GAClC,cAAc,YAAY,QAAQ,CACpC;CAEA,MAAM,QAAQ,aAAa,OAAO;CAClC,MAAM,EAAE,YAAY,WAAW,EAAE,WAAW,OAAO,UAAU,CAAC;CAE9D,MAAM,EAAE,UAAU,uBAAuB,SAAS,YAAY;CAC9D,MAAM,YAAY,iBAAiB,SAAS,YAAY;CAExD,MAAM,oBAAoB,eAAuB;EAC/C,IAAI,aAAa,OAAO,UAAU;GAChC,MAAM,mBAAoB,YAAY,OAAO,UAAU,IAAK;GAC5D,cACE,cAAc,aAAa,QAAQ,GACnC,YAAY,kBAAkB,MAAM,QAAQ,GAC5C,EACE,WAAW,KACb,CACF;EACF;CACF;CAEA,MAAM,kBAAkB;EACtB,IAAI,aAAa,OAAO,UACtB,cACE,cAAc,aAAa,QAAQ,GACnC,YAAY,WAAW,MAAM,QAAQ,GACrC,EACE,WAAW,KACb,CACF;CAEJ;CAEA,IAAI,aAAa,UAAU,CAAC,SAAS,CAAC,SAAS,aAC7C,OAAO;CAGT,OACE,qBAAC,iBAAD,EAAA,UAAA;EACE,oBAAC,mBAAD;GAAmB,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAErC,CAAA;EACnB,oBAAC,mBAAD;GAAmB,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAErC,CAAA;EACnB,oBAAC,mBAAD;GAAmB,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAErC,CAAA;EACnB,oBAAC,mBAAD;GAAmB,SAAS;GACzB,UAAA,EAAE,YAAY;EACE,CAAA;CACJ,EAAA,CAAA;AAErB,CAAC"}
@@ -3,8 +3,8 @@ import { useAvailableChains } from "../../hooks/useAvailableChains.js";
3
3
  import { useFieldActions } from "../../stores/form/useFieldActions.js";
4
4
  import { FormKeyHelper } from "../../stores/form/types.js";
5
5
  import { useFieldValues } from "../../stores/form/useFieldValues.js";
6
- import { useGasRecommendation } from "../../hooks/useGasRecommendation.js";
7
6
  import { useTokenAddressBalance } from "../../hooks/useTokenAddressBalance.js";
7
+ import { useMaxSendAmount } from "../../hooks/useMaxSendAmount.js";
8
8
  import { useLinkedLimitFields } from "../../hooks/useLinkedLimitFields.js";
9
9
  import { Chip, ChipContainer } from "./PercentageChips.style.js";
10
10
  import { formatUnits } from "@lifi/sdk";
@@ -24,30 +24,19 @@ const PercentageChips = memo(({ formType }) => {
24
24
  const [chainId, tokenAddress] = useFieldValues(FormKeyHelper.getChainKey(formType), FormKeyHelper.getTokenKey(formType));
25
25
  const chain = getChainById(chainId);
26
26
  const { account } = useAccount({ chainType: chain?.chainType });
27
- const { data } = useGasRecommendation(chainId);
28
27
  const { token } = useTokenAddressBalance(chainId, tokenAddress);
29
- const getMaxAmount = () => {
30
- if (!token?.amount) return 0n;
31
- let maxAmount = token.amount;
32
- if (chain?.nativeToken.address === tokenAddress && data?.recommended) {
33
- const recommendedAmount = BigInt(data.recommended.amount);
34
- if (token.amount > recommendedAmount) maxAmount = token.amount - recommendedAmount;
35
- }
36
- return maxAmount;
37
- };
28
+ const maxAmount = useMaxSendAmount(chainId, tokenAddress);
38
29
  const applyAmount = (value) => {
39
30
  if (mode === "limit") setSendAmount(value);
40
31
  else setFieldValue(amountKey, value, { isTouched: true });
41
32
  };
42
33
  const handlePercentage = (percentage) => {
43
- const maxAmount = getMaxAmount();
44
34
  if (maxAmount && token?.decimals) {
45
35
  const percentageAmount = maxAmount * BigInt(percentage) / 100n;
46
36
  applyAmount(formatUnits(percentageAmount, token.decimals));
47
37
  }
48
38
  };
49
39
  const handleMax = () => {
50
- const maxAmount = getMaxAmount();
51
40
  if (maxAmount && token?.decimals) applyAmount(formatUnits(maxAmount, token.decimals));
52
41
  };
53
42
  if (formType !== "from" || isDisabled || !token || !account?.isConnected) return null;
@@ -1 +1 @@
1
- {"version":3,"file":"PercentageChips.js","names":[],"sources":["../../../../src/components/AmountInputCard/PercentageChips.tsx"],"sourcesContent":["import { formatUnits } from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport { type JSX, memo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport { useGasRecommendation } from '../../hooks/useGasRecommendation.js'\nimport { useLinkedLimitFields } from '../../hooks/useLinkedLimitFields.js'\nimport { useTokenAddressBalance } from '../../hooks/useTokenAddressBalance.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormTypeProps } from '../../stores/form/types.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport type { DisabledUIConfig } from '../../types/widget.js'\nimport { Chip, ChipContainer } from './PercentageChips.style.js'\n\nexport const PercentageChips: React.NamedExoticComponent<FormTypeProps> = memo(\n ({ formType }: FormTypeProps): JSX.Element | null => {\n const { t } = useTranslation()\n const { getChainById } = useAvailableChains()\n const { setFieldValue } = useFieldActions()\n const { disabledUI, mode } = useWidgetConfig()\n const { setSendAmount } = useLinkedLimitFields()\n\n const amountKey = FormKeyHelper.getAmountKey(formType)\n const isDisabled = !!disabledUI?.[amountKey as keyof DisabledUIConfig]\n\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const chain = getChainById(chainId)\n const { account } = useAccount({ chainType: chain?.chainType })\n\n const { data } = useGasRecommendation(chainId)\n const { token } = useTokenAddressBalance(chainId, tokenAddress)\n\n const getMaxAmount = (): bigint => {\n if (!token?.amount) {\n return 0n\n }\n let maxAmount = token.amount\n if (chain?.nativeToken.address === tokenAddress && data?.recommended) {\n const recommendedAmount = BigInt(data.recommended.amount)\n if (token.amount > recommendedAmount) {\n maxAmount = token.amount - recommendedAmount\n }\n }\n return maxAmount\n }\n\n // In limit mode the send amount must flow through the linked-field\n // derivation so the receive amount recomputes; otherwise it is a plain\n // form-field write.\n const applyAmount = (value: string): void => {\n if (mode === 'limit') {\n setSendAmount(value)\n } else {\n setFieldValue(amountKey, value, { isTouched: true })\n }\n }\n\n const handlePercentage = (percentage: number): void => {\n const maxAmount = getMaxAmount()\n if (maxAmount && token?.decimals) {\n const percentageAmount = (maxAmount * BigInt(percentage)) / 100n\n applyAmount(formatUnits(percentageAmount, token.decimals))\n }\n }\n\n const handleMax = (): void => {\n const maxAmount = getMaxAmount()\n if (maxAmount && token?.decimals) {\n applyAmount(formatUnits(maxAmount, token.decimals))\n }\n }\n\n if (formType !== 'from' || isDisabled || !token || !account?.isConnected) {\n return null\n }\n\n return (\n <ChipContainer>\n <Chip data-delay=\"0\" onClick={() => handlePercentage(25)}>\n 25%\n </Chip>\n <Chip data-delay=\"1\" onClick={() => handlePercentage(50)}>\n 50%\n </Chip>\n <Chip data-delay=\"2\" onClick={() => handlePercentage(75)}>\n 75%\n </Chip>\n <Chip data-delay=\"3\" onClick={handleMax}>\n {t('button.max')}\n </Chip>\n </ChipContainer>\n )\n }\n)\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAa,kBAA6D,MACvE,EAAE,eAAkD;CACnD,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,iBAAiB,mBAAmB;CAC5C,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,EAAE,YAAY,SAAS,gBAAgB;CAC7C,MAAM,EAAE,kBAAkB,qBAAqB;CAE/C,MAAM,YAAY,cAAc,aAAa,QAAQ;CACrD,MAAM,aAAa,CAAC,CAAC,aAAa;CAElC,MAAM,CAAC,SAAS,gBAAgB,eAC9B,cAAc,YAAY,QAAQ,GAClC,cAAc,YAAY,QAAQ,CACpC;CAEA,MAAM,QAAQ,aAAa,OAAO;CAClC,MAAM,EAAE,YAAY,WAAW,EAAE,WAAW,OAAO,UAAU,CAAC;CAE9D,MAAM,EAAE,SAAS,qBAAqB,OAAO;CAC7C,MAAM,EAAE,UAAU,uBAAuB,SAAS,YAAY;CAE9D,MAAM,qBAA6B;EACjC,IAAI,CAAC,OAAO,QACV,OAAO;EAET,IAAI,YAAY,MAAM;EACtB,IAAI,OAAO,YAAY,YAAY,gBAAgB,MAAM,aAAa;GACpE,MAAM,oBAAoB,OAAO,KAAK,YAAY,MAAM;GACxD,IAAI,MAAM,SAAS,mBACjB,YAAY,MAAM,SAAS;EAE/B;EACA,OAAO;CACT;CAKA,MAAM,eAAe,UAAwB;EAC3C,IAAI,SAAS,SACX,cAAc,KAAK;OAEnB,cAAc,WAAW,OAAO,EAAE,WAAW,KAAK,CAAC;CAEvD;CAEA,MAAM,oBAAoB,eAA6B;EACrD,MAAM,YAAY,aAAa;EAC/B,IAAI,aAAa,OAAO,UAAU;GAChC,MAAM,mBAAoB,YAAY,OAAO,UAAU,IAAK;GAC5D,YAAY,YAAY,kBAAkB,MAAM,QAAQ,CAAC;EAC3D;CACF;CAEA,MAAM,kBAAwB;EAC5B,MAAM,YAAY,aAAa;EAC/B,IAAI,aAAa,OAAO,UACtB,YAAY,YAAY,WAAW,MAAM,QAAQ,CAAC;CAEtD;CAEA,IAAI,aAAa,UAAU,cAAc,CAAC,SAAS,CAAC,SAAS,aAC3D,OAAO;CAGT,OACE,qBAAC,eAAD,EAAA,UAAA;EACE,oBAAC,MAAD;GAAM,cAAW;GAAI,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAEpD,CAAA;EACN,oBAAC,MAAD;GAAM,cAAW;GAAI,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAEpD,CAAA;EACN,oBAAC,MAAD;GAAM,cAAW;GAAI,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAEpD,CAAA;EACN,oBAAC,MAAD;GAAM,cAAW;GAAI,SAAS;GAC3B,UAAA,EAAE,YAAY;EACX,CAAA;CACO,EAAA,CAAA;AAEnB,CACF"}
1
+ {"version":3,"file":"PercentageChips.js","names":[],"sources":["../../../../src/components/AmountInputCard/PercentageChips.tsx"],"sourcesContent":["import { formatUnits } from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport { type JSX, memo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport { useLinkedLimitFields } from '../../hooks/useLinkedLimitFields.js'\nimport { useMaxSendAmount } from '../../hooks/useMaxSendAmount.js'\nimport { useTokenAddressBalance } from '../../hooks/useTokenAddressBalance.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormTypeProps } from '../../stores/form/types.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport type { DisabledUIConfig } from '../../types/widget.js'\nimport { Chip, ChipContainer } from './PercentageChips.style.js'\n\nexport const PercentageChips: React.NamedExoticComponent<FormTypeProps> = memo(\n ({ formType }: FormTypeProps): JSX.Element | null => {\n const { t } = useTranslation()\n const { getChainById } = useAvailableChains()\n const { setFieldValue } = useFieldActions()\n const { disabledUI, mode } = useWidgetConfig()\n const { setSendAmount } = useLinkedLimitFields()\n\n const amountKey = FormKeyHelper.getAmountKey(formType)\n const isDisabled = !!disabledUI?.[amountKey as keyof DisabledUIConfig]\n\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const chain = getChainById(chainId)\n const { account } = useAccount({ chainType: chain?.chainType })\n\n const { token } = useTokenAddressBalance(chainId, tokenAddress)\n const maxAmount = useMaxSendAmount(chainId, tokenAddress)\n\n // In limit mode the send amount must flow through the linked-field\n // derivation so the receive amount recomputes; otherwise it is a plain\n // form-field write.\n const applyAmount = (value: string): void => {\n if (mode === 'limit') {\n setSendAmount(value)\n } else {\n setFieldValue(amountKey, value, { isTouched: true })\n }\n }\n\n const handlePercentage = (percentage: number): void => {\n if (maxAmount && token?.decimals) {\n const percentageAmount = (maxAmount * BigInt(percentage)) / 100n\n applyAmount(formatUnits(percentageAmount, token.decimals))\n }\n }\n\n const handleMax = (): void => {\n if (maxAmount && token?.decimals) {\n applyAmount(formatUnits(maxAmount, token.decimals))\n }\n }\n\n if (formType !== 'from' || isDisabled || !token || !account?.isConnected) {\n return null\n }\n\n return (\n <ChipContainer>\n <Chip data-delay=\"0\" onClick={() => handlePercentage(25)}>\n 25%\n </Chip>\n <Chip data-delay=\"1\" onClick={() => handlePercentage(50)}>\n 50%\n </Chip>\n <Chip data-delay=\"2\" onClick={() => handlePercentage(75)}>\n 75%\n </Chip>\n <Chip data-delay=\"3\" onClick={handleMax}>\n {t('button.max')}\n </Chip>\n </ChipContainer>\n )\n }\n)\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,MAAa,kBAA6D,MACvE,EAAE,eAAkD;CACnD,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,iBAAiB,mBAAmB;CAC5C,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,EAAE,YAAY,SAAS,gBAAgB;CAC7C,MAAM,EAAE,kBAAkB,qBAAqB;CAE/C,MAAM,YAAY,cAAc,aAAa,QAAQ;CACrD,MAAM,aAAa,CAAC,CAAC,aAAa;CAElC,MAAM,CAAC,SAAS,gBAAgB,eAC9B,cAAc,YAAY,QAAQ,GAClC,cAAc,YAAY,QAAQ,CACpC;CAEA,MAAM,QAAQ,aAAa,OAAO;CAClC,MAAM,EAAE,YAAY,WAAW,EAAE,WAAW,OAAO,UAAU,CAAC;CAE9D,MAAM,EAAE,UAAU,uBAAuB,SAAS,YAAY;CAC9D,MAAM,YAAY,iBAAiB,SAAS,YAAY;CAKxD,MAAM,eAAe,UAAwB;EAC3C,IAAI,SAAS,SACX,cAAc,KAAK;OAEnB,cAAc,WAAW,OAAO,EAAE,WAAW,KAAK,CAAC;CAEvD;CAEA,MAAM,oBAAoB,eAA6B;EACrD,IAAI,aAAa,OAAO,UAAU;GAChC,MAAM,mBAAoB,YAAY,OAAO,UAAU,IAAK;GAC5D,YAAY,YAAY,kBAAkB,MAAM,QAAQ,CAAC;EAC3D;CACF;CAEA,MAAM,kBAAwB;EAC5B,IAAI,aAAa,OAAO,UACtB,YAAY,YAAY,WAAW,MAAM,QAAQ,CAAC;CAEtD;CAEA,IAAI,aAAa,UAAU,cAAc,CAAC,SAAS,CAAC,SAAS,aAC3D,OAAO;CAGT,OACE,qBAAC,eAAD,EAAA,UAAA;EACE,oBAAC,MAAD;GAAM,cAAW;GAAI,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAEpD,CAAA;EACN,oBAAC,MAAD;GAAM,cAAW;GAAI,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAEpD,CAAA;EACN,oBAAC,MAAD;GAAM,cAAW;GAAI,eAAe,iBAAiB,EAAE;GAAG,UAAA;EAEpD,CAAA;EACN,oBAAC,MAAD;GAAM,cAAW;GAAI,SAAS;GAC3B,UAAA,EAAE,YAAY;EACX,CAAA;CACO,EAAA,CAAA;AAEnB,CACF"}
@@ -8,7 +8,7 @@ const revealStagger = Object.fromEntries(Array.from({ length: chipCount }, (_, i
8
8
  opacity: 1,
9
9
  transform: "scale(1) translateX(0)",
10
10
  pointerEvents: "auto",
11
- transitionDelay: `${(chipCount - 1 - index) * staggerStepMs}ms`
11
+ transitionDelay: `${(3 - index) * staggerStepMs}ms`
12
12
  },
13
13
  [`.${cardClasses.root}:not(:hover) &`]: { transitionDelay: `${index * staggerStepMs}ms` }
14
14
  }]));
@@ -1 +1 @@
1
- {"version":3,"file":"PercentageChips.style.js","names":[],"sources":["../../../../src/components/AmountInputCard/PercentageChips.style.tsx"],"sourcesContent":["import { Box, Button, styled } from '@mui/material'\nimport { cardClasses } from '@mui/material/Card'\nimport type React from 'react'\n\nconst chipCount = 4\nconst staggerStepMs = 25\n\nconst revealStagger = Object.fromEntries(\n Array.from({ length: chipCount }, (_, index) => [\n `&[data-delay=\"${index}\"]`,\n {\n [`.${cardClasses.root}:hover &`]: {\n opacity: 1,\n transform: 'scale(1) translateX(0)',\n pointerEvents: 'auto',\n transitionDelay: `${(chipCount - 1 - index) * staggerStepMs}ms`,\n },\n [`.${cardClasses.root}:not(:hover) &`]: {\n transitionDelay: `${index * staggerStepMs}ms`,\n },\n },\n ])\n)\n\nexport const ChipContainer: React.FC<React.ComponentProps<typeof Box>> = styled(\n Box\n)(({ theme }) => ({\n display: 'flex',\n gap: theme.spacing(0.5),\n}))\n\nexport const Chip: React.FC<React.ComponentProps<typeof Button>> = styled(\n Button\n)(({ theme }) => ({\n minWidth: 0,\n padding: theme.spacing(0.5, 1.5),\n fontSize: 12,\n fontWeight: 700,\n lineHeight: 1.3334,\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,\n color: theme.vars.palette.text.primary,\n transition:\n 'opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 200ms cubic-bezier(0.4, 0, 0.2, 1), background-color 200ms ease',\n '&:hover': {\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)`,\n },\n // Reveal-on-hover — only on devices that support hover. On touch there is no\n // hover, so the chips stay permanently visible (the default above) instead of\n // becoming an unreachable dead row.\n '@media (hover: hover)': {\n opacity: 0,\n transform: 'scale(0.85) translateX(10px)',\n pointerEvents: 'none',\n ...revealStagger,\n '@media (prefers-reduced-motion: reduce)': {\n transform: 'none !important',\n transitionDelay: '0ms !important',\n },\n },\n}))\n"],"mappings":";;;AAIA,MAAM,YAAY;AAClB,MAAM,gBAAgB;AAEtB,MAAM,gBAAgB,OAAO,YAC3B,MAAM,KAAK,EAAE,QAAQ,UAAU,IAAI,GAAG,UAAU,CAC9C,iBAAiB,MAAM,KACvB;EACG,IAAI,YAAY,KAAK,YAAY;EAChC,SAAS;EACT,WAAW;EACX,eAAe;EACf,iBAAiB,IAAI,YAAY,IAAI,SAAS,cAAc;CAC9D;EACC,IAAI,YAAY,KAAK,kBAAkB,EACtC,iBAAiB,GAAG,QAAQ,cAAc,IAC5C;AACF,CACF,CAAC,CACH;AAEA,MAAa,gBAA4D,OACvE,GACF,CAAC,EAAE,EAAE,aAAa;CAChB,SAAS;CACT,KAAK,MAAM,QAAQ,EAAG;AACxB,EAAE;AAEF,MAAa,OAAsD,OACjE,MACF,CAAC,EAAE,EAAE,aAAa;CAChB,UAAU;CACV,SAAS,MAAM,QAAQ,IAAK,GAAG;CAC/B,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa;CAC9E,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,YACE;CACF,WAAW,EACT,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa,mBAChF;CAIA,yBAAyB;EACvB,SAAS;EACT,WAAW;EACX,eAAe;EACf,GAAG;EACH,2CAA2C;GACzC,WAAW;GACX,iBAAiB;EACnB;CACF;AACF,EAAE"}
1
+ {"version":3,"file":"PercentageChips.style.js","names":[],"sources":["../../../../src/components/AmountInputCard/PercentageChips.style.tsx"],"sourcesContent":["import { Box, Button, styled } from '@mui/material'\nimport { cardClasses } from '@mui/material/Card'\nimport type React from 'react'\n\nconst chipCount = 4\nconst staggerStepMs = 25\n\nconst revealStagger = Object.fromEntries(\n Array.from({ length: chipCount }, (_, index) => [\n `&[data-delay=\"${index}\"]`,\n {\n [`.${cardClasses.root}:hover &`]: {\n opacity: 1,\n transform: 'scale(1) translateX(0)',\n pointerEvents: 'auto',\n transitionDelay: `${(chipCount - 1 - index) * staggerStepMs}ms`,\n },\n [`.${cardClasses.root}:not(:hover) &`]: {\n transitionDelay: `${index * staggerStepMs}ms`,\n },\n },\n ])\n)\n\nexport const ChipContainer: React.FC<React.ComponentProps<typeof Box>> = styled(\n Box\n)(({ theme }) => ({\n display: 'flex',\n gap: theme.spacing(0.5),\n}))\n\nexport const Chip: React.FC<React.ComponentProps<typeof Button>> = styled(\n Button\n)(({ theme }) => ({\n minWidth: 0,\n padding: theme.spacing(0.5, 1.5),\n fontSize: 12,\n fontWeight: 700,\n lineHeight: 1.3334,\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,\n color: theme.vars.palette.text.primary,\n transition:\n 'opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 200ms cubic-bezier(0.4, 0, 0.2, 1), background-color 200ms ease',\n '&:hover': {\n backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)`,\n },\n // Reveal-on-hover — only on devices that support hover. On touch there is no\n // hover, so the chips stay permanently visible (the default above) instead of\n // becoming an unreachable dead row.\n '@media (hover: hover)': {\n opacity: 0,\n transform: 'scale(0.85) translateX(10px)',\n pointerEvents: 'none',\n ...revealStagger,\n '@media (prefers-reduced-motion: reduce)': {\n transform: 'none !important',\n transitionDelay: '0ms !important',\n },\n },\n}))\n"],"mappings":";;;AAIA,MAAM,YAAY;AAClB,MAAM,gBAAgB;AAEtB,MAAM,gBAAgB,OAAO,YAC3B,MAAM,KAAK,EAAE,QAAQ,UAAU,IAAI,GAAG,UAAU,CAC9C,iBAAiB,MAAM,KACvB;EACG,IAAI,YAAY,KAAK,YAAY;EAChC,SAAS;EACT,WAAW;EACX,eAAe;EACf,iBAAiB,IAAI,IAAgB,SAAS,cAAc;CAC9D;EACC,IAAI,YAAY,KAAK,kBAAkB,EACtC,iBAAiB,GAAG,QAAQ,cAAc,IAC5C;AACF,CACF,CAAC,CACH;AAEA,MAAa,gBAA4D,OACvE,GACF,CAAC,EAAE,EAAE,aAAa;CAChB,SAAS;CACT,KAAK,MAAM,QAAQ,EAAG;AACxB,EAAE;AAEF,MAAa,OAAsD,OACjE,MACF,CAAC,EAAE,EAAE,aAAa;CAChB,UAAU;CACV,SAAS,MAAM,QAAQ,IAAK,GAAG;CAC/B,UAAU;CACV,YAAY;CACZ,YAAY;CACZ,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa;CAC9E,OAAO,MAAM,KAAK,QAAQ,KAAK;CAC/B,YACE;CACF,WAAW,EACT,iBAAiB,sBAAsB,MAAM,KAAK,QAAQ,OAAO,aAAa,mBAChF;CAIA,yBAAyB;EACvB,SAAS;EACT,WAAW;EACX,eAAe;EACf,GAAG;EACH,2CAA2C;GACzC,WAAW;GACX,iBAAiB;EACnB;CACF;AACF,EAAE"}
@@ -40,15 +40,19 @@ const SendAmountCard = (props) => {
40
40
  };
41
41
  const title = mode === "limit" ? t("header.sell") : mode === "custom" && modeOptions?.custom?.type === "deposit" ? t("header.deposit") : t("header.send");
42
42
  let displayValue;
43
- if (isEditingRef.current) if (currentInputMode === "price") displayValue = formattedPriceInput;
44
- else displayValue = value;
45
- else if (currentInputMode === "price") displayValue = formatInputAmount(formatTokenPrice(value, token?.priceUSD).toFixed(2), 2);
46
- else displayValue = value;
43
+ if (isEditingRef.current) {
44
+ if (currentInputMode === "price") displayValue = formattedPriceInput;
45
+ else displayValue = value;
46
+ } else if (currentInputMode === "price") {
47
+ const priceValue = formatTokenPrice(value, token?.priceUSD);
48
+ displayValue = formatInputAmount(priceValue.toFixed(2), 2);
49
+ } else displayValue = value;
47
50
  const handleChange = (event) => {
48
51
  const { value: inputValue } = event.target;
49
52
  isEditingRef.current = true;
50
53
  if (currentInputMode === "price") {
51
- const formattedValue = formatInputAmount(inputValue.replace("$", ""), 2, true);
54
+ const cleanInputValue = inputValue.replace("$", "");
55
+ const formattedValue = formatInputAmount(cleanInputValue, 2, true);
52
56
  const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD);
53
57
  setFormattedPriceInput(formattedValue);
54
58
  applyFromAmount(tokenValue);
@@ -61,7 +65,10 @@ const SendAmountCard = (props) => {
61
65
  const { value: inputValue } = event.target;
62
66
  isEditingRef.current = false;
63
67
  if (currentInputMode === "price") {
64
- const formattedAmount = formatInputAmount(priceToTokenAmount(formatInputAmount(inputValue.replace("$", ""), 2), token?.priceUSD), token?.decimals);
68
+ const cleanInputValue = inputValue.replace("$", "");
69
+ const formattedValue = formatInputAmount(cleanInputValue, 2);
70
+ const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD);
71
+ const formattedAmount = formatInputAmount(tokenValue, token?.decimals);
65
72
  applyFromAmount(formattedAmount);
66
73
  } else {
67
74
  const formattedValue = formatInputAmount(inputValue, token?.decimals);
@@ -1 +1 @@
1
- {"version":3,"file":"SendAmountCard.js","names":[],"sources":["../../../../src/components/AmountInputCard/SendAmountCard.tsx"],"sourcesContent":["import type { CardProps } from '@mui/material'\nimport type { ChangeEvent, JSX } from 'react'\nimport { useLayoutEffect, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useLinkedLimitFields } from '../../hooks/useLinkedLimitFields.js'\nimport { useToken } from '../../hooks/useToken.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { useInputModeStore } from '../../stores/inputMode/useInputModeStore.js'\nimport {\n formatInputAmount,\n formatTokenPrice,\n priceToTokenAmount,\n usdDecimals,\n} from '../../utils/format.js'\nimport { fitInputText } from '../../utils/input.js'\nimport { CardTitle } from '../Card/CardTitle.js'\nimport { TokenPillButton } from '../TokenPillButton/TokenPillButton.js'\nimport {\n AmountCard,\n CardBodyRow,\n CardFooterRow,\n CardHeaderRow,\n LargeInput,\n maxInputFontSize,\n minInputFontSize,\n} from './AmountInputCard.style.js'\nimport { BalanceDisplay } from './BalanceDisplay.js'\nimport { FiatValueToggle } from './FiatValueToggle.js'\nimport { PercentageChips } from './PercentageChips.js'\n\nexport const SendAmountCard: React.FC<CardProps & { mask?: boolean }> = (\n props\n): JSX.Element => {\n const { t } = useTranslation()\n const { disabledUI, mode, modeOptions } = useWidgetConfig()\n const ref = useRef<HTMLInputElement>(null)\n const isEditingRef = useRef(false)\n const [formattedPriceInput, setFormattedPriceInput] = useState('')\n\n const formType = 'from' as const\n\n const [chainId, tokenAddress, value] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType),\n FormKeyHelper.getAmountKey(formType)\n )\n\n const { token } = useToken(chainId, tokenAddress)\n const { setFieldValue } = useFieldActions()\n const { inputMode } = useInputModeStore()\n const { setSendAmount } = useLinkedLimitFields()\n const currentInputMode = inputMode[formType]\n const disabled = disabledUI?.fromAmount\n\n // In limit mode the send amount drives the linked receive amount; otherwise\n // it is a plain form-field write.\n const applyFromAmount = (value: string): void => {\n if (mode === 'limit') {\n setSendAmount(value)\n } else {\n setFieldValue('fromAmount', value, { isDirty: true, isTouched: true })\n }\n }\n\n const title =\n mode === 'limit'\n ? t('header.sell')\n : mode === 'custom' && modeOptions?.custom?.type === 'deposit'\n ? t('header.deposit')\n : t('header.send')\n\n let displayValue: string\n if (isEditingRef.current) {\n if (currentInputMode === 'price') {\n displayValue = formattedPriceInput\n } else {\n displayValue = value as string\n }\n } else {\n if (currentInputMode === 'price') {\n const priceValue = formatTokenPrice(value as string, token?.priceUSD)\n displayValue = formatInputAmount(\n priceValue.toFixed(usdDecimals),\n usdDecimals\n )\n } else {\n displayValue = value as string\n }\n }\n\n const handleChange = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ): void => {\n const { value: inputValue } = event.target\n isEditingRef.current = true\n\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n const formattedValue = formatInputAmount(\n cleanInputValue,\n usdDecimals,\n true\n )\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n setFormattedPriceInput(formattedValue)\n applyFromAmount(tokenValue)\n } else {\n const formattedValue = formatInputAmount(\n inputValue,\n token?.decimals,\n true\n )\n applyFromAmount(formattedValue)\n }\n }\n\n const handleBlur = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ): void => {\n const { value: inputValue } = event.target\n isEditingRef.current = false\n\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n const formattedValue = formatInputAmount(cleanInputValue, usdDecimals)\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n const formattedAmount = formatInputAmount(tokenValue, token?.decimals)\n applyFromAmount(formattedAmount)\n } else {\n const formattedValue = formatInputAmount(inputValue, token?.decimals)\n applyFromAmount(formattedValue)\n }\n }\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: effect must run on value change\n useLayoutEffect(() => {\n if (ref.current) {\n fitInputText(maxInputFontSize, minInputFontSize, ref.current)\n }\n }, [displayValue])\n\n return (\n <AmountCard {...props} formType={formType}>\n <CardHeaderRow>\n <CardTitle sx={{ padding: 0 }}>{title}</CardTitle>\n <PercentageChips formType={formType} />\n </CardHeaderRow>\n <CardBodyRow>\n <LargeInput\n inputRef={ref}\n size=\"small\"\n autoComplete=\"off\"\n placeholder={currentInputMode === 'price' ? '$0' : '0'}\n inputProps={{ inputMode: 'decimal' }}\n onChange={handleChange}\n onBlur={handleBlur}\n value={\n currentInputMode === 'price'\n ? displayValue\n ? `$${displayValue}`\n : ''\n : displayValue\n }\n name=\"fromAmount\"\n disabled={disabled}\n required\n />\n <TokenPillButton formType={formType} />\n </CardBodyRow>\n <CardFooterRow>\n <FiatValueToggle formType={formType} />\n <BalanceDisplay formType={formType} />\n </CardFooterRow>\n </AmountCard>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SendAmountCard.js","names":[],"sources":["../../../../src/components/AmountInputCard/SendAmountCard.tsx"],"sourcesContent":["import type { CardProps } from '@mui/material'\nimport type { ChangeEvent, JSX } from 'react'\nimport { useLayoutEffect, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useLinkedLimitFields } from '../../hooks/useLinkedLimitFields.js'\nimport { useToken } from '../../hooks/useToken.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldActions } from '../../stores/form/useFieldActions.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { useInputModeStore } from '../../stores/inputMode/useInputModeStore.js'\nimport {\n formatInputAmount,\n formatTokenPrice,\n priceToTokenAmount,\n usdDecimals,\n} from '../../utils/format.js'\nimport { fitInputText } from '../../utils/input.js'\nimport { CardTitle } from '../Card/CardTitle.js'\nimport { TokenPillButton } from '../TokenPillButton/TokenPillButton.js'\nimport {\n AmountCard,\n CardBodyRow,\n CardFooterRow,\n CardHeaderRow,\n LargeInput,\n maxInputFontSize,\n minInputFontSize,\n} from './AmountInputCard.style.js'\nimport { BalanceDisplay } from './BalanceDisplay.js'\nimport { FiatValueToggle } from './FiatValueToggle.js'\nimport { PercentageChips } from './PercentageChips.js'\n\nexport const SendAmountCard: React.FC<CardProps & { mask?: boolean }> = (\n props\n): JSX.Element => {\n const { t } = useTranslation()\n const { disabledUI, mode, modeOptions } = useWidgetConfig()\n const ref = useRef<HTMLInputElement>(null)\n const isEditingRef = useRef(false)\n const [formattedPriceInput, setFormattedPriceInput] = useState('')\n\n const formType = 'from' as const\n\n const [chainId, tokenAddress, value] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType),\n FormKeyHelper.getAmountKey(formType)\n )\n\n const { token } = useToken(chainId, tokenAddress)\n const { setFieldValue } = useFieldActions()\n const { inputMode } = useInputModeStore()\n const { setSendAmount } = useLinkedLimitFields()\n const currentInputMode = inputMode[formType]\n const disabled = disabledUI?.fromAmount\n\n // In limit mode the send amount drives the linked receive amount; otherwise\n // it is a plain form-field write.\n const applyFromAmount = (value: string): void => {\n if (mode === 'limit') {\n setSendAmount(value)\n } else {\n setFieldValue('fromAmount', value, { isDirty: true, isTouched: true })\n }\n }\n\n const title =\n mode === 'limit'\n ? t('header.sell')\n : mode === 'custom' && modeOptions?.custom?.type === 'deposit'\n ? t('header.deposit')\n : t('header.send')\n\n let displayValue: string\n if (isEditingRef.current) {\n if (currentInputMode === 'price') {\n displayValue = formattedPriceInput\n } else {\n displayValue = value as string\n }\n } else {\n if (currentInputMode === 'price') {\n const priceValue = formatTokenPrice(value as string, token?.priceUSD)\n displayValue = formatInputAmount(\n priceValue.toFixed(usdDecimals),\n usdDecimals\n )\n } else {\n displayValue = value as string\n }\n }\n\n const handleChange = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ): void => {\n const { value: inputValue } = event.target\n isEditingRef.current = true\n\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n const formattedValue = formatInputAmount(\n cleanInputValue,\n usdDecimals,\n true\n )\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n setFormattedPriceInput(formattedValue)\n applyFromAmount(tokenValue)\n } else {\n const formattedValue = formatInputAmount(\n inputValue,\n token?.decimals,\n true\n )\n applyFromAmount(formattedValue)\n }\n }\n\n const handleBlur = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>\n ): void => {\n const { value: inputValue } = event.target\n isEditingRef.current = false\n\n if (currentInputMode === 'price') {\n const cleanInputValue = inputValue.replace('$', '')\n const formattedValue = formatInputAmount(cleanInputValue, usdDecimals)\n const tokenValue = priceToTokenAmount(formattedValue, token?.priceUSD)\n const formattedAmount = formatInputAmount(tokenValue, token?.decimals)\n applyFromAmount(formattedAmount)\n } else {\n const formattedValue = formatInputAmount(inputValue, token?.decimals)\n applyFromAmount(formattedValue)\n }\n }\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: effect must run on value change\n useLayoutEffect(() => {\n if (ref.current) {\n fitInputText(maxInputFontSize, minInputFontSize, ref.current)\n }\n }, [displayValue])\n\n return (\n <AmountCard {...props} formType={formType}>\n <CardHeaderRow>\n <CardTitle sx={{ padding: 0 }}>{title}</CardTitle>\n <PercentageChips formType={formType} />\n </CardHeaderRow>\n <CardBodyRow>\n <LargeInput\n inputRef={ref}\n size=\"small\"\n autoComplete=\"off\"\n placeholder={currentInputMode === 'price' ? '$0' : '0'}\n inputProps={{ inputMode: 'decimal' }}\n onChange={handleChange}\n onBlur={handleBlur}\n value={\n currentInputMode === 'price'\n ? displayValue\n ? `$${displayValue}`\n : ''\n : displayValue\n }\n name=\"fromAmount\"\n disabled={disabled}\n required\n />\n <TokenPillButton formType={formType} />\n </CardBodyRow>\n <CardFooterRow>\n <FiatValueToggle formType={formType} />\n <BalanceDisplay formType={formType} />\n </CardFooterRow>\n </AmountCard>\n )\n}\n"],"mappings":"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"}
@@ -33,6 +33,12 @@ const chainTypeIcons = [
33
33
  chainType: ChainType.TVM,
34
34
  icon: "https://lifinance.github.io/types/src/assets/icons/chains/tron.svg",
35
35
  defaultChainId: ChainId.TRN
36
+ },
37
+ {
38
+ name: "Stellar",
39
+ chainType: ChainType.STL,
40
+ icon: "https://lifinance.github.io/types/src/assets/icons/chains/stellar.svg",
41
+ defaultChainId: ChainId.XLM
36
42
  }
37
43
  ];
38
44
  const maxChainAvatarsCount = 4;
@@ -54,7 +60,7 @@ const AllChainsAvatar = memo(({ chains, size }) => {
54
60
  }
55
61
  return numberOfChains > 0;
56
62
  });
57
- if (existingChainTypeIcons.length === maxChainAvatarsCount) return existingChainTypeIcons;
63
+ if (existingChainTypeIcons.length >= maxChainAvatarsCount) return existingChainTypeIcons;
58
64
  const remainingSlots = maxChainAvatarsCount - existingChainTypeIcons.length;
59
65
  const predefinedIconNames = new Set(existingChainTypeIcons.map((icon) => icon.name));
60
66
  const additionalIcons = chains.filter((chain) => {
@@ -1 +1 @@
1
- {"version":3,"file":"AllChainsAvatar.js","names":[],"sources":["../../../../src/components/Chains/AllChainsAvatar.tsx"],"sourcesContent":["import {\n ChainId,\n ChainType,\n type EVMChain,\n type ExtendedChain,\n} from '@lifi/sdk'\nimport { Avatar, Box } from '@mui/material'\nimport type React from 'react'\nimport { type JSX, memo, useMemo } from 'react'\n\ninterface AllChainsAvatarProps {\n chains: ExtendedChain[] | EVMChain[]\n size: 'small' | 'medium'\n}\n\nconst chainTypeIcons = [\n {\n name: 'Ethereum',\n chainType: ChainType.EVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/ethereum.svg',\n defaultChainId: ChainId.ETH,\n },\n {\n name: 'Solana',\n chainType: ChainType.SVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/solana.svg',\n defaultChainId: ChainId.SOL,\n },\n {\n name: 'Bitcoin',\n chainType: ChainType.UTXO,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/bitcoin.svg',\n defaultChainId: ChainId.BTC,\n },\n {\n name: 'Sui',\n chainType: ChainType.MVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/sui.svg',\n defaultChainId: ChainId.SUI,\n },\n {\n name: 'Tron',\n chainType: ChainType.TVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/tron.svg',\n defaultChainId: ChainId.TRN,\n },\n]\n\nconst maxChainAvatarsCount = 4\n\nexport const AllChainsAvatar: React.NamedExoticComponent<AllChainsAvatarProps> =\n memo(({ chains, size }: AllChainsAvatarProps): JSX.Element => {\n const icons = useMemo(() => {\n // Create maps for efficient lookups\n const chainsPerChainType = new Map<ChainType, number>()\n const chainsByChainType = new Map<\n ChainType,\n (ExtendedChain | EVMChain)[]\n >()\n\n chains.forEach((chain) => {\n chainsPerChainType.set(\n chain.chainType,\n (chainsPerChainType.get(chain.chainType) || 0) + 1\n )\n const chainsOfType = chainsByChainType.get(chain.chainType) || []\n chainsOfType.push(chain)\n chainsByChainType.set(chain.chainType, chainsOfType)\n })\n\n // Get existing ecosystem icons\n const existingChainTypeIcons = chainTypeIcons.filter(\n (predefinedChain) => {\n const numberOfChains =\n chainsPerChainType.get(predefinedChain.chainType) ?? 0\n\n // If there's only one chain of this type, check if it's not the default\n if (numberOfChains === 1) {\n const chainsOfType = chainsByChainType.get(\n predefinedChain.chainType\n )\n const singleChain = chainsOfType?.[0]\n // Exclude the predefined icon if the single chain is not the default\n if (\n singleChain &&\n singleChain.id !== predefinedChain.defaultChainId\n ) {\n return false\n }\n }\n\n return numberOfChains > 0\n }\n )\n\n if (existingChainTypeIcons.length === maxChainAvatarsCount) {\n return existingChainTypeIcons\n }\n\n const remainingSlots =\n maxChainAvatarsCount - existingChainTypeIcons.length\n\n // Create a Set for O(1) lookup of predefined icon names\n const predefinedIconNames = new Set(\n existingChainTypeIcons.map((icon) => icon.name)\n )\n\n const chainsWithLogos = chains.filter((chain) => {\n // Filter out chain icons matching ecosystem icons\n return !predefinedIconNames.has(chain.name) && Boolean(chain.logoURI)\n })\n\n const additionalIcons = chainsWithLogos\n .slice(0, remainingSlots)\n .map((chain) => ({\n name: chain.name,\n chainType: chain.chainType,\n icon: chain.logoURI!,\n }))\n\n return [...existingChainTypeIcons, ...additionalIcons]\n }, [chains])\n\n const wrapperSize = size === 'small' ? '32px' : '40px'\n const avatarSize = size === 'small' ? '12px' : '16px'\n const avatarsCount = Math.min(icons.length, maxChainAvatarsCount)\n const gridRows = avatarsCount > 2 ? 2 : 1\n const gridColumns = avatarsCount > 1 ? 2 : 1\n\n return (\n <Box\n sx={{\n width: wrapperSize,\n height: wrapperSize,\n display: 'grid',\n gridTemplateRows: `repeat(${gridRows}, 1fr)`,\n gridTemplateColumns: `repeat(${gridColumns}, 1fr)`,\n placeItems: 'center',\n }}\n >\n {icons.slice(0, avatarsCount).map((chain, idx) => {\n const isThirdAvatarInThreeAvatarLayout =\n avatarsCount === 3 && idx === 2\n\n return (\n <Avatar\n key={`${chain.chainType}-${idx}`}\n src={chain.icon}\n alt={chain.name}\n sx={{\n width: avatarSize,\n height: avatarSize,\n margin: 'auto',\n ...(isThirdAvatarInThreeAvatarLayout && {\n gridColumn: '1 / span 2',\n gridRow: '2',\n justifySelf: 'center',\n }),\n }}\n >\n {chain.chainType[0]}\n </Avatar>\n )\n })}\n </Box>\n )\n })\n"],"mappings":";;;;;AAeA,MAAM,iBAAiB;CACrB;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;AACF;AAEA,MAAM,uBAAuB;AAE7B,MAAa,kBACX,MAAM,EAAE,QAAQ,WAA8C;CAC5D,MAAM,QAAQ,cAAc;EAE1B,MAAM,qCAAqB,IAAI,IAAuB;EACtD,MAAM,oCAAoB,IAAI,IAG5B;EAEF,OAAO,SAAS,UAAU;GACxB,mBAAmB,IACjB,MAAM,YACL,mBAAmB,IAAI,MAAM,SAAS,KAAK,KAAK,CACnD;GACA,MAAM,eAAe,kBAAkB,IAAI,MAAM,SAAS,KAAK,CAAC;GAChE,aAAa,KAAK,KAAK;GACvB,kBAAkB,IAAI,MAAM,WAAW,YAAY;EACrD,CAAC;EAGD,MAAM,yBAAyB,eAAe,QAC3C,oBAAoB;GACnB,MAAM,iBACJ,mBAAmB,IAAI,gBAAgB,SAAS,KAAK;GAGvD,IAAI,mBAAmB,GAAG;IAIxB,MAAM,cAHe,kBAAkB,IACrC,gBAAgB,SAEa,CAAC,GAAG;IAEnC,IACE,eACA,YAAY,OAAO,gBAAgB,gBAEnC,OAAO;GAEX;GAEA,OAAO,iBAAiB;EAC1B,CACF;EAEA,IAAI,uBAAuB,WAAW,sBACpC,OAAO;EAGT,MAAM,iBACJ,uBAAuB,uBAAuB;EAGhD,MAAM,sBAAsB,IAAI,IAC9B,uBAAuB,KAAK,SAAS,KAAK,IAAI,CAChD;EAOA,MAAM,kBALkB,OAAO,QAAQ,UAAU;GAE/C,OAAO,CAAC,oBAAoB,IAAI,MAAM,IAAI,KAAK,QAAQ,MAAM,OAAO;EACtE,CAEsC,CAAC,CACpC,MAAM,GAAG,cAAc,CAAC,CACxB,KAAK,WAAW;GACf,MAAM,MAAM;GACZ,WAAW,MAAM;GACjB,MAAM,MAAM;EACd,EAAE;EAEJ,OAAO,CAAC,GAAG,wBAAwB,GAAG,eAAe;CACvD,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,cAAc,SAAS,UAAU,SAAS;CAChD,MAAM,aAAa,SAAS,UAAU,SAAS;CAC/C,MAAM,eAAe,KAAK,IAAI,MAAM,QAAQ,oBAAoB;CAChE,MAAM,WAAW,eAAe,IAAI,IAAI;CACxC,MAAM,cAAc,eAAe,IAAI,IAAI;CAE3C,OACE,oBAAC,KAAD;EACE,IAAI;GACF,OAAO;GACP,QAAQ;GACR,SAAS;GACT,kBAAkB,UAAU,SAAS;GACrC,qBAAqB,UAAU,YAAY;GAC3C,YAAY;EACd;EAEC,UAAA,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ;GAChD,MAAM,mCACJ,iBAAiB,KAAK,QAAQ;GAEhC,OACE,oBAAC,QAAD;IAEE,KAAK,MAAM;IACX,KAAK,MAAM;IACX,IAAI;KACF,OAAO;KACP,QAAQ;KACR,QAAQ;KACR,GAAI,oCAAoC;MACtC,YAAY;MACZ,SAAS;MACT,aAAa;KACf;IACF;IAEC,UAAA,MAAM,UAAU;GACX,GAfD,GAAG,MAAM,UAAU,GAAG,KAerB;EAEZ,CAAC;CACE,CAAA;AAET,CAAC"}
1
+ {"version":3,"file":"AllChainsAvatar.js","names":[],"sources":["../../../../src/components/Chains/AllChainsAvatar.tsx"],"sourcesContent":["import {\n ChainId,\n ChainType,\n type EVMChain,\n type ExtendedChain,\n} from '@lifi/sdk'\nimport { Avatar, Box } from '@mui/material'\nimport type React from 'react'\nimport { type JSX, memo, useMemo } from 'react'\n\ninterface AllChainsAvatarProps {\n chains: ExtendedChain[] | EVMChain[]\n size: 'small' | 'medium'\n}\n\nconst chainTypeIcons = [\n {\n name: 'Ethereum',\n chainType: ChainType.EVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/ethereum.svg',\n defaultChainId: ChainId.ETH,\n },\n {\n name: 'Solana',\n chainType: ChainType.SVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/solana.svg',\n defaultChainId: ChainId.SOL,\n },\n {\n name: 'Bitcoin',\n chainType: ChainType.UTXO,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/bitcoin.svg',\n defaultChainId: ChainId.BTC,\n },\n {\n name: 'Sui',\n chainType: ChainType.MVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/sui.svg',\n defaultChainId: ChainId.SUI,\n },\n {\n name: 'Tron',\n chainType: ChainType.TVM,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/tron.svg',\n defaultChainId: ChainId.TRN,\n },\n {\n name: 'Stellar',\n chainType: ChainType.STL,\n icon: 'https://lifinance.github.io/types/src/assets/icons/chains/stellar.svg',\n defaultChainId: ChainId.XLM,\n },\n]\n\nconst maxChainAvatarsCount = 4\n\nexport const AllChainsAvatar: React.NamedExoticComponent<AllChainsAvatarProps> =\n memo(({ chains, size }: AllChainsAvatarProps): JSX.Element => {\n const icons = useMemo(() => {\n // Create maps for efficient lookups\n const chainsPerChainType = new Map<ChainType, number>()\n const chainsByChainType = new Map<\n ChainType,\n (ExtendedChain | EVMChain)[]\n >()\n\n chains.forEach((chain) => {\n chainsPerChainType.set(\n chain.chainType,\n (chainsPerChainType.get(chain.chainType) || 0) + 1\n )\n const chainsOfType = chainsByChainType.get(chain.chainType) || []\n chainsOfType.push(chain)\n chainsByChainType.set(chain.chainType, chainsOfType)\n })\n\n // Get existing ecosystem icons\n const existingChainTypeIcons = chainTypeIcons.filter(\n (predefinedChain) => {\n const numberOfChains =\n chainsPerChainType.get(predefinedChain.chainType) ?? 0\n\n // If there's only one chain of this type, check if it's not the default\n if (numberOfChains === 1) {\n const chainsOfType = chainsByChainType.get(\n predefinedChain.chainType\n )\n const singleChain = chainsOfType?.[0]\n // Exclude the predefined icon if the single chain is not the default\n if (\n singleChain &&\n singleChain.id !== predefinedChain.defaultChainId\n ) {\n return false\n }\n }\n\n return numberOfChains > 0\n }\n )\n\n if (existingChainTypeIcons.length >= maxChainAvatarsCount) {\n return existingChainTypeIcons\n }\n\n const remainingSlots =\n maxChainAvatarsCount - existingChainTypeIcons.length\n\n // Create a Set for O(1) lookup of predefined icon names\n const predefinedIconNames = new Set(\n existingChainTypeIcons.map((icon) => icon.name)\n )\n\n const chainsWithLogos = chains.filter((chain) => {\n // Filter out chain icons matching ecosystem icons\n return !predefinedIconNames.has(chain.name) && Boolean(chain.logoURI)\n })\n\n const additionalIcons = chainsWithLogos\n .slice(0, remainingSlots)\n .map((chain) => ({\n name: chain.name,\n chainType: chain.chainType,\n icon: chain.logoURI!,\n }))\n\n return [...existingChainTypeIcons, ...additionalIcons]\n }, [chains])\n\n const wrapperSize = size === 'small' ? '32px' : '40px'\n const avatarSize = size === 'small' ? '12px' : '16px'\n const avatarsCount = Math.min(icons.length, maxChainAvatarsCount)\n const gridRows = avatarsCount > 2 ? 2 : 1\n const gridColumns = avatarsCount > 1 ? 2 : 1\n\n return (\n <Box\n sx={{\n width: wrapperSize,\n height: wrapperSize,\n display: 'grid',\n gridTemplateRows: `repeat(${gridRows}, 1fr)`,\n gridTemplateColumns: `repeat(${gridColumns}, 1fr)`,\n placeItems: 'center',\n }}\n >\n {icons.slice(0, avatarsCount).map((chain, idx) => {\n const isThirdAvatarInThreeAvatarLayout =\n avatarsCount === 3 && idx === 2\n\n return (\n <Avatar\n key={`${chain.chainType}-${idx}`}\n src={chain.icon}\n alt={chain.name}\n sx={{\n width: avatarSize,\n height: avatarSize,\n margin: 'auto',\n ...(isThirdAvatarInThreeAvatarLayout && {\n gridColumn: '1 / span 2',\n gridRow: '2',\n justifySelf: 'center',\n }),\n }}\n >\n {chain.chainType[0]}\n </Avatar>\n )\n })}\n </Box>\n )\n })\n"],"mappings":";;;;;AAeA,MAAM,iBAAiB;CACrB;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;CACA;EACE,MAAM;EACN,WAAW,UAAU;EACrB,MAAM;EACN,gBAAgB,QAAQ;CAC1B;AACF;AAEA,MAAM,uBAAuB;AAE7B,MAAa,kBACX,MAAM,EAAE,QAAQ,WAA8C;CAC5D,MAAM,QAAQ,cAAc;EAE1B,MAAM,qCAAqB,IAAI,IAAuB;EACtD,MAAM,oCAAoB,IAAI,IAG5B;EAEF,OAAO,SAAS,UAAU;GACxB,mBAAmB,IACjB,MAAM,YACL,mBAAmB,IAAI,MAAM,SAAS,KAAK,KAAK,CACnD;GACA,MAAM,eAAe,kBAAkB,IAAI,MAAM,SAAS,KAAK,CAAC;GAChE,aAAa,KAAK,KAAK;GACvB,kBAAkB,IAAI,MAAM,WAAW,YAAY;EACrD,CAAC;EAGD,MAAM,yBAAyB,eAAe,QAC3C,oBAAoB;GACnB,MAAM,iBACJ,mBAAmB,IAAI,gBAAgB,SAAS,KAAK;GAGvD,IAAI,mBAAmB,GAAG;IAIxB,MAAM,cAHe,kBAAkB,IACrC,gBAAgB,SAEa,CAAC,GAAG;IAEnC,IACE,eACA,YAAY,OAAO,gBAAgB,gBAEnC,OAAO;GAEX;GAEA,OAAO,iBAAiB;EAC1B,CACF;EAEA,IAAI,uBAAuB,UAAU,sBACnC,OAAO;EAGT,MAAM,iBACJ,uBAAuB,uBAAuB;EAGhD,MAAM,sBAAsB,IAAI,IAC9B,uBAAuB,KAAK,SAAS,KAAK,IAAI,CAChD;EAOA,MAAM,kBALkB,OAAO,QAAQ,UAAU;GAE/C,OAAO,CAAC,oBAAoB,IAAI,MAAM,IAAI,KAAK,QAAQ,MAAM,OAAO;EACtE,CAEsC,CAAC,CACpC,MAAM,GAAG,cAAc,CAAC,CACxB,KAAK,WAAW;GACf,MAAM,MAAM;GACZ,WAAW,MAAM;GACjB,MAAM,MAAM;EACd,EAAE;EAEJ,OAAO,CAAC,GAAG,wBAAwB,GAAG,eAAe;CACvD,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,cAAc,SAAS,UAAU,SAAS;CAChD,MAAM,aAAa,SAAS,UAAU,SAAS;CAC/C,MAAM,eAAe,KAAK,IAAI,MAAM,QAAQ,oBAAoB;CAChE,MAAM,WAAW,eAAe,IAAI,IAAI;CACxC,MAAM,cAAc,eAAe,IAAI,IAAI;CAE3C,OACE,oBAAC,KAAD;EACE,IAAI;GACF,OAAO;GACP,QAAQ;GACR,SAAS;GACT,kBAAkB,UAAU,SAAS;GACrC,qBAAqB,UAAU,YAAY;GAC3C,YAAY;EACd;EAEC,UAAA,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,KAAK,OAAO,QAAQ;GAChD,MAAM,mCACJ,iBAAiB,KAAK,QAAQ;GAEhC,OACE,oBAAC,QAAD;IAEE,KAAK,MAAM;IACX,KAAK,MAAM;IACX,IAAI;KACF,OAAO;KACP,QAAQ;KACR,QAAQ;KACR,GAAI,oCAAoC;MACtC,YAAY;MACZ,SAAS;MACT,aAAa;KACf;IACF;IAEC,UAAA,MAAM,UAAU;GACX,GAfD,GAAG,MAAM,UAAU,GAAG,KAerB;EAEZ,CAAC;CACE,CAAA;AAET,CAAC"}
@@ -21,8 +21,9 @@ const slotProps = {
21
21
  } }
22
22
  };
23
23
  const Dialog$1 = ({ children, open, onClose }) => {
24
+ const getContainer = useGetScrollableContainer();
24
25
  return /* @__PURE__ */ jsx(Dialog, {
25
- container: useGetScrollableContainer(),
26
+ container: getContainer,
26
27
  open,
27
28
  onClose,
28
29
  sx: modalProps.sx,
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.js","names":["Dialog","MuiDialog"],"sources":["../../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import type { DialogProps, Theme } from '@mui/material'\nimport { Dialog as MuiDialog } from '@mui/material'\nimport type { PropsWithChildren } from 'react'\nimport { useGetScrollableContainer } from '../../hooks/useScrollableContainer.js'\n\nexport const modalProps: { sx: { position: string; overflow: string } } = {\n sx: {\n position: 'absolute',\n overflow: 'hidden',\n },\n}\n\nexport const slotProps: DialogProps['slotProps'] = {\n paper: {\n sx: (theme: Theme) => ({\n position: 'absolute',\n backgroundImage: 'none',\n backgroundColor: theme.vars.palette.background.default,\n borderTopLeftRadius: theme.vars.shape.borderRadius,\n borderTopRightRadius: theme.vars.shape.borderRadius,\n }),\n },\n backdrop: {\n sx: {\n position: 'absolute',\n backgroundColor: 'rgb(0 0 0 / 32%)',\n backdropFilter: 'blur(3px)',\n },\n },\n}\n\nexport const Dialog: React.FC<PropsWithChildren<DialogProps>> = ({\n children,\n open,\n onClose,\n}) => {\n const getContainer = useGetScrollableContainer()\n return (\n <MuiDialog\n container={getContainer}\n open={open}\n onClose={onClose}\n sx={modalProps.sx}\n slotProps={slotProps}\n >\n {children}\n </MuiDialog>\n )\n}\n"],"mappings":";;;;AAKA,MAAa,aAA6D,EACxE,IAAI;CACF,UAAU;CACV,UAAU;AACZ,EACF;AAEA,MAAa,YAAsC;CACjD,OAAO,EACL,KAAK,WAAkB;EACrB,UAAU;EACV,iBAAiB;EACjB,iBAAiB,MAAM,KAAK,QAAQ,WAAW;EAC/C,qBAAqB,MAAM,KAAK,MAAM;EACtC,sBAAsB,MAAM,KAAK,MAAM;CACzC,GACF;CACA,UAAU,EACR,IAAI;EACF,UAAU;EACV,iBAAiB;EACjB,gBAAgB;CAClB,EACF;AACF;AAEA,MAAaA,YAAoD,EAC/D,UACA,MACA,cACI;CAEJ,OACE,oBAACC,QAAD;EACE,WAHiB,0BAGK;EAChB;EACG;EACT,IAAI,WAAW;EACJ;EAEV;CACQ,CAAA;AAEf"}
1
+ {"version":3,"file":"Dialog.js","names":["Dialog","MuiDialog"],"sources":["../../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import type { DialogProps, Theme } from '@mui/material'\nimport { Dialog as MuiDialog } from '@mui/material'\nimport type { PropsWithChildren } from 'react'\nimport { useGetScrollableContainer } from '../../hooks/useScrollableContainer.js'\n\nexport const modalProps: { sx: { position: string; overflow: string } } = {\n sx: {\n position: 'absolute',\n overflow: 'hidden',\n },\n}\n\nexport const slotProps: DialogProps['slotProps'] = {\n paper: {\n sx: (theme: Theme) => ({\n position: 'absolute',\n backgroundImage: 'none',\n backgroundColor: theme.vars.palette.background.default,\n borderTopLeftRadius: theme.vars.shape.borderRadius,\n borderTopRightRadius: theme.vars.shape.borderRadius,\n }),\n },\n backdrop: {\n sx: {\n position: 'absolute',\n backgroundColor: 'rgb(0 0 0 / 32%)',\n backdropFilter: 'blur(3px)',\n },\n },\n}\n\nexport const Dialog: React.FC<PropsWithChildren<DialogProps>> = ({\n children,\n open,\n onClose,\n}) => {\n const getContainer = useGetScrollableContainer()\n return (\n <MuiDialog\n container={getContainer}\n open={open}\n onClose={onClose}\n sx={modalProps.sx}\n slotProps={slotProps}\n >\n {children}\n </MuiDialog>\n )\n}\n"],"mappings":";;;;AAKA,MAAa,aAA6D,EACxE,IAAI;CACF,UAAU;CACV,UAAU;AACZ,EACF;AAEA,MAAa,YAAsC;CACjD,OAAO,EACL,KAAK,WAAkB;EACrB,UAAU;EACV,iBAAiB;EACjB,iBAAiB,MAAM,KAAK,QAAQ,WAAW;EAC/C,qBAAqB,MAAM,KAAK,MAAM;EACtC,sBAAsB,MAAM,KAAK,MAAM;CACzC,GACF;CACA,UAAU,EACR,IAAI;EACF,UAAU;EACV,iBAAiB;EACjB,gBAAgB;CAClB,EACF;AACF;AAEA,MAAaA,YAAoD,EAC/D,UACA,MACA,cACI;CACJ,MAAM,eAAe,0BAA0B;CAC/C,OACE,oBAACC,QAAD;EACE,WAAW;EACL;EACG;EACT,IAAI,WAAW;EACJ;EAEV;CACQ,CAAA;AAEf"}
@@ -13,10 +13,11 @@ function Expansion() {
13
13
  const chainExpansionTypeRef = useRef(expansionType);
14
14
  const [routesOpen, setRoutesOpen] = useState(false);
15
15
  if (expansionType === "fromChain" || expansionType === "toChain") chainExpansionTypeRef.current = expansionType;
16
+ const containerWidth = useMemo(() => {
17
+ return routesOpen ? routesExpansionWidth : withChainExpansion ? chainExpansionWidth : 0;
18
+ }, [routesOpen, withChainExpansion]);
16
19
  return /* @__PURE__ */ jsxs(ExpansionContainer, {
17
- width: useMemo(() => {
18
- return routesOpen ? routesExpansionWidth : withChainExpansion ? chainExpansionWidth : 0;
19
- }, [routesOpen, withChainExpansion]),
20
+ width: containerWidth,
20
21
  children: [/* @__PURE__ */ jsx(RoutesExpanded, {
21
22
  canOpen: expansionType === "routes",
22
23
  setOpenExpansion: setRoutesOpen
@@ -1 +1 @@
1
- {"version":3,"file":"Expansion.js","names":[],"sources":["../../../../src/components/Expansion/Expansion.tsx"],"sourcesContent":["import { type JSX, useMemo, useRef, useState } from 'react'\nimport { useHasChainExpansion } from '../../hooks/useHasChainExpansion.js'\nimport { ExpansionType } from '../../types/widget.js'\nimport { ChainsExpanded } from '../Chains/ChainsExpanded.js'\nimport { chainExpansionWidth } from '../Chains/ChainsExpanded.style.js'\nimport { RoutesExpanded } from '../Routes/RoutesExpanded.js'\nimport { routesExpansionWidth } from '../Routes/RoutesExpanded.style.js'\nimport { ExpansionContainer } from './Expansion.style.js'\n\nexport function Expansion(): JSX.Element {\n const [withChainExpansion, expansionType] = useHasChainExpansion()\n const chainExpansionTypeRef = useRef<ExpansionType>(expansionType)\n const [routesOpen, setRoutesOpen] = useState(false)\n\n // Track the previous chain expansion type to avoid re-renders when transitioning to Routes\n if (\n expansionType === ExpansionType.FromChain ||\n expansionType === ExpansionType.ToChain\n ) {\n chainExpansionTypeRef.current = expansionType\n }\n\n const containerWidth = useMemo(() => {\n return routesOpen\n ? routesExpansionWidth\n : withChainExpansion\n ? chainExpansionWidth\n : 0\n }, [routesOpen, withChainExpansion])\n\n return (\n <ExpansionContainer width={containerWidth}>\n <RoutesExpanded\n canOpen={expansionType === ExpansionType.Routes}\n setOpenExpansion={setRoutesOpen}\n />\n <ChainsExpanded\n formType={\n chainExpansionTypeRef.current === ExpansionType.FromChain\n ? 'from'\n : 'to'\n }\n open={withChainExpansion}\n />\n </ExpansionContainer>\n )\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,YAAyB;CACvC,MAAM,CAAC,oBAAoB,iBAAiB,qBAAqB;CACjE,MAAM,wBAAwB,OAAsB,aAAa;CACjE,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAGlD,IACE,kBAAA,eACA,kBAAA,WAEA,sBAAsB,UAAU;CAWlC,OACE,qBAAC,oBAAD;EAAoB,OATC,cAAc;GACnC,OAAO,aACH,uBACA,qBACE,sBACA;EACR,GAAG,CAAC,YAAY,kBAAkB,CAGQ;EAAxC,UAAA,CACE,oBAAC,gBAAD;GACE,SAAS,kBAAA;GACT,kBAAkB;EACnB,CAAA,GACD,oBAAC,gBAAD;GACE,UACE,sBAAsB,YAAA,cAClB,SACA;GAEN,MAAM;EACP,CAAA,CACiB;;AAExB"}
1
+ {"version":3,"file":"Expansion.js","names":[],"sources":["../../../../src/components/Expansion/Expansion.tsx"],"sourcesContent":["import { type JSX, useMemo, useRef, useState } from 'react'\nimport { useHasChainExpansion } from '../../hooks/useHasChainExpansion.js'\nimport { ExpansionType } from '../../types/widget.js'\nimport { ChainsExpanded } from '../Chains/ChainsExpanded.js'\nimport { chainExpansionWidth } from '../Chains/ChainsExpanded.style.js'\nimport { RoutesExpanded } from '../Routes/RoutesExpanded.js'\nimport { routesExpansionWidth } from '../Routes/RoutesExpanded.style.js'\nimport { ExpansionContainer } from './Expansion.style.js'\n\nexport function Expansion(): JSX.Element {\n const [withChainExpansion, expansionType] = useHasChainExpansion()\n const chainExpansionTypeRef = useRef<ExpansionType>(expansionType)\n const [routesOpen, setRoutesOpen] = useState(false)\n\n // Track the previous chain expansion type to avoid re-renders when transitioning to Routes\n if (\n expansionType === ExpansionType.FromChain ||\n expansionType === ExpansionType.ToChain\n ) {\n chainExpansionTypeRef.current = expansionType\n }\n\n const containerWidth = useMemo(() => {\n return routesOpen\n ? routesExpansionWidth\n : withChainExpansion\n ? chainExpansionWidth\n : 0\n }, [routesOpen, withChainExpansion])\n\n return (\n <ExpansionContainer width={containerWidth}>\n <RoutesExpanded\n canOpen={expansionType === ExpansionType.Routes}\n setOpenExpansion={setRoutesOpen}\n />\n <ChainsExpanded\n formType={\n chainExpansionTypeRef.current === ExpansionType.FromChain\n ? 'from'\n : 'to'\n }\n open={withChainExpansion}\n />\n </ExpansionContainer>\n )\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,YAAyB;CACvC,MAAM,CAAC,oBAAoB,iBAAiB,qBAAqB;CACjE,MAAM,wBAAwB,OAAsB,aAAa;CACjE,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAGlD,IACE,kBAAA,eACA,kBAAA,WAEA,sBAAsB,UAAU;CAGlC,MAAM,iBAAiB,cAAc;EACnC,OAAO,aACH,uBACA,qBACE,sBACA;CACR,GAAG,CAAC,YAAY,kBAAkB,CAAC;CAEnC,OACE,qBAAC,oBAAD;EAAoB,OAAO;EAA3B,UAAA,CACE,oBAAC,gBAAD;GACE,SAAS,kBAAA;GACT,kBAAkB;EACnB,CAAA,GACD,oBAAC,gBAAD;GACE,UACE,sBAAsB,YAAA,cAClB,SACA;GAEN,MAAM;EACP,CAAA,CACiB;;AAExB"}
@@ -12,8 +12,9 @@ const SettingsButton = () => {
12
12
  const navigate = useNavigate();
13
13
  const { isCustomRouteSettings, isRouteSettingsWithWarnings } = useSettingMonitor();
14
14
  const variant = isRouteSettingsWithWarnings ? "warning" : isCustomRouteSettings ? "info" : void 0;
15
+ const tooltipMessage = variant ? t("tooltip.settingsModified") : t("header.settings");
15
16
  return /* @__PURE__ */ jsx(Tooltip, {
16
- title: variant ? t("tooltip.settingsModified") : t("header.settings"),
17
+ title: tooltipMessage,
17
18
  children: /* @__PURE__ */ jsx(SettingsIconButton, {
18
19
  size: "medium",
19
20
  onClick: () => navigate({ to: navigationRoutes.settings }),
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsButton.js","names":[],"sources":["../../../../src/components/Header/SettingsButton.tsx"],"sourcesContent":["import Settings from '@mui/icons-material/Settings'\nimport { Tooltip } from '@mui/material'\nimport { useNavigate } from '@tanstack/react-router'\nimport type { JSX } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useSettingMonitor } from '../../hooks/useSettingMonitor.js'\nimport { navigationRoutes } from '../../utils/navigationRoutes.js'\nimport {\n SettingsIconBadge,\n SettingsIconButton,\n} from './SettingsButton.style.js'\n\nexport const SettingsButton = (): JSX.Element => {\n const { t } = useTranslation()\n const navigate = useNavigate()\n\n const { isCustomRouteSettings, isRouteSettingsWithWarnings } =\n useSettingMonitor()\n\n const variant = isRouteSettingsWithWarnings\n ? 'warning'\n : isCustomRouteSettings\n ? 'info'\n : undefined\n\n const tooltipMessage = variant\n ? t('tooltip.settingsModified')\n : t('header.settings')\n\n return (\n <Tooltip title={tooltipMessage}>\n <SettingsIconButton\n size=\"medium\"\n onClick={() => navigate({ to: navigationRoutes.settings })}\n variant={variant}\n >\n {variant ? (\n <SettingsIconBadge variant=\"dot\" color={variant}>\n <Settings />\n </SettingsIconBadge>\n ) : (\n <Settings />\n )}\n </SettingsIconButton>\n </Tooltip>\n )\n}\n"],"mappings":";;;;;;;;;AAYA,MAAa,uBAAoC;CAC/C,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAE7B,MAAM,EAAE,uBAAuB,gCAC7B,kBAAkB;CAEpB,MAAM,UAAU,8BACZ,YACA,wBACE,SACA,KAAA;CAMN,OACE,oBAAC,SAAD;EAAS,OALY,UACnB,EAAE,0BAA0B,IAC5B,EAAE,iBAAiB;EAInB,UAAA,oBAAC,oBAAD;GACE,MAAK;GACL,eAAe,SAAS,EAAE,IAAI,iBAAiB,SAAS,CAAC;GAChD;GAER,UAAA,UACC,oBAAC,mBAAD;IAAmB,SAAQ;IAAM,OAAO;IACtC,UAAA,oBAAC,UAAD,CAAW,CAAA;GACM,CAAA,IAEnB,oBAAC,UAAD,CAAW,CAAA;EAEK,CAAA;CACb,CAAA;AAEb"}
1
+ {"version":3,"file":"SettingsButton.js","names":[],"sources":["../../../../src/components/Header/SettingsButton.tsx"],"sourcesContent":["import Settings from '@mui/icons-material/Settings'\nimport { Tooltip } from '@mui/material'\nimport { useNavigate } from '@tanstack/react-router'\nimport type { JSX } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useSettingMonitor } from '../../hooks/useSettingMonitor.js'\nimport { navigationRoutes } from '../../utils/navigationRoutes.js'\nimport {\n SettingsIconBadge,\n SettingsIconButton,\n} from './SettingsButton.style.js'\n\nexport const SettingsButton = (): JSX.Element => {\n const { t } = useTranslation()\n const navigate = useNavigate()\n\n const { isCustomRouteSettings, isRouteSettingsWithWarnings } =\n useSettingMonitor()\n\n const variant = isRouteSettingsWithWarnings\n ? 'warning'\n : isCustomRouteSettings\n ? 'info'\n : undefined\n\n const tooltipMessage = variant\n ? t('tooltip.settingsModified')\n : t('header.settings')\n\n return (\n <Tooltip title={tooltipMessage}>\n <SettingsIconButton\n size=\"medium\"\n onClick={() => navigate({ to: navigationRoutes.settings })}\n variant={variant}\n >\n {variant ? (\n <SettingsIconBadge variant=\"dot\" color={variant}>\n <Settings />\n </SettingsIconBadge>\n ) : (\n <Settings />\n )}\n </SettingsIconButton>\n </Tooltip>\n )\n}\n"],"mappings":";;;;;;;;;AAYA,MAAa,uBAAoC;CAC/C,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAE7B,MAAM,EAAE,uBAAuB,gCAC7B,kBAAkB;CAEpB,MAAM,UAAU,8BACZ,YACA,wBACE,SACA,KAAA;CAEN,MAAM,iBAAiB,UACnB,EAAE,0BAA0B,IAC5B,EAAE,iBAAiB;CAEvB,OACE,oBAAC,SAAD;EAAS,OAAO;EACd,UAAA,oBAAC,oBAAD;GACE,MAAK;GACL,eAAe,SAAS,EAAE,IAAI,iBAAiB,SAAS,CAAC;GAChD;GAER,UAAA,UACC,oBAAC,mBAAD;IAAmB,SAAQ;IAAM,OAAO;IACtC,UAAA,oBAAC,UAAD,CAAW,CAAA;GACM,CAAA,IAEnB,oBAAC,UAAD,CAAW,CAAA;EAEK,CAAA;CACb,CAAA;AAEb"}
@@ -4,7 +4,8 @@ import { useTheme } from "@mui/material";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/components/IconCircle/IconCircle.tsx
6
6
  const IconCircle = ({ status, size = 90, ...rest }) => {
7
- const colorConfig = getStatusColor(status, useTheme());
7
+ const theme = useTheme();
8
+ const colorConfig = getStatusColor(status, theme);
8
9
  const Icon = statusIcons[status];
9
10
  return /* @__PURE__ */ jsx(IconCircleRoot, {
10
11
  colorConfig,
@@ -1 +1 @@
1
- {"version":3,"file":"IconCircle.js","names":[],"sources":["../../../../src/components/IconCircle/IconCircle.tsx"],"sourcesContent":["import type { BoxProps } from '@mui/material'\nimport { useTheme } from '@mui/material'\nimport {\n getStatusColor,\n IconCircleRoot,\n iconCircleSize,\n} from './IconCircle.style.js'\nimport { type StatusIcon, statusIcons } from './statusIcons.js'\n\ninterface IconCircleProps extends Omit<BoxProps, 'color'> {\n status: StatusIcon\n size?: number\n}\n\nexport const IconCircle: React.FC<IconCircleProps> = ({\n status,\n size = iconCircleSize,\n ...rest\n}) => {\n const theme = useTheme()\n const colorConfig = getStatusColor(status, theme)\n const Icon = statusIcons[status]\n\n return (\n <IconCircleRoot colorConfig={colorConfig} circleSize={size} {...rest}>\n <Icon />\n </IconCircleRoot>\n )\n}\n"],"mappings":";;;;;AAcA,MAAa,cAAyC,EACpD,QACA,OAAA,IACA,GAAG,WACC;CAEJ,MAAM,cAAc,eAAe,QADrB,SACiC,CAAC;CAChD,MAAM,OAAO,YAAY;CAEzB,OACE,oBAAC,gBAAD;EAA6B;EAAa,YAAY;EAAM,GAAI;EAC9D,UAAA,oBAAC,MAAD,CAAO,CAAA;CACO,CAAA;AAEpB"}
1
+ {"version":3,"file":"IconCircle.js","names":[],"sources":["../../../../src/components/IconCircle/IconCircle.tsx"],"sourcesContent":["import type { BoxProps } from '@mui/material'\nimport { useTheme } from '@mui/material'\nimport {\n getStatusColor,\n IconCircleRoot,\n iconCircleSize,\n} from './IconCircle.style.js'\nimport { type StatusIcon, statusIcons } from './statusIcons.js'\n\ninterface IconCircleProps extends Omit<BoxProps, 'color'> {\n status: StatusIcon\n size?: number\n}\n\nexport const IconCircle: React.FC<IconCircleProps> = ({\n status,\n size = iconCircleSize,\n ...rest\n}) => {\n const theme = useTheme()\n const colorConfig = getStatusColor(status, theme)\n const Icon = statusIcons[status]\n\n return (\n <IconCircleRoot colorConfig={colorConfig} circleSize={size} {...rest}>\n <Icon />\n </IconCircleRoot>\n )\n}\n"],"mappings":";;;;;AAcA,MAAa,cAAyC,EACpD,QACA,OAAA,IACA,GAAG,WACC;CACJ,MAAM,QAAQ,SAAS;CACvB,MAAM,cAAc,eAAe,QAAQ,KAAK;CAChD,MAAM,OAAO,YAAY;CAEzB,OACE,oBAAC,gBAAD;EAA6B;EAAa,YAAY;EAAM,GAAI;EAC9D,UAAA,oBAAC,MAAD,CAAO,CAAA;CACO,CAAA;AAEpB"}
@@ -0,0 +1,27 @@
1
+ import { AlertMessage } from "./AlertMessage.js";
2
+ import { Typography } from "@mui/material";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { useTranslation } from "react-i18next";
5
+ import WarningRounded from "@mui/icons-material/WarningRounded";
6
+ //#region src/components/Messages/UnsupportedToAddressMessage.tsx
7
+ const UnsupportedToAddressMessage = ({ ...props }) => {
8
+ const { t } = useTranslation();
9
+ return /* @__PURE__ */ jsx(AlertMessage, {
10
+ title: /* @__PURE__ */ jsx(Typography, {
11
+ variant: "body2",
12
+ sx: {
13
+ px: 1,
14
+ color: "text.primary"
15
+ },
16
+ children: t("info.message.unsupportedToAddressMessage")
17
+ }),
18
+ icon: /* @__PURE__ */ jsx(WarningRounded, {}),
19
+ severity: "warning",
20
+ multiline: true,
21
+ ...props
22
+ });
23
+ };
24
+ //#endregion
25
+ export { UnsupportedToAddressMessage };
26
+
27
+ //# sourceMappingURL=UnsupportedToAddressMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnsupportedToAddressMessage.js","names":[],"sources":["../../../../src/components/Messages/UnsupportedToAddressMessage.tsx"],"sourcesContent":["import WarningRounded from '@mui/icons-material/WarningRounded'\nimport type { BoxProps } from '@mui/material'\nimport { Typography } from '@mui/material'\nimport { useTranslation } from 'react-i18next'\nimport { AlertMessage } from './AlertMessage.js'\n\nexport const UnsupportedToAddressMessage: React.FC<BoxProps> = ({\n ...props\n}) => {\n const { t } = useTranslation()\n return (\n <AlertMessage\n title={\n <Typography variant=\"body2\" sx={{ px: 1, color: 'text.primary' }}>\n {t('info.message.unsupportedToAddressMessage')}\n </Typography>\n }\n icon={<WarningRounded />}\n severity=\"warning\"\n multiline\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;AAMA,MAAa,+BAAmD,EAC9D,GAAG,YACC;CACJ,MAAM,EAAE,MAAM,eAAe;CAC7B,OACE,oBAAC,cAAD;EACE,OACE,oBAAC,YAAD;GAAY,SAAQ;GAAQ,IAAI;IAAE,IAAI;IAAG,OAAO;GAAe;GAC5D,UAAA,EAAE,0CAA0C;EACnC,CAAA;EAEd,MAAM,oBAAC,gBAAD,CAAiB,CAAA;EACvB,UAAS;EACT,WAAA;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -1 +1 @@
1
- {"version":3,"file":"WarningMessages.d.ts","names":[],"sources":["../../../../src/components/Messages/WarningMessages.tsx"],"mappings":";;;KAWK,uBAAuB;EAC1B,QAAQ;EACR;;cAGW,iBAAiB,MAAM,GAAG"}
1
+ {"version":3,"file":"WarningMessages.d.ts","names":[],"sources":["../../../../src/components/Messages/WarningMessages.tsx"],"mappings":";;;KAYK,uBAAuB;EAC1B,QAAQ;EACR;;cAGW,iBAAiB,MAAM,GAAG"}
@@ -4,6 +4,7 @@ import { FundsSufficiencyMessage } from "./FundsSufficiencyMessage.js";
4
4
  import { GasSufficiencyMessage } from "./GasSufficiencyMessage.js";
5
5
  import { MinFromAmountUSDMessage } from "./MinFromAmountUSDMessage.js";
6
6
  import { MissingRouteRequiredAccountMessage } from "./MissingRouteRequiredAccountMessage.js";
7
+ import { UnsupportedToAddressMessage } from "./UnsupportedToAddressMessage.js";
7
8
  import { useMessageQueue } from "./useMessageQueue.js";
8
9
  import { Collapse } from "@mui/material";
9
10
  import { jsx } from "react/jsx-runtime";
@@ -28,6 +29,7 @@ const WarningMessages = ({ route, allowInteraction, ...props }) => {
28
29
  });
29
30
  case "ACCOUNT_NOT_DEPLOYED": return /* @__PURE__ */ jsx(AccountNotDeployedMessage, { ...props });
30
31
  case "ACCOUNT_DEPLOYED": return /* @__PURE__ */ jsx(AccountDeployedMessage, { ...props });
32
+ case "UNSUPPORTED_TO_ADDRESS": return /* @__PURE__ */ jsx(UnsupportedToAddressMessage, { ...props });
31
33
  default: return null;
32
34
  }
33
35
  };