@lifi/widget 4.4.0 → 4.5.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.
- package/dist/esm/App.js.map +1 -1
- package/dist/esm/AppDrawer.js.map +1 -1
- package/dist/esm/AppLayout.js.map +1 -1
- package/dist/esm/AppProvider.js.map +1 -1
- package/dist/esm/components/ActionRow/ActionRow.js.map +1 -1
- package/dist/esm/components/AmountInput/AmountInput.js.map +1 -1
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
- package/dist/esm/components/AmountInput/PriceFormHelperText.js.map +1 -1
- package/dist/esm/components/AmountInputCard/AmountInputCardPair.js.map +1 -1
- package/dist/esm/components/AmountInputCard/BalanceDisplay.js.map +1 -1
- package/dist/esm/components/AmountInputCard/FiatValueToggle.js.map +1 -1
- package/dist/esm/components/AmountInputCard/PercentageChips.js.map +1 -1
- package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js.map +1 -1
- package/dist/esm/components/AmountInputCard/SendAmountCard.js.map +1 -1
- package/dist/esm/components/AppContainer.js.map +1 -1
- package/dist/esm/components/Avatar/AccountAvatar.js.map +1 -1
- package/dist/esm/components/Avatar/Avatar.js.map +1 -1
- package/dist/esm/components/Avatar/ChainBadgeContent.js.map +1 -1
- package/dist/esm/components/Avatar/TokenAvatar.js.map +1 -1
- package/dist/esm/components/BaseTransactionButton/BaseTransactionButton.js.map +1 -1
- package/dist/esm/components/Card/CardButton.js.map +1 -1
- package/dist/esm/components/ChainSelect/ChainSelect.js.map +1 -1
- package/dist/esm/components/Chains/AllChainsAvatar.js.map +1 -1
- package/dist/esm/components/Chains/ChainList.js.map +1 -1
- package/dist/esm/components/Chains/ChainListItem.js.map +1 -1
- package/dist/esm/components/Chains/ChainsExpanded.js.map +1 -1
- package/dist/esm/components/Chains/PinChainButton.js.map +1 -1
- package/dist/esm/components/Chains/SelectChainExpansionContent.js.map +1 -1
- package/dist/esm/components/Chains/SelectChainPageContent.js.map +1 -1
- package/dist/esm/components/Chains/VirtualizedChainList.js.map +1 -1
- package/dist/esm/components/ContextMenu.js.map +1 -1
- package/dist/esm/components/ContractComponent/NFT/NFTBase.js.map +1 -1
- package/dist/esm/components/ExecutionStatusCard/ExecutionChecklist.js.map +1 -1
- package/dist/esm/components/ExecutionStatusCard/ExecutionStatusCard.js.map +1 -1
- package/dist/esm/components/ExecutionStatusCard/StaggeredRevealTypography.js.map +1 -1
- package/dist/esm/components/ExecutionStatusCard/StatusIcon.js.map +1 -1
- package/dist/esm/components/Expansion/Expansion.js.map +1 -1
- package/dist/esm/components/Expansion/ExpansionTransition.js.map +1 -1
- package/dist/esm/components/FeeBreakdownTooltip.js.map +1 -1
- package/dist/esm/components/Header/ActivitiesButton.js.map +1 -1
- package/dist/esm/components/Header/BackButton.js.map +1 -1
- package/dist/esm/components/Header/CloseDrawerButton.js.map +1 -1
- package/dist/esm/components/Header/DisconnectIconButton.js.map +1 -1
- package/dist/esm/components/Header/HeaderTabs.js.map +1 -1
- package/dist/esm/components/Header/NavigationHeader.js.map +1 -1
- package/dist/esm/components/Header/SettingsButton.js.map +1 -1
- package/dist/esm/components/Header/WalletHeader.js.map +1 -1
- package/dist/esm/components/Header/WalletMenu.js.map +1 -1
- package/dist/esm/components/IconCircle/IconCircle.js.map +1 -1
- package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.js.map +1 -1
- package/dist/esm/components/LimitPriceCard/LimitPriceCard.js.map +1 -1
- package/dist/esm/components/LimitPriceCard/LimitPricePresets.js.map +1 -1
- package/dist/esm/components/Messages/AccountDeployedMessage.js.map +1 -1
- package/dist/esm/components/Messages/AccountNotDeployedMessage.js.map +1 -1
- package/dist/esm/components/Messages/AlertMessage.js.map +1 -1
- package/dist/esm/components/Messages/FundsSufficiencyMessage.js.map +1 -1
- package/dist/esm/components/Messages/GasRefuelMessage.js.map +1 -1
- package/dist/esm/components/Messages/GasSufficiencyMessage.js.map +1 -1
- package/dist/esm/components/Messages/MinFromAmountUSDMessage.js.map +1 -1
- package/dist/esm/components/Messages/MissingRouteRequiredAccountMessage.js.map +1 -1
- package/dist/esm/components/Messages/WarningMessages.js.map +1 -1
- package/dist/esm/components/NotFound.js.map +1 -1
- package/dist/esm/components/PoweredBy/PoweredBy.js.map +1 -1
- package/dist/esm/components/ProgressToNextUpdate.js.map +1 -1
- package/dist/esm/components/ReverseTokensButton/ReverseTokensButton.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteCard.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteCardEssentials.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteCardSkeleton.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteDetails.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteNotFoundCard.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteProviderCard.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteToken.js.map +1 -1
- package/dist/esm/components/RouteCard/RouteTokens.js.map +1 -1
- package/dist/esm/components/Routes/LimitOrderRoutes.js.map +1 -1
- package/dist/esm/components/Routes/Routes.js.map +1 -1
- package/dist/esm/components/Routes/RoutesContent.js.map +1 -1
- package/dist/esm/components/Routes/RoutesExpanded.js.map +1 -1
- package/dist/esm/components/Search/SearchInput.js.map +1 -1
- package/dist/esm/components/SelectChainAndToken.js.map +1 -1
- package/dist/esm/components/SelectTokenButton/SelectTokenButton.js.map +1 -1
- package/dist/esm/components/SendToWallet/SendToWalletButton.js.map +1 -1
- package/dist/esm/components/SendToWallet/SendToWalletExpandButton.js.map +1 -1
- package/dist/esm/components/SettingsPanel/SettingsPanel.js.map +1 -1
- package/dist/esm/components/Skeleton/WidgetSkeleton.js.map +1 -1
- package/dist/esm/components/Step/StepActions.js.map +1 -1
- package/dist/esm/components/StepActions/SentToWalletRow.js.map +1 -1
- package/dist/esm/components/StepActions/StepActionRow.js.map +1 -1
- package/dist/esm/components/StepActions/StepActionsList.js.map +1 -1
- package/dist/esm/components/SwapButton/SwapButton.js.map +1 -1
- package/dist/esm/components/TextFitter/TextFitter.js.map +1 -1
- package/dist/esm/components/Timer/StepStatusTimer.js.map +1 -1
- package/dist/esm/components/Token/Token.js.map +1 -1
- package/dist/esm/components/TokenList/PinTokenButton.js.map +1 -1
- package/dist/esm/components/TokenList/TokenDetailsSheet.js.map +1 -1
- package/dist/esm/components/TokenList/TokenDetailsSheetContent.js.map +1 -1
- package/dist/esm/components/TokenList/TokenList.js.map +1 -1
- package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
- package/dist/esm/components/TokenList/VirtualizedTokenList.js.map +1 -1
- package/dist/esm/components/TokenPillButton/TokenPillButton.js.map +1 -1
- package/dist/esm/components/TokenRate/TokenRate.js.map +1 -1
- package/dist/esm/components/Tools/ToolItem.js.map +1 -1
- package/dist/esm/components/Tools/Tools.js.map +1 -1
- package/dist/esm/components/TransactionCard/ActiveTransactionCard.js.map +1 -1
- package/dist/esm/components/TransactionCard/TransactionCard.js.map +1 -1
- package/dist/esm/components/TransactionCard/TransactionCardSkeleton.js.map +1 -1
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/config/version.js.map +1 -1
- package/dist/esm/hooks/useAccountsBalancesData.js +1 -14
- package/dist/esm/hooks/useAccountsBalancesData.js.map +1 -1
- package/dist/esm/hooks/useToAddressAutoPopulate.js.map +1 -1
- package/dist/esm/hooks/useTokenBalances.js.map +1 -1
- package/dist/esm/hooks/useTokenBalancesQueries.js +5 -3
- package/dist/esm/hooks/useTokenBalancesQueries.js.map +1 -1
- package/dist/esm/hooks/useTokens.js.map +1 -1
- package/dist/esm/pages/ActivitiesPage/ActivitiesPage.js.map +1 -1
- package/dist/esm/pages/ActivitiesPage/ActivitiesPageMenuButton.js.map +1 -1
- package/dist/esm/pages/LanguagesPage.js.map +1 -1
- package/dist/esm/pages/MainPage/LimitPageContent.js.map +1 -1
- package/dist/esm/pages/MainPage/MainPage.js.map +1 -1
- package/dist/esm/pages/MainPage/MainPageActions.js.map +1 -1
- package/dist/esm/pages/RoutePriorityPage.js.map +1 -1
- package/dist/esm/pages/RoutesPage/RoutesPage.js.map +1 -1
- package/dist/esm/pages/SelectEnabledToolsPage.js.map +1 -1
- package/dist/esm/pages/SelectTokenPage/SelectTokenPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/BookmarkAddressSheet.js.map +1 -1
- package/dist/esm/pages/SendToWallet/BookmarksPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/ConfirmAddressSheet.js.map +1 -1
- package/dist/esm/pages/SendToWallet/ConnectedWalletsPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/RecentWalletsPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/SendToConfiguredWalletPage.js.map +1 -1
- package/dist/esm/pages/SendToWallet/SendToWalletPage.js.map +1 -1
- package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/GasPriceSettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/LanguageSetting.js.map +1 -1
- package/dist/esm/pages/SettingsPage/ResetSettingsButton.js.map +1 -1
- package/dist/esm/pages/SettingsPage/RoutePrioritySettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SettingsCard/BadgedValue.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SettingsCard/SettingCardExpandable.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippagePage.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SmallBalanceFilterSettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/ThemeSettings.js.map +1 -1
- package/dist/esm/pages/TransactionDetailsPage/ContactSupportButton.js.map +1 -1
- package/dist/esm/pages/TransactionDetailsPage/ReceiptsCard.js.map +1 -1
- package/dist/esm/pages/TransactionDetailsPage/TransactionDetailsPage.js.map +1 -1
- package/dist/esm/pages/TransactionDetailsPage/TransactionDetailsSkeleton.js.map +1 -1
- package/dist/esm/pages/TransactionDetailsPage/TransferIdCard.js.map +1 -1
- package/dist/esm/pages/TransactionPage/ConfirmToAddressSheet.js.map +1 -1
- package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.js.map +1 -1
- package/dist/esm/pages/TransactionPage/ExecutionDoneCard.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TokenValueBottomSheet.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionDoneButtons.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionExecutionContent.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionFailedButtons.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionPage.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionReview.js.map +1 -1
- package/dist/esm/providers/I18nProvider/I18nProvider.js.map +1 -1
- package/dist/esm/providers/I18nProvider/types.d.ts.map +1 -1
- package/dist/esm/providers/WalletProvider/WalletProvider.js.map +1 -1
- package/dist/esm/stores/StoreProvider.js.map +1 -1
- package/dist/esm/stores/form/FormStore.js.map +1 -1
- package/dist/esm/stores/form/FormUpdater.js.map +1 -1
- package/dist/esm/stores/navigationTabs/useNavigationTabsStore.js.map +1 -1
- package/dist/esm/utils/tokenList.js +1 -4
- package/dist/esm/utils/tokenList.js.map +1 -1
- package/package.json +4 -4
- package/src/config/version.ts +1 -1
- package/src/hooks/useAccountsBalancesData.ts +4 -31
- package/src/hooks/useTokenBalancesQueries.ts +12 -4
- package/src/utils/tokenList.ts +1 -9
- package/dist/esm/hooks/useFilteredByTokenBalances.js +0 -74
- package/dist/esm/hooks/useFilteredByTokenBalances.js.map +0 -1
- package/src/hooks/useFilteredByTokenBalances.ts +0 -145
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PinTokenButton.js","names":[],"sources":["../../../../src/components/TokenList/PinTokenButton.tsx"],"sourcesContent":["import PushPinIcon from '@mui/icons-material/PushPin'\nimport PushPinOutlinedIcon from '@mui/icons-material/PushPinOutlined'\nimport { IconButton } from '@mui/material'\nimport type { JSX } from 'react'\nimport { usePinnedTokensStore } from '../../stores/pinnedTokens/PinnedTokensStore.js'\n\ninterface PinTokenButtonProps {\n chainId: number\n tokenAddress: string\n}\n\nexport const PinTokenButton = ({\n chainId,\n tokenAddress,\n}: PinTokenButtonProps): JSX.Element => {\n const [pinnedTokens, pinToken, unpinToken] = usePinnedTokensStore((state) => [\n state.pinnedTokens,\n state.pinToken,\n state.unpinToken,\n ])\n\n const isPinned =\n pinnedTokens[chainId]?.includes(tokenAddress.toLowerCase()) ?? false\n\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation()\n ;(e.currentTarget as HTMLElement).blur()\n if (isPinned) {\n unpinToken(chainId, tokenAddress)\n } else {\n pinToken(chainId, tokenAddress)\n }\n }\n\n const PinIcon = isPinned ? PushPinIcon : PushPinOutlinedIcon\n\n return (\n <IconButton\n sx={{ width: 20, height: 20 }}\n size=\"small\"\n onClick={handleClick}\n >\n <PinIcon\n sx={{\n fontSize: 12,\n color: isPinned ? 'text.primary' : 'text.secondary',\n }}\n />\n </IconButton>\n )\n}\n"],"mappings":";;;;;;AAWA,MAAa,kBAAkB,EAC7B,SACA,mBACsC;CACtC,MAAM,CAAC,cAAc,UAAU,cAAc,sBAAsB,UAAU;EAC3E,MAAM;EACN,MAAM;EACN,MAAM;CACR,CAAC;CAED,MAAM,WACJ,aAAa,QAAQ,EAAE,SAAS,aAAa,YAAY,CAAC,KAAK;CAEjE,MAAM,eAAe,MAAwB;EAC3C,EAAE,gBAAgB;EACjB,EAAG,cAA8B,KAAK;EACvC,IAAI,UACF,WAAW,SAAS,YAAY;OAEhC,SAAS,SAAS,YAAY;CAElC;CAIA,OACE,oBAAC,YAAD;EACE,IAAI;GAAE,OAAO;GAAI,QAAQ;EAAG;EAC5B,MAAK;EACL,SAAS;
|
|
1
|
+
{"version":3,"file":"PinTokenButton.js","names":[],"sources":["../../../../src/components/TokenList/PinTokenButton.tsx"],"sourcesContent":["import PushPinIcon from '@mui/icons-material/PushPin'\nimport PushPinOutlinedIcon from '@mui/icons-material/PushPinOutlined'\nimport { IconButton } from '@mui/material'\nimport type { JSX } from 'react'\nimport { usePinnedTokensStore } from '../../stores/pinnedTokens/PinnedTokensStore.js'\n\ninterface PinTokenButtonProps {\n chainId: number\n tokenAddress: string\n}\n\nexport const PinTokenButton = ({\n chainId,\n tokenAddress,\n}: PinTokenButtonProps): JSX.Element => {\n const [pinnedTokens, pinToken, unpinToken] = usePinnedTokensStore((state) => [\n state.pinnedTokens,\n state.pinToken,\n state.unpinToken,\n ])\n\n const isPinned =\n pinnedTokens[chainId]?.includes(tokenAddress.toLowerCase()) ?? false\n\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation()\n ;(e.currentTarget as HTMLElement).blur()\n if (isPinned) {\n unpinToken(chainId, tokenAddress)\n } else {\n pinToken(chainId, tokenAddress)\n }\n }\n\n const PinIcon = isPinned ? PushPinIcon : PushPinOutlinedIcon\n\n return (\n <IconButton\n sx={{ width: 20, height: 20 }}\n size=\"small\"\n onClick={handleClick}\n >\n <PinIcon\n sx={{\n fontSize: 12,\n color: isPinned ? 'text.primary' : 'text.secondary',\n }}\n />\n </IconButton>\n )\n}\n"],"mappings":";;;;;;AAWA,MAAa,kBAAkB,EAC7B,SACA,mBACsC;CACtC,MAAM,CAAC,cAAc,UAAU,cAAc,sBAAsB,UAAU;EAC3E,MAAM;EACN,MAAM;EACN,MAAM;CACR,CAAC;CAED,MAAM,WACJ,aAAa,QAAQ,EAAE,SAAS,aAAa,YAAY,CAAC,KAAK;CAEjE,MAAM,eAAe,MAAwB;EAC3C,EAAE,gBAAgB;EACjB,EAAG,cAA8B,KAAK;EACvC,IAAI,UACF,WAAW,SAAS,YAAY;OAEhC,SAAS,SAAS,YAAY;CAElC;CAIA,OACE,oBAAC,YAAD;EACE,IAAI;GAAE,OAAO;GAAI,QAAQ;EAAG;EAC5B,MAAK;EACL,SAAS;EAET,UAAA,oBARY,WAAW,cAAc,qBAQrC,EACE,IAAI;GACF,UAAU;GACV,OAAO,WAAW,iBAAiB;EACrC,EACD,CAAA;CACS,CAAA;AAEhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenDetailsSheet.js","names":[],"sources":["../../../../src/components/TokenList/TokenDetailsSheet.tsx"],"sourcesContent":["import type { JSX, Ref } from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { BottomSheet } from '../BottomSheet/BottomSheet.js'\nimport type { BottomSheetBase } from '../BottomSheet/types.js'\nimport { TokenDetailsSheetContent } from './TokenDetailsSheetContent.js'\nimport type { TokenDetailsSheetBase } from './types.js'\n\nexport const TokenDetailsSheet = ({\n ref,\n}: {\n ref?: Ref<TokenDetailsSheetBase>\n}): JSX.Element => {\n const bottomSheetRef = useRef<BottomSheetBase>(null)\n const [tokenAddress, setTokenAddress] = useState<string | undefined>(\n undefined\n )\n const [chainId, setChainId] = useState<number | undefined>(undefined)\n const [withoutContractAddress, setWithoutContractAddress] = useState(false)\n\n useImperativeHandle(\n ref,\n () => ({\n isOpen: () => bottomSheetRef.current?.isOpen(),\n open: (address: string, noContractAddress: boolean, chainId: number) => {\n setTokenAddress(address)\n setWithoutContractAddress(noContractAddress)\n setChainId(chainId)\n bottomSheetRef.current?.open()\n },\n close: () => {\n bottomSheetRef.current?.close()\n },\n }),\n []\n )\n\n return (\n <BottomSheet ref={bottomSheetRef} keepMounted>\n <TokenDetailsSheetContent\n onClose={() => bottomSheetRef.current?.close()}\n tokenAddress={tokenAddress}\n withoutContractAddress={withoutContractAddress}\n chainId={chainId}\n />\n </BottomSheet>\n )\n}\n"],"mappings":";;;;;AAOA,MAAa,qBAAqB,EAChC,UAGiB;CACjB,MAAM,iBAAiB,OAAwB,IAAI;CACnD,MAAM,CAAC,cAAc,mBAAmB,SACtC,KAAA,CACF;CACA,MAAM,CAAC,SAAS,cAAc,SAA6B,KAAA,CAAS;CACpE,MAAM,CAAC,wBAAwB,6BAA6B,SAAS,KAAK;CAE1E,oBACE,YACO;EACL,cAAc,eAAe,SAAS,OAAO;EAC7C,OAAO,SAAiB,mBAA4B,YAAoB;GACtE,gBAAgB,OAAO;GACvB,0BAA0B,iBAAiB;GAC3C,WAAW,OAAO;GAClB,eAAe,SAAS,KAAK;EAC/B;EACA,aAAa;GACX,eAAe,SAAS,MAAM;EAChC;CACF,IACA,CAAC,CACH;CAEA,OACE,oBAAC,aAAD;EAAa,KAAK;EAAgB,aAAA;
|
|
1
|
+
{"version":3,"file":"TokenDetailsSheet.js","names":[],"sources":["../../../../src/components/TokenList/TokenDetailsSheet.tsx"],"sourcesContent":["import type { JSX, Ref } from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { BottomSheet } from '../BottomSheet/BottomSheet.js'\nimport type { BottomSheetBase } from '../BottomSheet/types.js'\nimport { TokenDetailsSheetContent } from './TokenDetailsSheetContent.js'\nimport type { TokenDetailsSheetBase } from './types.js'\n\nexport const TokenDetailsSheet = ({\n ref,\n}: {\n ref?: Ref<TokenDetailsSheetBase>\n}): JSX.Element => {\n const bottomSheetRef = useRef<BottomSheetBase>(null)\n const [tokenAddress, setTokenAddress] = useState<string | undefined>(\n undefined\n )\n const [chainId, setChainId] = useState<number | undefined>(undefined)\n const [withoutContractAddress, setWithoutContractAddress] = useState(false)\n\n useImperativeHandle(\n ref,\n () => ({\n isOpen: () => bottomSheetRef.current?.isOpen(),\n open: (address: string, noContractAddress: boolean, chainId: number) => {\n setTokenAddress(address)\n setWithoutContractAddress(noContractAddress)\n setChainId(chainId)\n bottomSheetRef.current?.open()\n },\n close: () => {\n bottomSheetRef.current?.close()\n },\n }),\n []\n )\n\n return (\n <BottomSheet ref={bottomSheetRef} keepMounted>\n <TokenDetailsSheetContent\n onClose={() => bottomSheetRef.current?.close()}\n tokenAddress={tokenAddress}\n withoutContractAddress={withoutContractAddress}\n chainId={chainId}\n />\n </BottomSheet>\n )\n}\n"],"mappings":";;;;;AAOA,MAAa,qBAAqB,EAChC,UAGiB;CACjB,MAAM,iBAAiB,OAAwB,IAAI;CACnD,MAAM,CAAC,cAAc,mBAAmB,SACtC,KAAA,CACF;CACA,MAAM,CAAC,SAAS,cAAc,SAA6B,KAAA,CAAS;CACpE,MAAM,CAAC,wBAAwB,6BAA6B,SAAS,KAAK;CAE1E,oBACE,YACO;EACL,cAAc,eAAe,SAAS,OAAO;EAC7C,OAAO,SAAiB,mBAA4B,YAAoB;GACtE,gBAAgB,OAAO;GACvB,0BAA0B,iBAAiB;GAC3C,WAAW,OAAO;GAClB,eAAe,SAAS,KAAK;EAC/B;EACA,aAAa;GACX,eAAe,SAAS,MAAM;EAChC;CACF,IACA,CAAC,CACH;CAEA,OACE,oBAAC,aAAD;EAAa,KAAK;EAAgB,aAAA;EAChC,UAAA,oBAAC,0BAAD;GACE,eAAe,eAAe,SAAS,MAAM;GAC/B;GACU;GACf;EACV,CAAA;CACU,CAAA;AAEjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenDetailsSheetContent.js","names":[],"sources":["../../../../src/components/TokenList/TokenDetailsSheetContent.tsx"],"sourcesContent":["import Close from '@mui/icons-material/Close'\nimport ContentCopyRounded from '@mui/icons-material/ContentCopyRounded'\nimport OpenInNewRounded from '@mui/icons-material/OpenInNewRounded'\nimport { Box, IconButton, Link, Skeleton, Typography } from '@mui/material'\nimport type React from 'react'\nimport { type JSX, type PropsWithChildren, useMemo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport { useExplorer } from '../../hooks/useExplorer.js'\nimport { useToken } from '../../hooks/useToken.js'\nimport { shortenAddress } from '../../utils/wallet.js'\nimport { TokenAvatar } from '../Avatar/TokenAvatar.js'\nimport { CardIconButton } from '../Card/CardIconButton.js'\nimport {\n Label,\n MetricContainer,\n TokenDetailsSheetContainer,\n TokenDetailsSheetHeader,\n} from './TokenDetailsSheetContent.style.js'\n\ninterface TokenDetailsSheetContentProps {\n tokenAddress: string | undefined\n chainId: number | undefined\n withoutContractAddress: boolean\n onClose: () => void\n}\n\nconst noDataLabel = '-'\n\nexport const TokenDetailsSheetContent = ({\n tokenAddress,\n chainId,\n withoutContractAddress,\n onClose,\n}: TokenDetailsSheetContentProps): JSX.Element => {\n const { t } = useTranslation()\n const { getAddressLink } = useExplorer()\n const { getChainById } = useAvailableChains()\n\n const { token, isLoading } = useToken(chainId, tokenAddress, true)\n const chain = useMemo(() => getChainById(chainId), [chainId, getChainById])\n\n const copyContractAddress = async (e: React.MouseEvent) => {\n e.stopPropagation()\n try {\n // Clipboard API may throw if access is denied (e.g., in insecure contexts or older browsers)\n await navigator.clipboard.writeText(tokenAddress || '')\n } catch {\n // Silently fail to avoid crashing the UI if clipboard write fails\n }\n }\n\n return (\n <TokenDetailsSheetContainer>\n <TokenDetailsSheetHeader>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 3,\n }}\n >\n <TokenAvatar\n token={token}\n chain={chain}\n tokenAvatarSize={72}\n chainAvatarSize={28}\n isLoading={isLoading}\n />\n <MetricContainer>\n {isLoading ? (\n <>\n <Skeleton variant=\"rounded\" width={80} height={24} />\n <Skeleton variant=\"rounded\" width={80} height={16} />\n </>\n ) : (\n <>\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '24px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {token?.symbol || noDataLabel}\n </Typography>\n <Label>{token?.name || noDataLabel}</Label>\n </>\n )}\n </MetricContainer>\n </Box>\n <IconButton\n onClick={(e) => {\n e.stopPropagation()\n onClose()\n }}\n sx={{ mt: '-8px', mr: '-8px' }}\n >\n <Close />\n </IconButton>\n </TokenDetailsSheetHeader>\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.currentPrice')}\n width={200}\n height={40}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '32px',\n lineHeight: '40px',\n color: 'text.primary',\n }}\n >\n {token?.priceUSD\n ? t('format.currency', {\n value: token.priceUSD,\n })\n : noDataLabel}\n </Typography>\n </MetricWithSkeleton>\n {!withoutContractAddress && (\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.contractAddress')}\n width={200}\n height={24}\n >\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 1,\n }}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '18px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {shortenAddress(tokenAddress)}\n </Typography>\n {tokenAddress && (\n <CardIconButton size=\"small\" onClick={copyContractAddress}>\n <ContentCopyRounded fontSize=\"inherit\" />\n </CardIconButton>\n )}\n {tokenAddress && (\n <CardIconButton\n size=\"small\"\n LinkComponent={Link}\n href={getAddressLink(tokenAddress, chainId)}\n target=\"_blank\"\n rel=\"nofollow noreferrer\"\n onClick={(e) => e.stopPropagation()}\n >\n <OpenInNewRounded fontSize=\"inherit\" />\n </CardIconButton>\n )}\n </Box>\n </MetricWithSkeleton>\n )}\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.marketCap')}\n width={200}\n height={24}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '18px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {token?.marketCapUSD\n ? t('format.currency', {\n value: token.marketCapUSD,\n notation: 'compact',\n compactDisplay: 'short',\n maximumFractionDigits: 2,\n })\n : noDataLabel}\n </Typography>\n </MetricWithSkeleton>\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.volume24h')}\n width={200}\n height={24}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '18px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {token?.volumeUSD24H\n ? t('format.currency', {\n value: token.volumeUSD24H,\n notation: 'compact',\n compactDisplay: 'short',\n maximumFractionDigits: 2,\n })\n : noDataLabel}\n </Typography>\n </MetricWithSkeleton>\n </TokenDetailsSheetContainer>\n )\n}\n\ninterface MetricWithSkeletonProps {\n label: string\n isLoading: boolean\n width: number\n height: number\n}\n\nconst MetricWithSkeleton = ({\n label,\n width,\n height,\n isLoading,\n children,\n}: PropsWithChildren<MetricWithSkeletonProps>) => {\n return (\n <MetricContainer>\n <Label>{label}</Label>\n {isLoading ? (\n <Skeleton variant=\"rounded\" width={width} height={height} />\n ) : (\n children\n )}\n </MetricContainer>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TokenDetailsSheetContent.js","names":[],"sources":["../../../../src/components/TokenList/TokenDetailsSheetContent.tsx"],"sourcesContent":["import Close from '@mui/icons-material/Close'\nimport ContentCopyRounded from '@mui/icons-material/ContentCopyRounded'\nimport OpenInNewRounded from '@mui/icons-material/OpenInNewRounded'\nimport { Box, IconButton, Link, Skeleton, Typography } from '@mui/material'\nimport type React from 'react'\nimport { type JSX, type PropsWithChildren, useMemo } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport { useExplorer } from '../../hooks/useExplorer.js'\nimport { useToken } from '../../hooks/useToken.js'\nimport { shortenAddress } from '../../utils/wallet.js'\nimport { TokenAvatar } from '../Avatar/TokenAvatar.js'\nimport { CardIconButton } from '../Card/CardIconButton.js'\nimport {\n Label,\n MetricContainer,\n TokenDetailsSheetContainer,\n TokenDetailsSheetHeader,\n} from './TokenDetailsSheetContent.style.js'\n\ninterface TokenDetailsSheetContentProps {\n tokenAddress: string | undefined\n chainId: number | undefined\n withoutContractAddress: boolean\n onClose: () => void\n}\n\nconst noDataLabel = '-'\n\nexport const TokenDetailsSheetContent = ({\n tokenAddress,\n chainId,\n withoutContractAddress,\n onClose,\n}: TokenDetailsSheetContentProps): JSX.Element => {\n const { t } = useTranslation()\n const { getAddressLink } = useExplorer()\n const { getChainById } = useAvailableChains()\n\n const { token, isLoading } = useToken(chainId, tokenAddress, true)\n const chain = useMemo(() => getChainById(chainId), [chainId, getChainById])\n\n const copyContractAddress = async (e: React.MouseEvent) => {\n e.stopPropagation()\n try {\n // Clipboard API may throw if access is denied (e.g., in insecure contexts or older browsers)\n await navigator.clipboard.writeText(tokenAddress || '')\n } catch {\n // Silently fail to avoid crashing the UI if clipboard write fails\n }\n }\n\n return (\n <TokenDetailsSheetContainer>\n <TokenDetailsSheetHeader>\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 3,\n }}\n >\n <TokenAvatar\n token={token}\n chain={chain}\n tokenAvatarSize={72}\n chainAvatarSize={28}\n isLoading={isLoading}\n />\n <MetricContainer>\n {isLoading ? (\n <>\n <Skeleton variant=\"rounded\" width={80} height={24} />\n <Skeleton variant=\"rounded\" width={80} height={16} />\n </>\n ) : (\n <>\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '24px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {token?.symbol || noDataLabel}\n </Typography>\n <Label>{token?.name || noDataLabel}</Label>\n </>\n )}\n </MetricContainer>\n </Box>\n <IconButton\n onClick={(e) => {\n e.stopPropagation()\n onClose()\n }}\n sx={{ mt: '-8px', mr: '-8px' }}\n >\n <Close />\n </IconButton>\n </TokenDetailsSheetHeader>\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.currentPrice')}\n width={200}\n height={40}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '32px',\n lineHeight: '40px',\n color: 'text.primary',\n }}\n >\n {token?.priceUSD\n ? t('format.currency', {\n value: token.priceUSD,\n })\n : noDataLabel}\n </Typography>\n </MetricWithSkeleton>\n {!withoutContractAddress && (\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.contractAddress')}\n width={200}\n height={24}\n >\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 1,\n }}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '18px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {shortenAddress(tokenAddress)}\n </Typography>\n {tokenAddress && (\n <CardIconButton size=\"small\" onClick={copyContractAddress}>\n <ContentCopyRounded fontSize=\"inherit\" />\n </CardIconButton>\n )}\n {tokenAddress && (\n <CardIconButton\n size=\"small\"\n LinkComponent={Link}\n href={getAddressLink(tokenAddress, chainId)}\n target=\"_blank\"\n rel=\"nofollow noreferrer\"\n onClick={(e) => e.stopPropagation()}\n >\n <OpenInNewRounded fontSize=\"inherit\" />\n </CardIconButton>\n )}\n </Box>\n </MetricWithSkeleton>\n )}\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.marketCap')}\n width={200}\n height={24}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '18px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {token?.marketCapUSD\n ? t('format.currency', {\n value: token.marketCapUSD,\n notation: 'compact',\n compactDisplay: 'short',\n maximumFractionDigits: 2,\n })\n : noDataLabel}\n </Typography>\n </MetricWithSkeleton>\n <MetricWithSkeleton\n isLoading={isLoading}\n label={t('tokenMetric.volume24h')}\n width={200}\n height={24}\n >\n <Typography\n sx={{\n fontWeight: 700,\n fontSize: '18px',\n lineHeight: '24px',\n color: 'text.primary',\n }}\n >\n {token?.volumeUSD24H\n ? t('format.currency', {\n value: token.volumeUSD24H,\n notation: 'compact',\n compactDisplay: 'short',\n maximumFractionDigits: 2,\n })\n : noDataLabel}\n </Typography>\n </MetricWithSkeleton>\n </TokenDetailsSheetContainer>\n )\n}\n\ninterface MetricWithSkeletonProps {\n label: string\n isLoading: boolean\n width: number\n height: number\n}\n\nconst MetricWithSkeleton = ({\n label,\n width,\n height,\n isLoading,\n children,\n}: PropsWithChildren<MetricWithSkeletonProps>) => {\n return (\n <MetricContainer>\n <Label>{label}</Label>\n {isLoading ? (\n <Skeleton variant=\"rounded\" width={width} height={height} />\n ) : (\n children\n )}\n </MetricContainer>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenList.js","names":[],"sources":["../../../../src/components/TokenList/TokenList.tsx"],"sourcesContent":["import { Box } from '@mui/material'\nimport { type FC, memo, useEffect, useRef } from 'react'\nimport { useDebouncedWatch } from '../../hooks/useDebouncedWatch.js'\nimport { useListHeight } from '../../hooks/useListHeight.js'\nimport { useNavigateBack } from '../../hooks/useNavigateBack.js'\nimport { useTokenBalances } from '../../hooks/useTokenBalances.js'\nimport { useWidgetEvents } from '../../hooks/useWidgetEvents.js'\nimport { useChainOrderStore } from '../../stores/chains/ChainOrderStore.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { WidgetEvent } from '../../types/events.js'\nimport { TokenNotFound } from './TokenNotFound.js'\nimport type { TokenListProps } from './types.js'\nimport { useTokenSelect } from './useTokenSelect.js'\nimport { VirtualizedTokenList } from './VirtualizedTokenList.js'\n\nexport const TokenList: FC<TokenListProps> = memo(({ formType, headerRef }) => {\n const navigateBack = useNavigateBack()\n const listParentRef = useRef<HTMLUListElement | null>(null)\n const { listHeight } = useListHeight({\n listParentRef,\n headerRef,\n })\n\n const emitter = useWidgetEvents()\n\n const [selectedChainId, selectedTokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const isAllNetworks = useChainOrderStore(\n (state) => state[`${formType}IsAllNetworks`]\n )\n\n const [tokenSearchFilter]: string[] = useDebouncedWatch(\n 320,\n 'tokenSearchFilter'\n )\n\n const {\n tokens,\n withCategories,\n withPinnedTokens,\n isTokensLoading,\n isBalanceLoading,\n isSearchLoading,\n } = useTokenBalances(\n selectedChainId,\n formType,\n isAllNetworks,\n tokenSearchFilter\n )\n\n const handleTokenClick = useTokenSelect(formType, navigateBack)\n\n const showCategories = withCategories && !tokenSearchFilter && !isAllNetworks\n\n useEffect(() => {\n const normalizedSearchFilter = tokenSearchFilter?.replaceAll('$', '')\n if (normalizedSearchFilter) {\n emitter.emit(WidgetEvent.TokenSearch, {\n value: normalizedSearchFilter,\n tokens,\n })\n }\n }, [tokenSearchFilter, tokens, emitter])\n\n return (\n <Box ref={listParentRef} style={{ height: listHeight, overflow: 'auto' }}>\n {!tokens.length && !isTokensLoading && !isSearchLoading ? (\n <TokenNotFound formType={formType} />\n ) : null}\n <VirtualizedTokenList\n tokens={tokens}\n scrollElementRef={listParentRef}\n chainId={selectedChainId}\n isLoading={isTokensLoading || isSearchLoading}\n isBalanceLoading={isBalanceLoading}\n showCategories={showCategories}\n showPinnedTokens={withPinnedTokens}\n onClick={handleTokenClick}\n selectedTokenAddress={selectedTokenAddress}\n isAllNetworks={isAllNetworks}\n />\n </Box>\n )\n})\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAa,YAAgC,MAAM,EAAE,UAAU,gBAAgB;CAC7E,MAAM,eAAe,gBAAgB;CACrC,MAAM,gBAAgB,OAAgC,IAAI;CAC1D,MAAM,EAAE,eAAe,cAAc;EACnC;EACA;CACF,CAAC;CAED,MAAM,UAAU,gBAAgB;CAEhC,MAAM,CAAC,iBAAiB,wBAAwB,eAC9C,cAAc,YAAY,QAAQ,GAClC,cAAc,YAAY,QAAQ,CACpC;CAEA,MAAM,gBAAgB,oBACnB,UAAU,MAAM,GAAG,SAAS,eAC/B;CAEA,MAAM,CAAC,qBAA+B,kBACpC,KACA,mBACF;CAEA,MAAM,EACJ,QACA,gBACA,kBACA,iBACA,kBACA,oBACE,iBACF,iBACA,UACA,eACA,iBACF;CAEA,MAAM,mBAAmB,eAAe,UAAU,YAAY;CAE9D,MAAM,iBAAiB,kBAAkB,CAAC,qBAAqB,CAAC;CAEhE,gBAAgB;EACd,MAAM,yBAAyB,mBAAmB,WAAW,KAAK,EAAE;EACpE,IAAI,wBACF,QAAQ,KAAA,eAA8B;GACpC,OAAO;GACP;EACF,CAAC;CAEL,GAAG;EAAC;EAAmB;EAAQ;CAAO,CAAC;CAEvC,OACE,qBAAC,KAAD;EAAK,KAAK;EAAe,OAAO;GAAE,QAAQ;GAAY,UAAU;EAAO;
|
|
1
|
+
{"version":3,"file":"TokenList.js","names":[],"sources":["../../../../src/components/TokenList/TokenList.tsx"],"sourcesContent":["import { Box } from '@mui/material'\nimport { type FC, memo, useEffect, useRef } from 'react'\nimport { useDebouncedWatch } from '../../hooks/useDebouncedWatch.js'\nimport { useListHeight } from '../../hooks/useListHeight.js'\nimport { useNavigateBack } from '../../hooks/useNavigateBack.js'\nimport { useTokenBalances } from '../../hooks/useTokenBalances.js'\nimport { useWidgetEvents } from '../../hooks/useWidgetEvents.js'\nimport { useChainOrderStore } from '../../stores/chains/ChainOrderStore.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport { WidgetEvent } from '../../types/events.js'\nimport { TokenNotFound } from './TokenNotFound.js'\nimport type { TokenListProps } from './types.js'\nimport { useTokenSelect } from './useTokenSelect.js'\nimport { VirtualizedTokenList } from './VirtualizedTokenList.js'\n\nexport const TokenList: FC<TokenListProps> = memo(({ formType, headerRef }) => {\n const navigateBack = useNavigateBack()\n const listParentRef = useRef<HTMLUListElement | null>(null)\n const { listHeight } = useListHeight({\n listParentRef,\n headerRef,\n })\n\n const emitter = useWidgetEvents()\n\n const [selectedChainId, selectedTokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n FormKeyHelper.getTokenKey(formType)\n )\n\n const isAllNetworks = useChainOrderStore(\n (state) => state[`${formType}IsAllNetworks`]\n )\n\n const [tokenSearchFilter]: string[] = useDebouncedWatch(\n 320,\n 'tokenSearchFilter'\n )\n\n const {\n tokens,\n withCategories,\n withPinnedTokens,\n isTokensLoading,\n isBalanceLoading,\n isSearchLoading,\n } = useTokenBalances(\n selectedChainId,\n formType,\n isAllNetworks,\n tokenSearchFilter\n )\n\n const handleTokenClick = useTokenSelect(formType, navigateBack)\n\n const showCategories = withCategories && !tokenSearchFilter && !isAllNetworks\n\n useEffect(() => {\n const normalizedSearchFilter = tokenSearchFilter?.replaceAll('$', '')\n if (normalizedSearchFilter) {\n emitter.emit(WidgetEvent.TokenSearch, {\n value: normalizedSearchFilter,\n tokens,\n })\n }\n }, [tokenSearchFilter, tokens, emitter])\n\n return (\n <Box ref={listParentRef} style={{ height: listHeight, overflow: 'auto' }}>\n {!tokens.length && !isTokensLoading && !isSearchLoading ? (\n <TokenNotFound formType={formType} />\n ) : null}\n <VirtualizedTokenList\n tokens={tokens}\n scrollElementRef={listParentRef}\n chainId={selectedChainId}\n isLoading={isTokensLoading || isSearchLoading}\n isBalanceLoading={isBalanceLoading}\n showCategories={showCategories}\n showPinnedTokens={withPinnedTokens}\n onClick={handleTokenClick}\n selectedTokenAddress={selectedTokenAddress}\n isAllNetworks={isAllNetworks}\n />\n </Box>\n )\n})\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAa,YAAgC,MAAM,EAAE,UAAU,gBAAgB;CAC7E,MAAM,eAAe,gBAAgB;CACrC,MAAM,gBAAgB,OAAgC,IAAI;CAC1D,MAAM,EAAE,eAAe,cAAc;EACnC;EACA;CACF,CAAC;CAED,MAAM,UAAU,gBAAgB;CAEhC,MAAM,CAAC,iBAAiB,wBAAwB,eAC9C,cAAc,YAAY,QAAQ,GAClC,cAAc,YAAY,QAAQ,CACpC;CAEA,MAAM,gBAAgB,oBACnB,UAAU,MAAM,GAAG,SAAS,eAC/B;CAEA,MAAM,CAAC,qBAA+B,kBACpC,KACA,mBACF;CAEA,MAAM,EACJ,QACA,gBACA,kBACA,iBACA,kBACA,oBACE,iBACF,iBACA,UACA,eACA,iBACF;CAEA,MAAM,mBAAmB,eAAe,UAAU,YAAY;CAE9D,MAAM,iBAAiB,kBAAkB,CAAC,qBAAqB,CAAC;CAEhE,gBAAgB;EACd,MAAM,yBAAyB,mBAAmB,WAAW,KAAK,EAAE;EACpE,IAAI,wBACF,QAAQ,KAAA,eAA8B;GACpC,OAAO;GACP;EACF,CAAC;CAEL,GAAG;EAAC;EAAmB;EAAQ;CAAO,CAAC;CAEvC,OACE,qBAAC,KAAD;EAAK,KAAK;EAAe,OAAO;GAAE,QAAQ;GAAY,UAAU;EAAO;EAAvE,UAAA,CACG,CAAC,OAAO,UAAU,CAAC,mBAAmB,CAAC,kBACtC,oBAAC,eAAD,EAAyB,SAAW,CAAA,IAClC,MACJ,oBAAC,sBAAD;GACU;GACR,kBAAkB;GAClB,SAAS;GACT,WAAW,mBAAmB;GACZ;GACF;GAChB,kBAAkB;GAClB,SAAS;GACa;GACP;EAChB,CAAA,CACE;;AAET,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenListItem.js","names":["ListItem","IconButton","InfoOutlinedIcon","ListItemButton"],"sources":["../../../../src/components/TokenList/TokenListItem.tsx"],"sourcesContent":["import type { StaticToken } from '@lifi/sdk'\nimport { ChainType } from '@lifi/sdk'\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'\nimport WarningRounded from '@mui/icons-material/WarningRounded'\nimport {\n Avatar,\n Box,\n ListItemAvatar,\n ListItemText,\n listItemSecondaryActionClasses,\n Skeleton,\n Slide,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport type { JSX, MouseEventHandler } from 'react'\nimport { memo, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useLongPress } from '../../hooks/useLongPress.js'\nimport { formatTokenAmount, formatTokenPrice } from '../../utils/format.js'\nimport { shortenAddress } from '../../utils/wallet.js'\nimport { TokenAvatar } from '../Avatar/TokenAvatar.js'\nimport { ListItemButton } from '../ListItem/ListItemButton.js'\nimport { PinTokenButton } from './PinTokenButton.js'\nimport { IconButton, ListItem } from './TokenList.style.js'\nimport type {\n TokenListItemAvatarProps,\n TokenListItemButtonProps,\n TokenListItemProps,\n} from './types.js'\n\nexport const TokenListItem: React.FC<TokenListItemProps> = memo(\n ({\n onClick,\n size,\n start,\n token,\n chain,\n isBalanceLoading,\n startAdornment,\n endAdornment,\n selected,\n onShowTokenDetails,\n }) => {\n return (\n <ListItem\n style={{\n height: `${size}px`,\n transform: `translateY(${start}px)`,\n padding: 0,\n }}\n >\n {startAdornment}\n <TokenListItemButton\n token={token}\n isBalanceLoading={isBalanceLoading}\n onClick={onClick}\n chain={chain}\n selected={selected}\n onShowTokenDetails={onShowTokenDetails}\n />\n {endAdornment}\n </ListItem>\n )\n }\n)\n\nconst TokenListItemAvatar = memo(({ token }: TokenListItemAvatarProps) => {\n const [isImageLoading, setIsImageLoading] = useState(true)\n\n return (\n <Avatar\n src={token.logoURI}\n alt={token.symbol}\n sx={(theme) =>\n isImageLoading ? { bgcolor: theme.vars.palette.grey[300] } : null\n }\n onLoad={() => setIsImageLoading(false)}\n >\n {token.symbol?.[0]}\n </Avatar>\n )\n})\n\ninterface OpenTokenDetailsButtonProps {\n tokenAddress: string | undefined\n withoutContractAddress: boolean\n chainId: number\n onClick: (\n tokenAddress: string,\n withoutContractAddress: boolean,\n chainId: number\n ) => void\n}\n\nconst OpenTokenDetailsButton = ({\n tokenAddress,\n withoutContractAddress,\n chainId,\n onClick,\n}: OpenTokenDetailsButtonProps) => {\n if (!tokenAddress) {\n return null\n }\n return (\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation()\n e.currentTarget.blur() // Remove focus to prevent accessibility issues when opening drawer\n onClick(tokenAddress, withoutContractAddress, chainId)\n }}\n >\n <InfoOutlinedIcon />\n </IconButton>\n )\n}\n\nconst TokenListItemButton: React.FC<TokenListItemButtonProps> = memo(\n ({\n onClick,\n token,\n chain,\n isBalanceLoading,\n selected,\n onShowTokenDetails,\n }) => {\n const { t } = useTranslation()\n const container = useRef(null)\n const timeoutId = useRef<ReturnType<typeof setTimeout>>(undefined)\n const [showAddress, setShowAddress] = useState(false)\n\n const withoutContractAddress = chain?.chainType === ChainType.UTXO\n\n const onMouseEnter = () => {\n timeoutId.current = setTimeout(() => {\n if (token.address) {\n setShowAddress(true)\n }\n }, 350)\n }\n\n const onMouseLeave = () => {\n clearTimeout(timeoutId.current)\n if (showAddress) {\n setShowAddress(false)\n }\n }\n\n const handleClick: MouseEventHandler<HTMLDivElement> = (e) => {\n e.stopPropagation()\n onClick?.(token.address, token.chainId)\n }\n\n const tokenAmount = useMemo(\n () => formatTokenAmount(token.amount, token.decimals),\n [token.amount, token.decimals]\n )\n\n const tokenPrice = useMemo(\n () => formatTokenPrice(token.amount, token.priceUSD, token.decimals),\n [token.amount, token.priceUSD, token.decimals]\n )\n\n const longPressEvents = useLongPress(() =>\n onShowTokenDetails(token.address, withoutContractAddress, token.chainId)\n )\n\n return (\n <ListItemButton\n onClick={handleClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n {...longPressEvents}\n dense\n selected={selected}\n sx={{\n height: 60,\n marginBottom: '4px',\n }}\n >\n <ListItemAvatar>\n {chain ? (\n <TokenAvatar\n token={token as StaticToken}\n chain={chain}\n tokenAvatarSize={40}\n chainAvatarSize={16}\n />\n ) : (\n <TokenListItemAvatar token={token} />\n )}\n </ListItemAvatar>\n <ListItemText\n primary={\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n {token.symbol}\n {!token.verified && (\n <Tooltip\n title={t('warning.message.unverifiedToken')}\n placement=\"top\"\n arrow\n >\n <WarningRounded\n sx={{\n display: 'flex',\n fontSize: 16,\n color: 'warning.main',\n cursor: 'help',\n }}\n />\n </Tooltip>\n )}\n </Box>\n }\n slotProps={{\n secondary: {\n component: 'div',\n },\n }}\n secondary={\n withoutContractAddress ? (\n <Box\n ref={container}\n sx={{\n height: 20,\n display: 'flex',\n }}\n >\n <Box\n sx={{\n pt: 0.25,\n }}\n >\n {token.name}\n </Box>\n <Box\n sx={{\n position: 'relative',\n }}\n >\n <Slide\n direction=\"up\"\n in={showAddress}\n container={container.current}\n style={{\n position: 'absolute',\n }}\n appear={false}\n mountOnEnter\n >\n <Box>\n <OpenTokenDetailsButton\n tokenAddress={token.address}\n withoutContractAddress={withoutContractAddress}\n chainId={token.chainId}\n onClick={onShowTokenDetails}\n />\n <PinTokenButton\n chainId={token.chainId}\n tokenAddress={token.address}\n />\n </Box>\n </Slide>\n </Box>\n </Box>\n ) : (\n <Box\n ref={container}\n sx={{\n position: 'relative',\n height: 20,\n }}\n >\n <Slide\n direction=\"down\"\n in={!showAddress}\n container={container.current}\n style={{\n position: 'absolute',\n }}\n appear={false}\n >\n <Box\n sx={{\n pt: 0.25,\n }}\n >\n {token.name}\n </Box>\n </Slide>\n <Slide\n direction=\"up\"\n in={showAddress}\n container={container.current}\n style={{\n position: 'absolute',\n }}\n appear={false}\n mountOnEnter\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 0.5,\n }}\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n pt: 0.125,\n }}\n >\n {shortenAddress(token.address)}\n </Box>\n <Box>\n <OpenTokenDetailsButton\n tokenAddress={token.address}\n withoutContractAddress={withoutContractAddress}\n chainId={token.chainId}\n onClick={onShowTokenDetails}\n />\n <PinTokenButton\n chainId={token.chainId}\n tokenAddress={token.address}\n />\n </Box>\n </Box>\n </Slide>\n </Box>\n )\n }\n />\n {isBalanceLoading ? (\n <TokenAmountSkeleton />\n ) : (\n <Box sx={{ textAlign: 'right' }}>\n {token.amount ? (\n <Typography\n noWrap\n sx={{\n fontWeight: 600,\n }}\n title={tokenAmount}\n >\n {t('format.tokenAmount', {\n value: tokenAmount,\n })}\n </Typography>\n ) : null}\n {token.amount && token.priceUSD ? (\n <Typography\n data-price={token.priceUSD}\n sx={{\n fontWeight: 500,\n fontSize: 12,\n color: 'text.secondary',\n }}\n >\n {t('format.currency', {\n value: tokenPrice,\n })}\n </Typography>\n ) : null}\n </Box>\n )}\n </ListItemButton>\n )\n }\n)\n\nexport const TokenListItemSkeleton = (): JSX.Element => {\n return (\n <ListItem\n secondaryAction={<TokenAmountSkeleton />}\n disablePadding\n sx={(theme) => ({\n position: 'relative',\n flexDirection: 'row',\n alignItems: 'center',\n padding: 0,\n [`& .${listItemSecondaryActionClasses.root}`]: {\n right: theme.spacing(1.5),\n },\n })}\n >\n <ListItemAvatar>\n <Skeleton\n variant=\"circular\"\n width={40}\n height={40}\n sx={{ marginLeft: 1.5, marginRight: 2 }}\n />\n </ListItemAvatar>\n <ListItemText\n primary={<Skeleton variant=\"text\" width={56} height={24} />}\n secondary={<Skeleton variant=\"text\" width={96} height={16} />}\n />\n </ListItem>\n )\n}\n\nconst TokenAmountSkeleton: React.FC = () => {\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-end',\n }}\n >\n <Skeleton variant=\"text\" width={56} height={24} />\n <Skeleton variant=\"text\" width={48} height={16} />\n </Box>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AA+BA,MAAa,gBAA8C,MACxD,EACC,SACA,MACA,OACA,OACA,OACA,kBACA,gBACA,cACA,UACA,yBACI;CACJ,OACE,qBAACA,YAAD;EACE,OAAO;GACL,QAAQ,GAAG,KAAK;GAChB,WAAW,cAAc,MAAM;GAC/B,SAAS;EACX;YALF;GAOG;GACD,oBAAC,qBAAD;IACS;IACW;IACT;IACF;IACG;IACU;GACrB,CAAA;GACA;EACO;;AAEd,CACF;AAEA,MAAM,sBAAsB,MAAM,EAAE,YAAsC;CACxE,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,IAAI;CAEzD,OACE,oBAAC,QAAD;EACE,KAAK,MAAM;EACX,KAAK,MAAM;EACX,KAAK,UACH,iBAAiB,EAAE,SAAS,MAAM,KAAK,QAAQ,KAAK,KAAK,IAAI;EAE/D,cAAc,kBAAkB,KAAK;YAEpC,MAAM,SAAS;CACV,CAAA;AAEZ,CAAC;AAaD,MAAM,0BAA0B,EAC9B,cACA,wBACA,SACA,cACiC;CACjC,IAAI,CAAC,cACH,OAAO;CAET,OACE,oBAACC,cAAD;EACE,MAAK;EACL,UAAU,MAAM;GACd,EAAE,gBAAgB;GAClB,EAAE,cAAc,KAAK;GACrB,QAAQ,cAAc,wBAAwB,OAAO;EACvD;YAEA,oBAACC,cAAD,CAAmB,CAAA;CACT,CAAA;AAEhB;AAEA,MAAM,sBAA0D,MAC7D,EACC,SACA,OACA,OACA,kBACA,UACA,yBACI;CACJ,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,YAAY,OAAO,IAAI;CAC7B,MAAM,YAAY,OAAsC,KAAA,CAAS;CACjE,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CAEpD,MAAM,yBAAyB,OAAO,cAAc,UAAU;CAE9D,MAAM,qBAAqB;EACzB,UAAU,UAAU,iBAAiB;GACnC,IAAI,MAAM,SACR,eAAe,IAAI;EAEvB,GAAG,GAAG;CACR;CAEA,MAAM,qBAAqB;EACzB,aAAa,UAAU,OAAO;EAC9B,IAAI,aACF,eAAe,KAAK;CAExB;CAEA,MAAM,eAAkD,MAAM;EAC5D,EAAE,gBAAgB;EAClB,UAAU,MAAM,SAAS,MAAM,OAAO;CACxC;CAEA,MAAM,cAAc,cACZ,kBAAkB,MAAM,QAAQ,MAAM,QAAQ,GACpD,CAAC,MAAM,QAAQ,MAAM,QAAQ,CAC/B;CAEA,MAAM,aAAa,cACX,iBAAiB,MAAM,QAAQ,MAAM,UAAU,MAAM,QAAQ,GACnE;EAAC,MAAM;EAAQ,MAAM;EAAU,MAAM;CAAQ,CAC/C;CAMA,OACE,qBAACC,kBAAD;EACE,SAAS;EACK;EACA;EACd,GAToB,mBACtB,mBAAmB,MAAM,SAAS,wBAAwB,MAAM,OAAO,CAQnD;EAClB,OAAA;EACU;EACV,IAAI;GACF,QAAQ;GACR,cAAc;EAChB;YAVF;GAYE,oBAAC,gBAAD,EAAA,UACG,QACC,oBAAC,aAAD;IACS;IACA;IACP,iBAAiB;IACjB,iBAAiB;GAClB,CAAA,IAED,oBAAC,qBAAD,EAA4B,MAAQ,CAAA,EAExB,CAAA;GAChB,oBAAC,cAAD;IACE,SACE,qBAAC,KAAD;KAAK,IAAI;MAAE,SAAS;MAAQ,YAAY;MAAU,KAAK;KAAI;eAA3D,CACG,MAAM,QACN,CAAC,MAAM,YACN,oBAAC,SAAD;MACE,OAAO,EAAE,iCAAiC;MAC1C,WAAU;MACV,OAAA;gBAEA,oBAAC,gBAAD,EACE,IAAI;OACF,SAAS;OACT,UAAU;OACV,OAAO;OACP,QAAQ;MACV,EACD,CAAA;KACM,CAAA,CAER;;IAEP,WAAW,EACT,WAAW,EACT,WAAW,MACb,EACF;IACA,WACE,yBACE,qBAAC,KAAD;KACE,KAAK;KACL,IAAI;MACF,QAAQ;MACR,SAAS;KACX;eALF,CAOE,oBAAC,KAAD;MACE,IAAI,EACF,IAAI,IACN;gBAEC,MAAM;KACJ,CAAA,GACL,oBAAC,KAAD;MACE,IAAI,EACF,UAAU,WACZ;gBAEA,oBAAC,OAAD;OACE,WAAU;OACV,IAAI;OACJ,WAAW,UAAU;OACrB,OAAO,EACL,UAAU,WACZ;OACA,QAAQ;OACR,cAAA;iBAEA,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,wBAAD;QACE,cAAc,MAAM;QACI;QACxB,SAAS,MAAM;QACf,SAAS;OACV,CAAA,GACD,oBAAC,gBAAD;QACE,SAAS,MAAM;QACf,cAAc,MAAM;OACrB,CAAA,CACE,EAAA,CAAA;MACA,CAAA;KACJ,CAAA,CACF;SAEL,qBAAC,KAAD;KACE,KAAK;KACL,IAAI;MACF,UAAU;MACV,QAAQ;KACV;eALF,CAOE,oBAAC,OAAD;MACE,WAAU;MACV,IAAI,CAAC;MACL,WAAW,UAAU;MACrB,OAAO,EACL,UAAU,WACZ;MACA,QAAQ;gBAER,oBAAC,KAAD;OACE,IAAI,EACF,IAAI,IACN;iBAEC,MAAM;MACJ,CAAA;KACA,CAAA,GACP,oBAAC,OAAD;MACE,WAAU;MACV,IAAI;MACJ,WAAW,UAAU;MACrB,OAAO,EACL,UAAU,WACZ;MACA,QAAQ;MACR,cAAA;gBAEA,qBAAC,KAAD;OACE,IAAI;QACF,SAAS;QACT,YAAY;QACZ,KAAK;OACP;iBALF,CAOE,oBAAC,KAAD;QACE,IAAI;SACF,SAAS;SACT,YAAY;SACZ,IAAI;QACN;kBAEC,eAAe,MAAM,OAAO;OAC1B,CAAA,GACL,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,wBAAD;QACE,cAAc,MAAM;QACI;QACxB,SAAS,MAAM;QACf,SAAS;OACV,CAAA,GACD,oBAAC,gBAAD;QACE,SAAS,MAAM;QACf,cAAc,MAAM;OACrB,CAAA,CACE,EAAA,CAAA,CACF;;KACA,CAAA,CACJ;;GAGV,CAAA;GACA,mBACC,oBAAC,qBAAD,CAAsB,CAAA,IAEtB,qBAAC,KAAD;IAAK,IAAI,EAAE,WAAW,QAAQ;cAA9B,CACG,MAAM,SACL,oBAAC,YAAD;KACE,QAAA;KACA,IAAI,EACF,YAAY,IACd;KACA,OAAO;eAEN,EAAE,sBAAsB,EACvB,OAAO,YACT,CAAC;IACS,CAAA,IACV,MACH,MAAM,UAAU,MAAM,WACrB,oBAAC,YAAD;KACE,cAAY,MAAM;KAClB,IAAI;MACF,YAAY;MACZ,UAAU;MACV,OAAO;KACT;eAEC,EAAE,mBAAmB,EACpB,OAAO,WACT,CAAC;IACS,CAAA,IACV,IACD;;EAEO;;AAEpB,CACF;AAEA,MAAa,8BAA2C;CACtD,OACE,qBAACH,YAAD;EACE,iBAAiB,oBAAC,qBAAD,CAAsB,CAAA;EACvC,gBAAA;EACA,KAAK,WAAW;GACd,UAAU;GACV,eAAe;GACf,YAAY;GACZ,SAAS;IACR,MAAM,+BAA+B,SAAS,EAC7C,OAAO,MAAM,QAAQ,GAAG,EAC1B;EACF;YAXF,CAaE,oBAAC,gBAAD,EAAA,UACE,oBAAC,UAAD;GACE,SAAQ;GACR,OAAO;GACP,QAAQ;GACR,IAAI;IAAE,YAAY;IAAK,aAAa;GAAE;EACvC,CAAA,EACa,CAAA,GAChB,oBAAC,cAAD;GACE,SAAS,oBAAC,UAAD;IAAU,SAAQ;IAAO,OAAO;IAAI,QAAQ;GAAK,CAAA;GAC1D,WAAW,oBAAC,UAAD;IAAU,SAAQ;IAAO,OAAO;IAAI,QAAQ;GAAK,CAAA;EAC7D,CAAA,CACO;;AAEd;AAEA,MAAM,4BAAsC;CAC1C,OACE,qBAAC,KAAD;EACE,IAAI;GACF,SAAS;GACT,eAAe;GACf,YAAY;EACd;YALF,CAOE,oBAAC,UAAD;GAAU,SAAQ;GAAO,OAAO;GAAI,QAAQ;EAAK,CAAA,GACjD,oBAAC,UAAD;GAAU,SAAQ;GAAO,OAAO;GAAI,QAAQ;EAAK,CAAA,CAC9C;;AAET"}
|
|
1
|
+
{"version":3,"file":"TokenListItem.js","names":["ListItem","IconButton","InfoOutlinedIcon","ListItemButton"],"sources":["../../../../src/components/TokenList/TokenListItem.tsx"],"sourcesContent":["import type { StaticToken } from '@lifi/sdk'\nimport { ChainType } from '@lifi/sdk'\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'\nimport WarningRounded from '@mui/icons-material/WarningRounded'\nimport {\n Avatar,\n Box,\n ListItemAvatar,\n ListItemText,\n listItemSecondaryActionClasses,\n Skeleton,\n Slide,\n Tooltip,\n Typography,\n} from '@mui/material'\nimport type { JSX, MouseEventHandler } from 'react'\nimport { memo, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useLongPress } from '../../hooks/useLongPress.js'\nimport { formatTokenAmount, formatTokenPrice } from '../../utils/format.js'\nimport { shortenAddress } from '../../utils/wallet.js'\nimport { TokenAvatar } from '../Avatar/TokenAvatar.js'\nimport { ListItemButton } from '../ListItem/ListItemButton.js'\nimport { PinTokenButton } from './PinTokenButton.js'\nimport { IconButton, ListItem } from './TokenList.style.js'\nimport type {\n TokenListItemAvatarProps,\n TokenListItemButtonProps,\n TokenListItemProps,\n} from './types.js'\n\nexport const TokenListItem: React.FC<TokenListItemProps> = memo(\n ({\n onClick,\n size,\n start,\n token,\n chain,\n isBalanceLoading,\n startAdornment,\n endAdornment,\n selected,\n onShowTokenDetails,\n }) => {\n return (\n <ListItem\n style={{\n height: `${size}px`,\n transform: `translateY(${start}px)`,\n padding: 0,\n }}\n >\n {startAdornment}\n <TokenListItemButton\n token={token}\n isBalanceLoading={isBalanceLoading}\n onClick={onClick}\n chain={chain}\n selected={selected}\n onShowTokenDetails={onShowTokenDetails}\n />\n {endAdornment}\n </ListItem>\n )\n }\n)\n\nconst TokenListItemAvatar = memo(({ token }: TokenListItemAvatarProps) => {\n const [isImageLoading, setIsImageLoading] = useState(true)\n\n return (\n <Avatar\n src={token.logoURI}\n alt={token.symbol}\n sx={(theme) =>\n isImageLoading ? { bgcolor: theme.vars.palette.grey[300] } : null\n }\n onLoad={() => setIsImageLoading(false)}\n >\n {token.symbol?.[0]}\n </Avatar>\n )\n})\n\ninterface OpenTokenDetailsButtonProps {\n tokenAddress: string | undefined\n withoutContractAddress: boolean\n chainId: number\n onClick: (\n tokenAddress: string,\n withoutContractAddress: boolean,\n chainId: number\n ) => void\n}\n\nconst OpenTokenDetailsButton = ({\n tokenAddress,\n withoutContractAddress,\n chainId,\n onClick,\n}: OpenTokenDetailsButtonProps) => {\n if (!tokenAddress) {\n return null\n }\n return (\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation()\n e.currentTarget.blur() // Remove focus to prevent accessibility issues when opening drawer\n onClick(tokenAddress, withoutContractAddress, chainId)\n }}\n >\n <InfoOutlinedIcon />\n </IconButton>\n )\n}\n\nconst TokenListItemButton: React.FC<TokenListItemButtonProps> = memo(\n ({\n onClick,\n token,\n chain,\n isBalanceLoading,\n selected,\n onShowTokenDetails,\n }) => {\n const { t } = useTranslation()\n const container = useRef(null)\n const timeoutId = useRef<ReturnType<typeof setTimeout>>(undefined)\n const [showAddress, setShowAddress] = useState(false)\n\n const withoutContractAddress = chain?.chainType === ChainType.UTXO\n\n const onMouseEnter = () => {\n timeoutId.current = setTimeout(() => {\n if (token.address) {\n setShowAddress(true)\n }\n }, 350)\n }\n\n const onMouseLeave = () => {\n clearTimeout(timeoutId.current)\n if (showAddress) {\n setShowAddress(false)\n }\n }\n\n const handleClick: MouseEventHandler<HTMLDivElement> = (e) => {\n e.stopPropagation()\n onClick?.(token.address, token.chainId)\n }\n\n const tokenAmount = useMemo(\n () => formatTokenAmount(token.amount, token.decimals),\n [token.amount, token.decimals]\n )\n\n const tokenPrice = useMemo(\n () => formatTokenPrice(token.amount, token.priceUSD, token.decimals),\n [token.amount, token.priceUSD, token.decimals]\n )\n\n const longPressEvents = useLongPress(() =>\n onShowTokenDetails(token.address, withoutContractAddress, token.chainId)\n )\n\n return (\n <ListItemButton\n onClick={handleClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n {...longPressEvents}\n dense\n selected={selected}\n sx={{\n height: 60,\n marginBottom: '4px',\n }}\n >\n <ListItemAvatar>\n {chain ? (\n <TokenAvatar\n token={token as StaticToken}\n chain={chain}\n tokenAvatarSize={40}\n chainAvatarSize={16}\n />\n ) : (\n <TokenListItemAvatar token={token} />\n )}\n </ListItemAvatar>\n <ListItemText\n primary={\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n {token.symbol}\n {!token.verified && (\n <Tooltip\n title={t('warning.message.unverifiedToken')}\n placement=\"top\"\n arrow\n >\n <WarningRounded\n sx={{\n display: 'flex',\n fontSize: 16,\n color: 'warning.main',\n cursor: 'help',\n }}\n />\n </Tooltip>\n )}\n </Box>\n }\n slotProps={{\n secondary: {\n component: 'div',\n },\n }}\n secondary={\n withoutContractAddress ? (\n <Box\n ref={container}\n sx={{\n height: 20,\n display: 'flex',\n }}\n >\n <Box\n sx={{\n pt: 0.25,\n }}\n >\n {token.name}\n </Box>\n <Box\n sx={{\n position: 'relative',\n }}\n >\n <Slide\n direction=\"up\"\n in={showAddress}\n container={container.current}\n style={{\n position: 'absolute',\n }}\n appear={false}\n mountOnEnter\n >\n <Box>\n <OpenTokenDetailsButton\n tokenAddress={token.address}\n withoutContractAddress={withoutContractAddress}\n chainId={token.chainId}\n onClick={onShowTokenDetails}\n />\n <PinTokenButton\n chainId={token.chainId}\n tokenAddress={token.address}\n />\n </Box>\n </Slide>\n </Box>\n </Box>\n ) : (\n <Box\n ref={container}\n sx={{\n position: 'relative',\n height: 20,\n }}\n >\n <Slide\n direction=\"down\"\n in={!showAddress}\n container={container.current}\n style={{\n position: 'absolute',\n }}\n appear={false}\n >\n <Box\n sx={{\n pt: 0.25,\n }}\n >\n {token.name}\n </Box>\n </Slide>\n <Slide\n direction=\"up\"\n in={showAddress}\n container={container.current}\n style={{\n position: 'absolute',\n }}\n appear={false}\n mountOnEnter\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 0.5,\n }}\n >\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n pt: 0.125,\n }}\n >\n {shortenAddress(token.address)}\n </Box>\n <Box>\n <OpenTokenDetailsButton\n tokenAddress={token.address}\n withoutContractAddress={withoutContractAddress}\n chainId={token.chainId}\n onClick={onShowTokenDetails}\n />\n <PinTokenButton\n chainId={token.chainId}\n tokenAddress={token.address}\n />\n </Box>\n </Box>\n </Slide>\n </Box>\n )\n }\n />\n {isBalanceLoading ? (\n <TokenAmountSkeleton />\n ) : (\n <Box sx={{ textAlign: 'right' }}>\n {token.amount ? (\n <Typography\n noWrap\n sx={{\n fontWeight: 600,\n }}\n title={tokenAmount}\n >\n {t('format.tokenAmount', {\n value: tokenAmount,\n })}\n </Typography>\n ) : null}\n {token.amount && token.priceUSD ? (\n <Typography\n data-price={token.priceUSD}\n sx={{\n fontWeight: 500,\n fontSize: 12,\n color: 'text.secondary',\n }}\n >\n {t('format.currency', {\n value: tokenPrice,\n })}\n </Typography>\n ) : null}\n </Box>\n )}\n </ListItemButton>\n )\n }\n)\n\nexport const TokenListItemSkeleton = (): JSX.Element => {\n return (\n <ListItem\n secondaryAction={<TokenAmountSkeleton />}\n disablePadding\n sx={(theme) => ({\n position: 'relative',\n flexDirection: 'row',\n alignItems: 'center',\n padding: 0,\n [`& .${listItemSecondaryActionClasses.root}`]: {\n right: theme.spacing(1.5),\n },\n })}\n >\n <ListItemAvatar>\n <Skeleton\n variant=\"circular\"\n width={40}\n height={40}\n sx={{ marginLeft: 1.5, marginRight: 2 }}\n />\n </ListItemAvatar>\n <ListItemText\n primary={<Skeleton variant=\"text\" width={56} height={24} />}\n secondary={<Skeleton variant=\"text\" width={96} height={16} />}\n />\n </ListItem>\n )\n}\n\nconst TokenAmountSkeleton: React.FC = () => {\n return (\n <Box\n sx={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-end',\n }}\n >\n <Skeleton variant=\"text\" width={56} height={24} />\n <Skeleton variant=\"text\" width={48} height={16} />\n </Box>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualizedTokenList.js","names":["List"],"sources":["../../../../src/components/TokenList/VirtualizedTokenList.tsx"],"sourcesContent":["import { Typography } from '@mui/material'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport type { FC } from 'react'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport type { TokenAmount } from '../../types/token.js'\nimport { TokenDetailsSheet } from './TokenDetailsSheet.js'\nimport { List } from './TokenList.style.js'\nimport { TokenListItem, TokenListItemSkeleton } from './TokenListItem.js'\nimport type {\n TokenDetailsSheetBase,\n VirtualizedTokenListProps,\n} from './types.js'\n\nconst tokenItemHeight = 64 // 60 + 4px margin-bottom\n\nexport const VirtualizedTokenList: FC<VirtualizedTokenListProps> = ({\n tokens,\n scrollElementRef,\n chainId,\n selectedTokenAddress,\n isLoading,\n isBalanceLoading,\n showCategories,\n showPinnedTokens,\n onClick,\n isAllNetworks,\n}) => {\n const { t } = useTranslation()\n\n const { chains } = useAvailableChains()\n\n // Create Set for O(1) chain lookup instead of O(n) find\n const chainsSet = useMemo(() => {\n if (!chains) {\n return undefined\n }\n return new Map(chains.map((chain) => [chain.id, chain]))\n }, [chains])\n\n const tokenDetailsSheetRef = useRef<TokenDetailsSheetBase>(null)\n\n const onShowTokenDetails = useCallback(\n (tokenAddress: string, noContractAddress: boolean, chainId: number) => {\n tokenDetailsSheetRef.current?.open(\n tokenAddress,\n noContractAddress,\n chainId\n )\n },\n []\n )\n\n const getItemKey = useCallback(\n (index: number) => {\n const token = tokens[index]\n return `${token.chainId}-${token.address}-${index}`\n },\n [tokens]\n )\n\n const estimateSize = useCallback(\n (index: number) => {\n const currentToken = tokens[index]\n const previousToken = tokens[index - 1]\n let size = tokenItemHeight\n\n // Pinned tokens (always shown, even in all networks mode)\n if (currentToken.pinned && index === 0) {\n size += 24\n }\n if (previousToken?.pinned && !currentToken.pinned) {\n size += 32\n }\n\n if (!showCategories) {\n return size\n }\n\n if (currentToken.featured && !currentToken.pinned && index === 0) {\n size += 24\n }\n\n // Category transition (excluding pinned tokens)\n const isNotPinned = !currentToken.pinned && !previousToken?.pinned\n if (\n isNotPinned &&\n ((previousToken?.amount && !currentToken.amount) ||\n (previousToken?.featured && !currentToken.featured) ||\n (previousToken?.popular && !currentToken.popular))\n ) {\n size += 32\n }\n\n return size\n },\n [tokens, showCategories]\n )\n\n const virtualizerConfig = useMemo(\n () => ({\n count: tokens.length,\n overscan: 5,\n getScrollElement: () => scrollElementRef.current,\n estimateSize,\n getItemKey,\n paddingEnd: 8,\n }),\n [tokens.length, estimateSize, getItemKey, scrollElementRef]\n )\n\n const { getVirtualItems, getTotalSize, scrollToIndex, measure } =\n useVirtualizer(virtualizerConfig)\n\n // Address the issue of disappearing tokens on rerender\n useEffect(() => {\n if (scrollElementRef.current) {\n measure()\n }\n }, [measure, scrollElementRef.current])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: run only when chainId changes\n useEffect(() => {\n // Scroll to the top of the list when switching the chains\n if (getVirtualItems().length) {\n scrollToIndex(0, { align: 'start' })\n }\n // Close the token details sheet when switching the chains\n tokenDetailsSheetRef.current?.close()\n }, [scrollToIndex, isAllNetworks, chainId, getVirtualItems])\n\n return (\n <>\n <List\n className=\"long-list\"\n style={{ height: getTotalSize() }}\n disablePadding\n >\n {getVirtualItems().map((item) => {\n const currentToken = tokens[item.index]\n const previousToken: TokenAmount | undefined = tokens[item.index - 1]\n const chain = chainsSet?.get(currentToken.chainId)\n\n const isNotPinned = !currentToken.pinned\n const isFirstPinnedToken = currentToken.pinned && item.index === 0\n const isTransitionFromPinned = previousToken?.pinned && isNotPinned\n\n // Category transitions (excluding pinned)\n const isTransitionFromFeatured =\n previousToken?.featured && !currentToken.featured && isNotPinned\n const isTransitionFromMyTokens =\n previousToken?.amount && !currentToken.amount && isNotPinned\n const isTransitionFromPopular =\n previousToken?.popular && !currentToken.popular && isNotPinned\n\n // Determine which category label to show\n const startAdornmentLabel = (() => {\n if (showPinnedTokens && isFirstPinnedToken) {\n return t('main.pinnedTokens')\n }\n if (showPinnedTokens && !showCategories && isTransitionFromPinned) {\n return t('main.allTokens')\n }\n if (!showCategories) {\n return null\n }\n\n if (\n (isTransitionFromPinned && currentToken.featured) ||\n (currentToken.featured && isNotPinned && item.index === 0)\n ) {\n return t('main.featuredTokens')\n }\n if (\n (isTransitionFromFeatured || isTransitionFromPinned) &&\n currentToken.amount &&\n isNotPinned\n ) {\n return t('main.myTokens')\n }\n if (\n (isTransitionFromFeatured ||\n isTransitionFromMyTokens ||\n isTransitionFromPinned) &&\n currentToken.popular &&\n isNotPinned\n ) {\n return t('main.popularTokens')\n }\n if (\n isTransitionFromMyTokens ||\n isTransitionFromFeatured ||\n isTransitionFromPinned ||\n isTransitionFromPopular\n ) {\n return t('main.allTokens')\n }\n return null\n })()\n\n const isSelected =\n selectedTokenAddress === currentToken.address &&\n chainId === currentToken.chainId\n\n return (\n <TokenListItem\n key={item.key}\n onClick={onClick}\n size={item.size}\n start={item.start}\n token={currentToken}\n chain={isAllNetworks ? chain : undefined}\n selected={isSelected}\n onShowTokenDetails={onShowTokenDetails}\n isBalanceLoading={isBalanceLoading}\n startAdornment={\n startAdornmentLabel ? (\n <Typography\n sx={{\n fontSize: 14,\n fontWeight: 600,\n lineHeight: '16px',\n px: 1.5,\n pt:\n isFirstPinnedToken ||\n (currentToken.featured &&\n isNotPinned &&\n item.index === 0)\n ? 0\n : 1,\n pb: 1,\n }}\n >\n {startAdornmentLabel}\n </Typography>\n ) : null\n }\n />\n )\n })}\n </List>\n <TokenDetailsSheet ref={tokenDetailsSheetRef} />\n {isLoading && (\n <List disablePadding sx={{ cursor: 'default' }}>\n {Array.from({ length: 3 }).map((_, index) => (\n <TokenListItemSkeleton key={index} />\n ))}\n </List>\n )}\n </>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VirtualizedTokenList.js","names":["List"],"sources":["../../../../src/components/TokenList/VirtualizedTokenList.tsx"],"sourcesContent":["import { Typography } from '@mui/material'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport type { FC } from 'react'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useAvailableChains } from '../../hooks/useAvailableChains.js'\nimport type { TokenAmount } from '../../types/token.js'\nimport { TokenDetailsSheet } from './TokenDetailsSheet.js'\nimport { List } from './TokenList.style.js'\nimport { TokenListItem, TokenListItemSkeleton } from './TokenListItem.js'\nimport type {\n TokenDetailsSheetBase,\n VirtualizedTokenListProps,\n} from './types.js'\n\nconst tokenItemHeight = 64 // 60 + 4px margin-bottom\n\nexport const VirtualizedTokenList: FC<VirtualizedTokenListProps> = ({\n tokens,\n scrollElementRef,\n chainId,\n selectedTokenAddress,\n isLoading,\n isBalanceLoading,\n showCategories,\n showPinnedTokens,\n onClick,\n isAllNetworks,\n}) => {\n const { t } = useTranslation()\n\n const { chains } = useAvailableChains()\n\n // Create Set for O(1) chain lookup instead of O(n) find\n const chainsSet = useMemo(() => {\n if (!chains) {\n return undefined\n }\n return new Map(chains.map((chain) => [chain.id, chain]))\n }, [chains])\n\n const tokenDetailsSheetRef = useRef<TokenDetailsSheetBase>(null)\n\n const onShowTokenDetails = useCallback(\n (tokenAddress: string, noContractAddress: boolean, chainId: number) => {\n tokenDetailsSheetRef.current?.open(\n tokenAddress,\n noContractAddress,\n chainId\n )\n },\n []\n )\n\n const getItemKey = useCallback(\n (index: number) => {\n const token = tokens[index]\n return `${token.chainId}-${token.address}-${index}`\n },\n [tokens]\n )\n\n const estimateSize = useCallback(\n (index: number) => {\n const currentToken = tokens[index]\n const previousToken = tokens[index - 1]\n let size = tokenItemHeight\n\n // Pinned tokens (always shown, even in all networks mode)\n if (currentToken.pinned && index === 0) {\n size += 24\n }\n if (previousToken?.pinned && !currentToken.pinned) {\n size += 32\n }\n\n if (!showCategories) {\n return size\n }\n\n if (currentToken.featured && !currentToken.pinned && index === 0) {\n size += 24\n }\n\n // Category transition (excluding pinned tokens)\n const isNotPinned = !currentToken.pinned && !previousToken?.pinned\n if (\n isNotPinned &&\n ((previousToken?.amount && !currentToken.amount) ||\n (previousToken?.featured && !currentToken.featured) ||\n (previousToken?.popular && !currentToken.popular))\n ) {\n size += 32\n }\n\n return size\n },\n [tokens, showCategories]\n )\n\n const virtualizerConfig = useMemo(\n () => ({\n count: tokens.length,\n overscan: 5,\n getScrollElement: () => scrollElementRef.current,\n estimateSize,\n getItemKey,\n paddingEnd: 8,\n }),\n [tokens.length, estimateSize, getItemKey, scrollElementRef]\n )\n\n const { getVirtualItems, getTotalSize, scrollToIndex, measure } =\n useVirtualizer(virtualizerConfig)\n\n // Address the issue of disappearing tokens on rerender\n useEffect(() => {\n if (scrollElementRef.current) {\n measure()\n }\n }, [measure, scrollElementRef.current])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: run only when chainId changes\n useEffect(() => {\n // Scroll to the top of the list when switching the chains\n if (getVirtualItems().length) {\n scrollToIndex(0, { align: 'start' })\n }\n // Close the token details sheet when switching the chains\n tokenDetailsSheetRef.current?.close()\n }, [scrollToIndex, isAllNetworks, chainId, getVirtualItems])\n\n return (\n <>\n <List\n className=\"long-list\"\n style={{ height: getTotalSize() }}\n disablePadding\n >\n {getVirtualItems().map((item) => {\n const currentToken = tokens[item.index]\n const previousToken: TokenAmount | undefined = tokens[item.index - 1]\n const chain = chainsSet?.get(currentToken.chainId)\n\n const isNotPinned = !currentToken.pinned\n const isFirstPinnedToken = currentToken.pinned && item.index === 0\n const isTransitionFromPinned = previousToken?.pinned && isNotPinned\n\n // Category transitions (excluding pinned)\n const isTransitionFromFeatured =\n previousToken?.featured && !currentToken.featured && isNotPinned\n const isTransitionFromMyTokens =\n previousToken?.amount && !currentToken.amount && isNotPinned\n const isTransitionFromPopular =\n previousToken?.popular && !currentToken.popular && isNotPinned\n\n // Determine which category label to show\n const startAdornmentLabel = (() => {\n if (showPinnedTokens && isFirstPinnedToken) {\n return t('main.pinnedTokens')\n }\n if (showPinnedTokens && !showCategories && isTransitionFromPinned) {\n return t('main.allTokens')\n }\n if (!showCategories) {\n return null\n }\n\n if (\n (isTransitionFromPinned && currentToken.featured) ||\n (currentToken.featured && isNotPinned && item.index === 0)\n ) {\n return t('main.featuredTokens')\n }\n if (\n (isTransitionFromFeatured || isTransitionFromPinned) &&\n currentToken.amount &&\n isNotPinned\n ) {\n return t('main.myTokens')\n }\n if (\n (isTransitionFromFeatured ||\n isTransitionFromMyTokens ||\n isTransitionFromPinned) &&\n currentToken.popular &&\n isNotPinned\n ) {\n return t('main.popularTokens')\n }\n if (\n isTransitionFromMyTokens ||\n isTransitionFromFeatured ||\n isTransitionFromPinned ||\n isTransitionFromPopular\n ) {\n return t('main.allTokens')\n }\n return null\n })()\n\n const isSelected =\n selectedTokenAddress === currentToken.address &&\n chainId === currentToken.chainId\n\n return (\n <TokenListItem\n key={item.key}\n onClick={onClick}\n size={item.size}\n start={item.start}\n token={currentToken}\n chain={isAllNetworks ? chain : undefined}\n selected={isSelected}\n onShowTokenDetails={onShowTokenDetails}\n isBalanceLoading={isBalanceLoading}\n startAdornment={\n startAdornmentLabel ? (\n <Typography\n sx={{\n fontSize: 14,\n fontWeight: 600,\n lineHeight: '16px',\n px: 1.5,\n pt:\n isFirstPinnedToken ||\n (currentToken.featured &&\n isNotPinned &&\n item.index === 0)\n ? 0\n : 1,\n pb: 1,\n }}\n >\n {startAdornmentLabel}\n </Typography>\n ) : null\n }\n />\n )\n })}\n </List>\n <TokenDetailsSheet ref={tokenDetailsSheetRef} />\n {isLoading && (\n <List disablePadding sx={{ cursor: 'default' }}>\n {Array.from({ length: 3 }).map((_, index) => (\n <TokenListItemSkeleton key={index} />\n ))}\n </List>\n )}\n </>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenPillButton.js","names":[],"sources":["../../../../src/components/TokenPillButton/TokenPillButton.tsx"],"sourcesContent":["import { useNavigate } from '@tanstack/react-router'\nimport type { JSX } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useChain } from '../../hooks/useChain.js'\nimport { useToken } from '../../hooks/useToken.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormTypeProps } from '../../stores/form/types.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport type { DisabledUIConfig } from '../../types/widget.js'\nimport { navigationRoutes } from '../../utils/navigationRoutes.js'\nimport { AvatarBadgedDefault } from '../Avatar/Avatar.js'\nimport { TokenAvatar } from '../Avatar/TokenAvatar.js'\nimport {\n TokenPill,\n TokenPillLabel,\n TokenPillSymbol,\n TokenSelectPill,\n} from './TokenPillButton.style.js'\n\nexport const TokenPillButton: React.FC<FormTypeProps> = ({\n formType,\n}): JSX.Element => {\n const { t } = useTranslation()\n const navigate = useNavigate()\n const { disabledUI, mode } = useWidgetConfig()\n\n const tokenKey = FormKeyHelper.getTokenKey(formType)\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n tokenKey\n )\n\n const { chain } = useChain(chainId)\n const { token } = useToken(chainId, tokenAddress)\n\n const isSelected = !!(chain && token)\n\n const handleClick = (): void => {\n navigate({\n to:\n formType === 'from'\n ? navigationRoutes.fromToken\n : mode === 'refuel'\n ? navigationRoutes.toTokenNative\n : navigationRoutes.toToken,\n })\n }\n\n const isDisabled = !!disabledUI?.[tokenKey as keyof DisabledUIConfig]\n\n const testId = `widget-${formType}-token-button`\n\n if (isSelected) {\n return (\n <TokenPill\n onClick={isDisabled ? undefined : handleClick}\n disabled={isDisabled}\n data-testid={testId}\n >\n <TokenAvatar\n token={token}\n chain={chain}\n tokenAvatarSize={24}\n chainAvatarSize={12}\n />\n <TokenPillSymbol>{token.symbol}</TokenPillSymbol>\n </TokenPill>\n )\n }\n\n return (\n <TokenSelectPill\n onClick={isDisabled ? undefined : handleClick}\n data-testid={testId}\n >\n <AvatarBadgedDefault chain={chain} avatarSize={24} badgeSize={12} />\n <TokenPillLabel>{t('main.select')}</TokenPillLabel>\n </TokenSelectPill>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,MAAa,mBAA4C,EACvD,eACiB;CACjB,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,YAAY,SAAS,gBAAgB;CAE7C,MAAM,WAAW,cAAc,YAAY,QAAQ;CACnD,MAAM,CAAC,SAAS,gBAAgB,eAC9B,cAAc,YAAY,QAAQ,GAClC,QACF;CAEA,MAAM,EAAE,UAAU,SAAS,OAAO;CAClC,MAAM,EAAE,UAAU,SAAS,SAAS,YAAY;CAEhD,MAAM,aAAa,CAAC,EAAE,SAAS;CAE/B,MAAM,oBAA0B;EAC9B,SAAS,EACP,IACE,aAAa,SACT,iBAAiB,YACjB,SAAS,WACP,iBAAiB,gBACjB,iBAAiB,QAC3B,CAAC;CACH;CAEA,MAAM,aAAa,CAAC,CAAC,aAAa;CAElC,MAAM,SAAS,UAAU,SAAS;CAElC,IAAI,YACF,OACE,qBAAC,WAAD;EACE,SAAS,aAAa,KAAA,IAAY;EAClC,UAAU;EACV,eAAa;
|
|
1
|
+
{"version":3,"file":"TokenPillButton.js","names":[],"sources":["../../../../src/components/TokenPillButton/TokenPillButton.tsx"],"sourcesContent":["import { useNavigate } from '@tanstack/react-router'\nimport type { JSX } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useChain } from '../../hooks/useChain.js'\nimport { useToken } from '../../hooks/useToken.js'\nimport { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormTypeProps } from '../../stores/form/types.js'\nimport { FormKeyHelper } from '../../stores/form/types.js'\nimport { useFieldValues } from '../../stores/form/useFieldValues.js'\nimport type { DisabledUIConfig } from '../../types/widget.js'\nimport { navigationRoutes } from '../../utils/navigationRoutes.js'\nimport { AvatarBadgedDefault } from '../Avatar/Avatar.js'\nimport { TokenAvatar } from '../Avatar/TokenAvatar.js'\nimport {\n TokenPill,\n TokenPillLabel,\n TokenPillSymbol,\n TokenSelectPill,\n} from './TokenPillButton.style.js'\n\nexport const TokenPillButton: React.FC<FormTypeProps> = ({\n formType,\n}): JSX.Element => {\n const { t } = useTranslation()\n const navigate = useNavigate()\n const { disabledUI, mode } = useWidgetConfig()\n\n const tokenKey = FormKeyHelper.getTokenKey(formType)\n const [chainId, tokenAddress] = useFieldValues(\n FormKeyHelper.getChainKey(formType),\n tokenKey\n )\n\n const { chain } = useChain(chainId)\n const { token } = useToken(chainId, tokenAddress)\n\n const isSelected = !!(chain && token)\n\n const handleClick = (): void => {\n navigate({\n to:\n formType === 'from'\n ? navigationRoutes.fromToken\n : mode === 'refuel'\n ? navigationRoutes.toTokenNative\n : navigationRoutes.toToken,\n })\n }\n\n const isDisabled = !!disabledUI?.[tokenKey as keyof DisabledUIConfig]\n\n const testId = `widget-${formType}-token-button`\n\n if (isSelected) {\n return (\n <TokenPill\n onClick={isDisabled ? undefined : handleClick}\n disabled={isDisabled}\n data-testid={testId}\n >\n <TokenAvatar\n token={token}\n chain={chain}\n tokenAvatarSize={24}\n chainAvatarSize={12}\n />\n <TokenPillSymbol>{token.symbol}</TokenPillSymbol>\n </TokenPill>\n )\n }\n\n return (\n <TokenSelectPill\n onClick={isDisabled ? undefined : handleClick}\n data-testid={testId}\n >\n <AvatarBadgedDefault chain={chain} avatarSize={24} badgeSize={12} />\n <TokenPillLabel>{t('main.select')}</TokenPillLabel>\n </TokenSelectPill>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,MAAa,mBAA4C,EACvD,eACiB;CACjB,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,EAAE,YAAY,SAAS,gBAAgB;CAE7C,MAAM,WAAW,cAAc,YAAY,QAAQ;CACnD,MAAM,CAAC,SAAS,gBAAgB,eAC9B,cAAc,YAAY,QAAQ,GAClC,QACF;CAEA,MAAM,EAAE,UAAU,SAAS,OAAO;CAClC,MAAM,EAAE,UAAU,SAAS,SAAS,YAAY;CAEhD,MAAM,aAAa,CAAC,EAAE,SAAS;CAE/B,MAAM,oBAA0B;EAC9B,SAAS,EACP,IACE,aAAa,SACT,iBAAiB,YACjB,SAAS,WACP,iBAAiB,gBACjB,iBAAiB,QAC3B,CAAC;CACH;CAEA,MAAM,aAAa,CAAC,CAAC,aAAa;CAElC,MAAM,SAAS,UAAU,SAAS;CAElC,IAAI,YACF,OACE,qBAAC,WAAD;EACE,SAAS,aAAa,KAAA,IAAY;EAClC,UAAU;EACV,eAAa;EAHf,UAAA,CAKE,oBAAC,aAAD;GACS;GACA;GACP,iBAAiB;GACjB,iBAAiB;EAClB,CAAA,GACD,oBAAC,iBAAD,EAAA,UAAkB,MAAM,OAAwB,CAAA,CACvC;;CAIf,OACE,qBAAC,iBAAD;EACE,SAAS,aAAa,KAAA,IAAY;EAClC,eAAa;EAFf,UAAA,CAIE,oBAAC,qBAAD;GAA4B;GAAO,YAAY;GAAI,WAAW;EAAK,CAAA,GACnE,oBAAC,gBAAD,EAAA,UAAiB,EAAE,aAAa,EAAkB,CAAA,CACnC;;AAErB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenRate.js","names":[],"sources":["../../../../src/components/TokenRate/TokenRate.tsx"],"sourcesContent":["import { formatUnits, type RouteExtended } from '@lifi/sdk'\nimport type { TypographyProps } from '@mui/material'\nimport type { MouseEventHandler } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { create } from 'zustand'\nimport { TokenRateTypography } from './TokenRate.style.js'\n\ninterface TokenRateProps extends TypographyProps {\n route: RouteExtended\n}\n\ninterface TokenRateState {\n isForward: boolean\n toggleIsForward(): void\n}\n\nconst useTokenRate = create<TokenRateState>((set) => ({\n isForward: true,\n toggleIsForward: () => set((state) => ({ isForward: !state.isForward })),\n}))\n\nexport const TokenRate: React.FC<TokenRateProps> = ({ route }) => {\n const { t } = useTranslation()\n const { isForward, toggleIsForward } = useTokenRate()\n\n const toggleRate: MouseEventHandler<HTMLSpanElement> = (e) => {\n e.stopPropagation()\n toggleIsForward()\n }\n\n const lastStep = route.steps.at(-1)\n\n const fromToken = {\n ...route.fromToken,\n amount: BigInt(route.fromAmount),\n }\n const toToken = {\n ...(lastStep?.execution?.toToken ??\n lastStep?.action.toToken ??\n route.toToken),\n amount: lastStep?.execution?.toAmount\n ? BigInt(lastStep.execution.toAmount)\n : BigInt(route.toAmount),\n }\n\n const fromToRate =\n Number.parseFloat(formatUnits(toToken.amount!, toToken.decimals)) /\n Number.parseFloat(formatUnits(fromToken.amount!, fromToken.decimals))\n const toFromRate =\n Number.parseFloat(formatUnits(fromToken.amount!, fromToken.decimals)) /\n Number.parseFloat(formatUnits(toToken.amount!, toToken.decimals))\n\n const rateText = isForward\n ? `1 ${fromToken.symbol} ≈ ${t('format.tokenAmount', { value: fromToRate })} ${toToken.symbol}`\n : `1 ${toToken.symbol} ≈ ${t('format.tokenAmount', { value: toFromRate })} ${fromToken.symbol}`\n\n return (\n <TokenRateTypography onClick={toggleRate} role=\"button\">\n {rateText}\n </TokenRateTypography>\n )\n}\n"],"mappings":";;;;;;AAgBA,MAAM,eAAe,QAAwB,SAAS;CACpD,WAAW;CACX,uBAAuB,KAAK,WAAW,EAAE,WAAW,CAAC,MAAM,UAAU,EAAE;AACzE,EAAE;AAEF,MAAa,aAAuC,EAAE,YAAY;CAChE,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,WAAW,oBAAoB,aAAa;CAEpD,MAAM,cAAkD,MAAM;EAC5D,EAAE,gBAAgB;EAClB,gBAAgB;CAClB;CAEA,MAAM,WAAW,MAAM,MAAM,GAAG,EAAE;CAElC,MAAM,YAAY;EAChB,GAAG,MAAM;EACT,QAAQ,OAAO,MAAM,UAAU;CACjC;CACA,MAAM,UAAU;EACd,GAAI,UAAU,WAAW,WACvB,UAAU,OAAO,WACjB,MAAM;EACR,QAAQ,UAAU,WAAW,WACzB,OAAO,SAAS,UAAU,QAAQ,IAClC,OAAO,MAAM,QAAQ;CAC3B;CAEA,MAAM,aACJ,OAAO,WAAW,YAAY,QAAQ,QAAS,QAAQ,QAAQ,CAAC,IAChE,OAAO,WAAW,YAAY,UAAU,QAAS,UAAU,QAAQ,CAAC;CACtE,MAAM,aACJ,OAAO,WAAW,YAAY,UAAU,QAAS,UAAU,QAAQ,CAAC,IACpE,OAAO,WAAW,YAAY,QAAQ,QAAS,QAAQ,QAAQ,CAAC;CAMlE,OACE,oBAAC,qBAAD;EAAqB,SAAS;EAAY,MAAK;
|
|
1
|
+
{"version":3,"file":"TokenRate.js","names":[],"sources":["../../../../src/components/TokenRate/TokenRate.tsx"],"sourcesContent":["import { formatUnits, type RouteExtended } from '@lifi/sdk'\nimport type { TypographyProps } from '@mui/material'\nimport type { MouseEventHandler } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { create } from 'zustand'\nimport { TokenRateTypography } from './TokenRate.style.js'\n\ninterface TokenRateProps extends TypographyProps {\n route: RouteExtended\n}\n\ninterface TokenRateState {\n isForward: boolean\n toggleIsForward(): void\n}\n\nconst useTokenRate = create<TokenRateState>((set) => ({\n isForward: true,\n toggleIsForward: () => set((state) => ({ isForward: !state.isForward })),\n}))\n\nexport const TokenRate: React.FC<TokenRateProps> = ({ route }) => {\n const { t } = useTranslation()\n const { isForward, toggleIsForward } = useTokenRate()\n\n const toggleRate: MouseEventHandler<HTMLSpanElement> = (e) => {\n e.stopPropagation()\n toggleIsForward()\n }\n\n const lastStep = route.steps.at(-1)\n\n const fromToken = {\n ...route.fromToken,\n amount: BigInt(route.fromAmount),\n }\n const toToken = {\n ...(lastStep?.execution?.toToken ??\n lastStep?.action.toToken ??\n route.toToken),\n amount: lastStep?.execution?.toAmount\n ? BigInt(lastStep.execution.toAmount)\n : BigInt(route.toAmount),\n }\n\n const fromToRate =\n Number.parseFloat(formatUnits(toToken.amount!, toToken.decimals)) /\n Number.parseFloat(formatUnits(fromToken.amount!, fromToken.decimals))\n const toFromRate =\n Number.parseFloat(formatUnits(fromToken.amount!, fromToken.decimals)) /\n Number.parseFloat(formatUnits(toToken.amount!, toToken.decimals))\n\n const rateText = isForward\n ? `1 ${fromToken.symbol} ≈ ${t('format.tokenAmount', { value: fromToRate })} ${toToken.symbol}`\n : `1 ${toToken.symbol} ≈ ${t('format.tokenAmount', { value: toFromRate })} ${fromToken.symbol}`\n\n return (\n <TokenRateTypography onClick={toggleRate} role=\"button\">\n {rateText}\n </TokenRateTypography>\n )\n}\n"],"mappings":";;;;;;AAgBA,MAAM,eAAe,QAAwB,SAAS;CACpD,WAAW;CACX,uBAAuB,KAAK,WAAW,EAAE,WAAW,CAAC,MAAM,UAAU,EAAE;AACzE,EAAE;AAEF,MAAa,aAAuC,EAAE,YAAY;CAChE,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,EAAE,WAAW,oBAAoB,aAAa;CAEpD,MAAM,cAAkD,MAAM;EAC5D,EAAE,gBAAgB;EAClB,gBAAgB;CAClB;CAEA,MAAM,WAAW,MAAM,MAAM,GAAG,EAAE;CAElC,MAAM,YAAY;EAChB,GAAG,MAAM;EACT,QAAQ,OAAO,MAAM,UAAU;CACjC;CACA,MAAM,UAAU;EACd,GAAI,UAAU,WAAW,WACvB,UAAU,OAAO,WACjB,MAAM;EACR,QAAQ,UAAU,WAAW,WACzB,OAAO,SAAS,UAAU,QAAQ,IAClC,OAAO,MAAM,QAAQ;CAC3B;CAEA,MAAM,aACJ,OAAO,WAAW,YAAY,QAAQ,QAAS,QAAQ,QAAQ,CAAC,IAChE,OAAO,WAAW,YAAY,UAAU,QAAS,UAAU,QAAQ,CAAC;CACtE,MAAM,aACJ,OAAO,WAAW,YAAY,UAAU,QAAS,UAAU,QAAQ,CAAC,IACpE,OAAO,WAAW,YAAY,QAAQ,QAAS,QAAQ,QAAQ,CAAC;CAMlE,OACE,oBAAC,qBAAD;EAAqB,SAAS;EAAY,MAAK;EALhC,UAAA,YACb,KAAK,UAAU,OAAO,KAAK,EAAE,sBAAsB,EAAE,OAAO,WAAW,CAAC,EAAE,GAAG,QAAQ,WACrF,KAAK,QAAQ,OAAO,KAAK,EAAE,sBAAsB,EAAE,OAAO,WAAW,CAAC,EAAE,GAAG,UAAU;CAKlE,CAAA;AAEzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolItem.js","names":["ListItemText"],"sources":["../../../../src/components/Tools/ToolItem.tsx"],"sourcesContent":["import { Avatar, Checkbox, ListItemAvatar } from '@mui/material'\nimport { memo, type NamedExoticComponent } from 'react'\nimport { ListItemText } from '../ListItemText.js'\nimport { SettingsListItemButton } from '../SettingsListItemButton.js'\n\ninterface ToolItemProps {\n tool: any\n typeKey: string\n isEnabled: boolean\n onToggle: (key: string) => void\n}\n\nexport const ToolItem: NamedExoticComponent<ToolItemProps> =\n memo<ToolItemProps>(({ tool, typeKey, isEnabled, onToggle }) => {\n const handleClick = () => {\n onToggle(tool.key)\n }\n\n const handleCheckboxClick = (e: React.MouseEvent) => {\n e.stopPropagation()\n onToggle(tool.key)\n }\n\n return (\n <SettingsListItemButton onClick={handleClick}>\n <ListItemAvatar>\n <Avatar src={tool.logoURI} alt={tool.name}>\n {tool.name[0]}\n </Avatar>\n </ListItemAvatar>\n <ListItemText primary={tool.name} />\n <Checkbox\n id={`${typeKey}-${tool.key}-checkbox`}\n checked={isEnabled}\n onChange={handleClick}\n onClick={handleCheckboxClick}\n sx={{ mr: -1 }}\n />\n </SettingsListItemButton>\n )\n })\n"],"mappings":";;;;;;AAYA,MAAa,WACX,MAAqB,EAAE,MAAM,SAAS,WAAW,eAAe;CAC9D,MAAM,oBAAoB;EACxB,SAAS,KAAK,GAAG;CACnB;CAEA,MAAM,uBAAuB,MAAwB;EACnD,EAAE,gBAAgB;EAClB,SAAS,KAAK,GAAG;CACnB;CAEA,OACE,qBAAC,wBAAD;EAAwB,SAAS;
|
|
1
|
+
{"version":3,"file":"ToolItem.js","names":["ListItemText"],"sources":["../../../../src/components/Tools/ToolItem.tsx"],"sourcesContent":["import { Avatar, Checkbox, ListItemAvatar } from '@mui/material'\nimport { memo, type NamedExoticComponent } from 'react'\nimport { ListItemText } from '../ListItemText.js'\nimport { SettingsListItemButton } from '../SettingsListItemButton.js'\n\ninterface ToolItemProps {\n tool: any\n typeKey: string\n isEnabled: boolean\n onToggle: (key: string) => void\n}\n\nexport const ToolItem: NamedExoticComponent<ToolItemProps> =\n memo<ToolItemProps>(({ tool, typeKey, isEnabled, onToggle }) => {\n const handleClick = () => {\n onToggle(tool.key)\n }\n\n const handleCheckboxClick = (e: React.MouseEvent) => {\n e.stopPropagation()\n onToggle(tool.key)\n }\n\n return (\n <SettingsListItemButton onClick={handleClick}>\n <ListItemAvatar>\n <Avatar src={tool.logoURI} alt={tool.name}>\n {tool.name[0]}\n </Avatar>\n </ListItemAvatar>\n <ListItemText primary={tool.name} />\n <Checkbox\n id={`${typeKey}-${tool.key}-checkbox`}\n checked={isEnabled}\n onChange={handleClick}\n onClick={handleCheckboxClick}\n sx={{ mr: -1 }}\n />\n </SettingsListItemButton>\n )\n })\n"],"mappings":";;;;;;AAYA,MAAa,WACX,MAAqB,EAAE,MAAM,SAAS,WAAW,eAAe;CAC9D,MAAM,oBAAoB;EACxB,SAAS,KAAK,GAAG;CACnB;CAEA,MAAM,uBAAuB,MAAwB;EACnD,EAAE,gBAAgB;EAClB,SAAS,KAAK,GAAG;CACnB;CAEA,OACE,qBAAC,wBAAD;EAAwB,SAAS;EAAjC,UAAA;GACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,QAAD;IAAQ,KAAK,KAAK;IAAS,KAAK,KAAK;IAClC,UAAA,KAAK,KAAK;GACL,CAAA,EACM,CAAA;GAChB,oBAACA,gBAAD,EAAc,SAAS,KAAK,KAAO,CAAA;GACnC,oBAAC,UAAD;IACE,IAAI,GAAG,QAAQ,GAAG,KAAK,IAAI;IAC3B,SAAS;IACT,UAAU;IACV,SAAS;IACT,IAAI,EAAE,IAAI,GAAG;GACd,CAAA;EACqB;;AAE5B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tools.js","names":[],"sources":["../../../../src/components/Tools/Tools.tsx"],"sourcesContent":["import type { ToolsResponse } from '@lifi/sdk'\nimport { List } from '@mui/material'\nimport { type JSX, useMemo, useRef } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useSettingsStore } from '../../stores/settings/SettingsStore.js'\nimport { useSettingsActions } from '../../stores/settings/useSettingsActions.js'\nimport { SearchNotFound } from '../Search/SearchNotFound.js'\nimport { ToolItem } from './ToolItem.js'\n\nexport type ToolCollectionTypes =\n | ToolsResponse['exchanges']\n | ToolsResponse['bridges']\n\ninterface ToolsProps {\n filteredTools: ToolCollectionTypes\n type: 'Bridges' | 'Exchanges'\n}\n\nexport const Tools = ({ filteredTools, type }: ToolsProps): JSX.Element => {\n const { t } = useTranslation()\n const typeKey = type.toLowerCase() as 'bridges' | 'exchanges'\n const enabledTools = useSettingsStore((state) => state[`_enabled${type}`])\n const { setToolValue } = useSettingsActions()\n\n // Use ref to access current enabledTools without causing re-renders\n const enabledToolsRef = useRef(enabledTools)\n enabledToolsRef.current = enabledTools\n const toggleCallbacks = useMemo(() => {\n const callbacks: Record<string, () => void> = {}\n filteredTools.forEach((tool) => {\n callbacks[tool.key] = () => {\n // Access current state via ref to avoid dependency on enabledTools\n setToolValue(type, tool.key, !enabledToolsRef.current[tool.key])\n }\n })\n return callbacks\n }, [filteredTools, setToolValue, type])\n\n if (!filteredTools.length) {\n return <SearchNotFound message={t(`info.message.empty${type}List`)} />\n }\n\n return (\n <List\n className=\"long-list\"\n disablePadding\n data-testid={`${typeKey}-list`}\n sx={{ px: 1.5, pb: 2 }}\n >\n {filteredTools.map((tool) => (\n <ToolItem\n key={tool.key}\n tool={tool}\n typeKey={typeKey}\n isEnabled={enabledTools[tool.key]}\n onToggle={toggleCallbacks[tool.key]}\n />\n ))}\n </List>\n )\n}\n"],"mappings":";;;;;;;;;AAkBA,MAAa,SAAS,EAAE,eAAe,WAAoC;CACzE,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,UAAU,KAAK,YAAY;CACjC,MAAM,eAAe,kBAAkB,UAAU,MAAM,WAAW,OAAO;CACzE,MAAM,EAAE,iBAAiB,mBAAmB;CAG5C,MAAM,kBAAkB,OAAO,YAAY;CAC3C,gBAAgB,UAAU;CAC1B,MAAM,kBAAkB,cAAc;EACpC,MAAM,YAAwC,CAAC;EAC/C,cAAc,SAAS,SAAS;GAC9B,UAAU,KAAK,aAAa;IAE1B,aAAa,MAAM,KAAK,KAAK,CAAC,gBAAgB,QAAQ,KAAK,IAAI;GACjE;EACF,CAAC;EACD,OAAO;CACT,GAAG;EAAC;EAAe;EAAc;CAAI,CAAC;CAEtC,IAAI,CAAC,cAAc,QACjB,OAAO,oBAAC,gBAAD,EAAgB,SAAS,EAAE,qBAAqB,KAAK,KAAK,EAAI,CAAA;CAGvE,OACE,oBAAC,MAAD;EACE,WAAU;EACV,gBAAA;EACA,eAAa,GAAG,QAAQ;EACxB,IAAI;GAAE,IAAI;GAAK,IAAI;EAAE;
|
|
1
|
+
{"version":3,"file":"Tools.js","names":[],"sources":["../../../../src/components/Tools/Tools.tsx"],"sourcesContent":["import type { ToolsResponse } from '@lifi/sdk'\nimport { List } from '@mui/material'\nimport { type JSX, useMemo, useRef } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useSettingsStore } from '../../stores/settings/SettingsStore.js'\nimport { useSettingsActions } from '../../stores/settings/useSettingsActions.js'\nimport { SearchNotFound } from '../Search/SearchNotFound.js'\nimport { ToolItem } from './ToolItem.js'\n\nexport type ToolCollectionTypes =\n | ToolsResponse['exchanges']\n | ToolsResponse['bridges']\n\ninterface ToolsProps {\n filteredTools: ToolCollectionTypes\n type: 'Bridges' | 'Exchanges'\n}\n\nexport const Tools = ({ filteredTools, type }: ToolsProps): JSX.Element => {\n const { t } = useTranslation()\n const typeKey = type.toLowerCase() as 'bridges' | 'exchanges'\n const enabledTools = useSettingsStore((state) => state[`_enabled${type}`])\n const { setToolValue } = useSettingsActions()\n\n // Use ref to access current enabledTools without causing re-renders\n const enabledToolsRef = useRef(enabledTools)\n enabledToolsRef.current = enabledTools\n const toggleCallbacks = useMemo(() => {\n const callbacks: Record<string, () => void> = {}\n filteredTools.forEach((tool) => {\n callbacks[tool.key] = () => {\n // Access current state via ref to avoid dependency on enabledTools\n setToolValue(type, tool.key, !enabledToolsRef.current[tool.key])\n }\n })\n return callbacks\n }, [filteredTools, setToolValue, type])\n\n if (!filteredTools.length) {\n return <SearchNotFound message={t(`info.message.empty${type}List`)} />\n }\n\n return (\n <List\n className=\"long-list\"\n disablePadding\n data-testid={`${typeKey}-list`}\n sx={{ px: 1.5, pb: 2 }}\n >\n {filteredTools.map((tool) => (\n <ToolItem\n key={tool.key}\n tool={tool}\n typeKey={typeKey}\n isEnabled={enabledTools[tool.key]}\n onToggle={toggleCallbacks[tool.key]}\n />\n ))}\n </List>\n )\n}\n"],"mappings":";;;;;;;;;AAkBA,MAAa,SAAS,EAAE,eAAe,WAAoC;CACzE,MAAM,EAAE,MAAM,eAAe;CAC7B,MAAM,UAAU,KAAK,YAAY;CACjC,MAAM,eAAe,kBAAkB,UAAU,MAAM,WAAW,OAAO;CACzE,MAAM,EAAE,iBAAiB,mBAAmB;CAG5C,MAAM,kBAAkB,OAAO,YAAY;CAC3C,gBAAgB,UAAU;CAC1B,MAAM,kBAAkB,cAAc;EACpC,MAAM,YAAwC,CAAC;EAC/C,cAAc,SAAS,SAAS;GAC9B,UAAU,KAAK,aAAa;IAE1B,aAAa,MAAM,KAAK,KAAK,CAAC,gBAAgB,QAAQ,KAAK,IAAI;GACjE;EACF,CAAC;EACD,OAAO;CACT,GAAG;EAAC;EAAe;EAAc;CAAI,CAAC;CAEtC,IAAI,CAAC,cAAc,QACjB,OAAO,oBAAC,gBAAD,EAAgB,SAAS,EAAE,qBAAqB,KAAK,KAAK,EAAI,CAAA;CAGvE,OACE,oBAAC,MAAD;EACE,WAAU;EACV,gBAAA;EACA,eAAa,GAAG,QAAQ;EACxB,IAAI;GAAE,IAAI;GAAK,IAAI;EAAE;EAEpB,UAAA,cAAc,KAAK,SAClB,oBAAC,UAAD;GAEQ;GACG;GACT,WAAW,aAAa,KAAK;GAC7B,UAAU,gBAAgB,KAAK;EAChC,GALM,KAAK,GAKX,CACF;CACG,CAAA;AAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActiveTransactionCard.js","names":["Card"],"sources":["../../../../src/components/TransactionCard/ActiveTransactionCard.tsx"],"sourcesContent":["import type { RouteExtended } from '@lifi/sdk'\nimport DeleteOutline from '@mui/icons-material/DeleteOutlined'\nimport { Tooltip, Typography } from '@mui/material'\nimport type { JSX, MouseEvent } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useActionMessage } from '../../hooks/useActionMessage.js'\nimport { RouteExecutionStatus } from '../../stores/routes/types.js'\nimport { getExpiryTimestamp } from '../../utils/timer.js'\nimport { ActionRow } from '../ActionRow/ActionRow.js'\nimport { Card } from '../Card/Card.js'\nimport { IconCircle } from '../IconCircle/IconCircle.js'\nimport { RouteTokens } from '../RouteCard/RouteTokens.js'\nimport { ExecutionTimerText } from '../Timer/ExecutionTimerText.js'\nimport { CircularProgressPending } from '../Timer/StepStatusTimer.style.js'\nimport { DeleteButton, PendingCircle } from './ActiveTransactionCard.style.js'\n\ninterface ActiveTransactionCardProps {\n route: RouteExtended\n status?: RouteExecutionStatus\n onClick: () => void\n onDelete: (e: MouseEvent) => void\n}\n\nexport const ActiveTransactionCard = ({\n route,\n status,\n onClick,\n onDelete,\n}: ActiveTransactionCardProps): JSX.Element => {\n const { t } = useTranslation()\n\n const lastActiveStep = route.steps.findLast((step) => step.execution)\n const lastActiveAction = lastActiveStep?.execution?.actions?.at(-1)\n const { title } = useActionMessage(lastActiveStep, lastActiveAction)\n\n const isFailed = status === RouteExecutionStatus.Failed\n\n const statusIcon = (() => {\n if (isFailed) {\n return <IconCircle status=\"error\" size={24} />\n }\n if (\n ['ACTION_REQUIRED', 'MESSAGE_REQUIRED', 'RESET_REQUIRED'].includes(\n lastActiveAction?.status ?? ''\n )\n ) {\n return <IconCircle status=\"info\" size={24} />\n }\n return (\n <PendingCircle>\n <CircularProgressPending size={24} sx={{ top: -2, left: -2 }} />\n </PendingCircle>\n )\n })()\n\n return (\n <Card onClick={onClick} indented>\n <ActionRow\n sx={{ mb: 1.5 }}\n startAdornment={statusIcon}\n message={title ?? ''}\n endAdornment={\n isFailed ? (\n <Tooltip title={t('button.clearTransaction')}>\n <DeleteButton size=\"small\" onClick={onDelete}>\n <DeleteOutline sx={{ fontSize: 16 }} />\n </DeleteButton>\n </Tooltip>\n ) : lastActiveStep?.execution?.signedAt ? (\n <Typography sx={{ fontSize: 12, fontWeight: 600 }}>\n <ExecutionTimerText\n expiryTimestamp={getExpiryTimestamp(lastActiveStep)}\n />\n </Typography>\n ) : undefined\n }\n />\n <RouteTokens route={route} />\n </Card>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAa,yBAAyB,EACpC,OACA,QACA,SACA,eAC6C;CAC7C,MAAM,EAAE,MAAM,eAAe;CAE7B,MAAM,iBAAiB,MAAM,MAAM,UAAU,SAAS,KAAK,SAAS;CACpE,MAAM,mBAAmB,gBAAgB,WAAW,SAAS,GAAG,EAAE;CAClE,MAAM,EAAE,UAAU,iBAAiB,gBAAgB,gBAAgB;CAEnE,MAAM,WAAW,WAAA;CAoBjB,OACE,qBAACA,QAAD;EAAe;EAAS,UAAA;
|
|
1
|
+
{"version":3,"file":"ActiveTransactionCard.js","names":["Card"],"sources":["../../../../src/components/TransactionCard/ActiveTransactionCard.tsx"],"sourcesContent":["import type { RouteExtended } from '@lifi/sdk'\nimport DeleteOutline from '@mui/icons-material/DeleteOutlined'\nimport { Tooltip, Typography } from '@mui/material'\nimport type { JSX, MouseEvent } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { useActionMessage } from '../../hooks/useActionMessage.js'\nimport { RouteExecutionStatus } from '../../stores/routes/types.js'\nimport { getExpiryTimestamp } from '../../utils/timer.js'\nimport { ActionRow } from '../ActionRow/ActionRow.js'\nimport { Card } from '../Card/Card.js'\nimport { IconCircle } from '../IconCircle/IconCircle.js'\nimport { RouteTokens } from '../RouteCard/RouteTokens.js'\nimport { ExecutionTimerText } from '../Timer/ExecutionTimerText.js'\nimport { CircularProgressPending } from '../Timer/StepStatusTimer.style.js'\nimport { DeleteButton, PendingCircle } from './ActiveTransactionCard.style.js'\n\ninterface ActiveTransactionCardProps {\n route: RouteExtended\n status?: RouteExecutionStatus\n onClick: () => void\n onDelete: (e: MouseEvent) => void\n}\n\nexport const ActiveTransactionCard = ({\n route,\n status,\n onClick,\n onDelete,\n}: ActiveTransactionCardProps): JSX.Element => {\n const { t } = useTranslation()\n\n const lastActiveStep = route.steps.findLast((step) => step.execution)\n const lastActiveAction = lastActiveStep?.execution?.actions?.at(-1)\n const { title } = useActionMessage(lastActiveStep, lastActiveAction)\n\n const isFailed = status === RouteExecutionStatus.Failed\n\n const statusIcon = (() => {\n if (isFailed) {\n return <IconCircle status=\"error\" size={24} />\n }\n if (\n ['ACTION_REQUIRED', 'MESSAGE_REQUIRED', 'RESET_REQUIRED'].includes(\n lastActiveAction?.status ?? ''\n )\n ) {\n return <IconCircle status=\"info\" size={24} />\n }\n return (\n <PendingCircle>\n <CircularProgressPending size={24} sx={{ top: -2, left: -2 }} />\n </PendingCircle>\n )\n })()\n\n return (\n <Card onClick={onClick} indented>\n <ActionRow\n sx={{ mb: 1.5 }}\n startAdornment={statusIcon}\n message={title ?? ''}\n endAdornment={\n isFailed ? (\n <Tooltip title={t('button.clearTransaction')}>\n <DeleteButton size=\"small\" onClick={onDelete}>\n <DeleteOutline sx={{ fontSize: 16 }} />\n </DeleteButton>\n </Tooltip>\n ) : lastActiveStep?.execution?.signedAt ? (\n <Typography sx={{ fontSize: 12, fontWeight: 600 }}>\n <ExecutionTimerText\n expiryTimestamp={getExpiryTimestamp(lastActiveStep)}\n />\n </Typography>\n ) : undefined\n }\n />\n <RouteTokens route={route} />\n </Card>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAa,yBAAyB,EACpC,OACA,QACA,SACA,eAC6C;CAC7C,MAAM,EAAE,MAAM,eAAe;CAE7B,MAAM,iBAAiB,MAAM,MAAM,UAAU,SAAS,KAAK,SAAS;CACpE,MAAM,mBAAmB,gBAAgB,WAAW,SAAS,GAAG,EAAE;CAClE,MAAM,EAAE,UAAU,iBAAiB,gBAAgB,gBAAgB;CAEnE,MAAM,WAAW,WAAA;CAoBjB,OACE,qBAACA,QAAD;EAAe;EAAS,UAAA;EAAxB,UAAA,CACE,oBAAC,WAAD;GACE,IAAI,EAAE,IAAI,IAAI;GACd,uBAtBoB;IACxB,IAAI,UACF,OAAO,oBAAC,YAAD;KAAY,QAAO;KAAQ,MAAM;IAAK,CAAA;IAE/C,IACE;KAAC;KAAmB;KAAoB;IAAgB,CAAC,CAAC,SACxD,kBAAkB,UAAU,EAC9B,GAEA,OAAO,oBAAC,YAAD;KAAY,QAAO;KAAO,MAAM;IAAK,CAAA;IAE9C,OACE,oBAAC,eAAD,EAAA,UACE,oBAAC,yBAAD;KAAyB,MAAM;KAAI,IAAI;MAAE,KAAK;MAAI,MAAM;KAAG;IAAI,CAAA,EAClD,CAAA;GAEnB,EAAA,CAM+B;GACzB,SAAS,SAAS;GAClB,cACE,WACE,oBAAC,SAAD;IAAS,OAAO,EAAE,yBAAyB;IACzC,UAAA,oBAAC,cAAD;KAAc,MAAK;KAAQ,SAAS;KAClC,UAAA,oBAAC,eAAD,EAAe,IAAI,EAAE,UAAU,GAAG,EAAI,CAAA;IAC1B,CAAA;GACP,CAAA,IACP,gBAAgB,WAAW,WAC7B,oBAAC,YAAD;IAAY,IAAI;KAAE,UAAU;KAAI,YAAY;IAAI;IAC9C,UAAA,oBAAC,oBAAD,EACE,iBAAiB,mBAAmB,cAAc,EACnD,CAAA;GACS,CAAA,IACV,KAAA;EAEP,CAAA,GACD,oBAAC,aAAD,EAAoB,MAAQ,CAAA,CACxB;;AAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionCard.js","names":["Card"],"sources":["../../../../src/components/TransactionCard/TransactionCard.tsx"],"sourcesContent":["import type { RouteExtended } from '@lifi/sdk'\nimport { Box } from '@mui/material'\nimport type { JSX } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { Card } from '../Card/Card.js'\nimport { RouteTokens } from '../RouteCard/RouteTokens.js'\nimport { DateLabelContainer, DateLabelText } from './TransactionCard.style.js'\n\ninterface TransactionCardProps {\n route: RouteExtended\n date: Date\n onClick?: () => void\n}\n\nexport const TransactionCard = ({\n route,\n date,\n onClick,\n}: TransactionCardProps): JSX.Element => {\n const { i18n } = useTranslation()\n\n return (\n <Card indented onClick={onClick}>\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>\n <DateLabelContainer>\n <DateLabelText color=\"text.secondary\">\n {date.toLocaleString(i18n.language, { dateStyle: 'long' })}\n </DateLabelText>\n <DateLabelText color=\"text.secondary\">\n {date.toLocaleString(i18n.language, { timeStyle: 'short' })}\n </DateLabelText>\n </DateLabelContainer>\n <RouteTokens route={route} />\n </Box>\n </Card>\n )\n}\n"],"mappings":";;;;;;;AAcA,MAAa,mBAAmB,EAC9B,OACA,MACA,cACuC;CACvC,MAAM,EAAE,SAAS,eAAe;CAEhC,OACE,oBAACA,QAAD;EAAM,UAAA;EAAkB;
|
|
1
|
+
{"version":3,"file":"TransactionCard.js","names":["Card"],"sources":["../../../../src/components/TransactionCard/TransactionCard.tsx"],"sourcesContent":["import type { RouteExtended } from '@lifi/sdk'\nimport { Box } from '@mui/material'\nimport type { JSX } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { Card } from '../Card/Card.js'\nimport { RouteTokens } from '../RouteCard/RouteTokens.js'\nimport { DateLabelContainer, DateLabelText } from './TransactionCard.style.js'\n\ninterface TransactionCardProps {\n route: RouteExtended\n date: Date\n onClick?: () => void\n}\n\nexport const TransactionCard = ({\n route,\n date,\n onClick,\n}: TransactionCardProps): JSX.Element => {\n const { i18n } = useTranslation()\n\n return (\n <Card indented onClick={onClick}>\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>\n <DateLabelContainer>\n <DateLabelText color=\"text.secondary\">\n {date.toLocaleString(i18n.language, { dateStyle: 'long' })}\n </DateLabelText>\n <DateLabelText color=\"text.secondary\">\n {date.toLocaleString(i18n.language, { timeStyle: 'short' })}\n </DateLabelText>\n </DateLabelContainer>\n <RouteTokens route={route} />\n </Box>\n </Card>\n )\n}\n"],"mappings":";;;;;;;AAcA,MAAa,mBAAmB,EAC9B,OACA,MACA,cACuC;CACvC,MAAM,EAAE,SAAS,eAAe;CAEhC,OACE,oBAACA,QAAD;EAAM,UAAA;EAAkB;EACtB,UAAA,qBAAC,KAAD;GAAK,IAAI;IAAE,SAAS;IAAQ,eAAe;IAAU,KAAK;GAAI;GAA9D,UAAA,CACE,qBAAC,oBAAD,EAAA,UAAA,CACE,oBAAC,eAAD;IAAe,OAAM;IAClB,UAAA,KAAK,eAAe,KAAK,UAAU,EAAE,WAAW,OAAO,CAAC;GAC5C,CAAA,GACf,oBAAC,eAAD;IAAe,OAAM;IAClB,UAAA,KAAK,eAAe,KAAK,UAAU,EAAE,WAAW,QAAQ,CAAC;GAC7C,CAAA,CACG,EAAA,CAAA,GACpB,oBAAC,aAAD,EAAoB,MAAQ,CAAA,CACzB;;CACD,CAAA;AAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionCardSkeleton.js","names":["Card"],"sources":["../../../../src/components/TransactionCard/TransactionCardSkeleton.tsx"],"sourcesContent":["import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'\nimport { Box, Skeleton } from '@mui/material'\nimport type { JSX } from 'react'\nimport { Card } from '../Card/Card.js'\nimport { TokenSkeleton } from '../Token/Token.js'\n\ninterface TransactionCardSkeletonProps {\n active?: boolean\n}\n\nexport const TransactionCardSkeleton = ({\n active,\n}: TransactionCardSkeletonProps): JSX.Element => {\n return (\n <Card indented>\n {active ? (\n <Skeleton\n variant=\"rectangular\"\n height={40}\n sx={(theme) => ({\n borderRadius: theme.vars.shape.borderRadiusTertiary,\n mb: 1.5,\n })}\n />\n ) : (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n pb: 1.5,\n }}\n >\n <Skeleton\n variant=\"rectangular\"\n width={96}\n height={18}\n sx={(theme) => ({\n borderRadius: theme.vars.shape.borderRadius,\n })}\n />\n <Skeleton\n variant=\"rectangular\"\n width={64}\n height={18}\n sx={(theme) => ({\n borderRadius: theme.vars.shape.borderRadius,\n })}\n />\n </Box>\n )}\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>\n <TokenSkeleton />\n <Box\n sx={{\n width: 40,\n height: 20,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <ArrowDownwardIcon sx={{ fontSize: 16, color: 'text.secondary' }} />\n </Box>\n <TokenSkeleton />\n </Box>\n </Card>\n )\n}\n"],"mappings":";;;;;;AAUA,MAAa,2BAA2B,EACtC,aAC+C;CAC/C,OACE,qBAACA,QAAD;EAAM,UAAA;
|
|
1
|
+
{"version":3,"file":"TransactionCardSkeleton.js","names":["Card"],"sources":["../../../../src/components/TransactionCard/TransactionCardSkeleton.tsx"],"sourcesContent":["import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'\nimport { Box, Skeleton } from '@mui/material'\nimport type { JSX } from 'react'\nimport { Card } from '../Card/Card.js'\nimport { TokenSkeleton } from '../Token/Token.js'\n\ninterface TransactionCardSkeletonProps {\n active?: boolean\n}\n\nexport const TransactionCardSkeleton = ({\n active,\n}: TransactionCardSkeletonProps): JSX.Element => {\n return (\n <Card indented>\n {active ? (\n <Skeleton\n variant=\"rectangular\"\n height={40}\n sx={(theme) => ({\n borderRadius: theme.vars.shape.borderRadiusTertiary,\n mb: 1.5,\n })}\n />\n ) : (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n pb: 1.5,\n }}\n >\n <Skeleton\n variant=\"rectangular\"\n width={96}\n height={18}\n sx={(theme) => ({\n borderRadius: theme.vars.shape.borderRadius,\n })}\n />\n <Skeleton\n variant=\"rectangular\"\n width={64}\n height={18}\n sx={(theme) => ({\n borderRadius: theme.vars.shape.borderRadius,\n })}\n />\n </Box>\n )}\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>\n <TokenSkeleton />\n <Box\n sx={{\n width: 40,\n height: 20,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <ArrowDownwardIcon sx={{ fontSize: 16, color: 'text.secondary' }} />\n </Box>\n <TokenSkeleton />\n </Box>\n </Card>\n )\n}\n"],"mappings":";;;;;;AAUA,MAAa,2BAA2B,EACtC,aAC+C;CAC/C,OACE,qBAACA,QAAD;EAAM,UAAA;EAAN,UAAA,CACG,SACC,oBAAC,UAAD;GACE,SAAQ;GACR,QAAQ;GACR,KAAK,WAAW;IACd,cAAc,MAAM,KAAK,MAAM;IAC/B,IAAI;GACN;EACD,CAAA,IAED,qBAAC,KAAD;GACE,IAAI;IACF,SAAS;IACT,gBAAgB;IAChB,IAAI;GACN;GALF,UAAA,CAOE,oBAAC,UAAD;IACE,SAAQ;IACR,OAAO;IACP,QAAQ;IACR,KAAK,WAAW,EACd,cAAc,MAAM,KAAK,MAAM,aACjC;GACD,CAAA,GACD,oBAAC,UAAD;IACE,SAAQ;IACR,OAAO;IACP,QAAQ;IACR,KAAK,WAAW,EACd,cAAc,MAAM,KAAK,MAAM,aACjC;GACD,CAAA,CACE;EAEP,CAAA,GAAA,qBAAC,KAAD;GAAK,IAAI;IAAE,SAAS;IAAQ,eAAe;IAAU,KAAK;GAAI;GAA9D,UAAA;IACE,oBAAC,eAAD,CAAgB,CAAA;IAChB,oBAAC,KAAD;KACE,IAAI;MACF,OAAO;MACP,QAAQ;MACR,SAAS;MACT,YAAY;MACZ,gBAAgB;KAClB;KAEA,UAAA,oBAAC,mBAAD,EAAmB,IAAI;MAAE,UAAU;MAAI,OAAO;KAAiB,EAAI,CAAA;IAChE,CAAA;IACL,oBAAC,eAAD,CAAgB,CAAA;GACb;EACD,CAAA,CAAA;;AAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","names":[],"sources":["../../../src/config/version.ts"],"sourcesContent":["export const name = '@lifi/widget'\nexport const version = '4.
|
|
1
|
+
{"version":3,"file":"version.js","names":[],"sources":["../../../src/config/version.ts"],"sourcesContent":["export const name = '@lifi/widget'\nexport const version = '4.5.0'\n"],"mappings":";AAAA,MAAa,OAAO;AACpB,MAAa,UAAU"}
|
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
import { useChains } from "./useChains.js";
|
|
2
|
-
import { useFilteredTokensByBalance } from "./useFilteredByTokenBalances.js";
|
|
3
2
|
import { useMemo } from "react";
|
|
4
3
|
import { useAccount } from "@lifi/wallet-management";
|
|
5
4
|
//#region src/hooks/useAccountsBalancesData.ts
|
|
6
5
|
const useAccountsBalancesData = (selectedChainId, formType, isAllNetworks, allTokens) => {
|
|
7
|
-
const { data: accountsWithTokens, isLoading: isAccountsLoading } = useAccountsData(selectedChainId, formType, isAllNetworks, allTokens);
|
|
8
|
-
const { data: filteredTokens, isLoading: isCachedBalancesLoading } = useFilteredTokensByBalance(accountsWithTokens, formType);
|
|
9
|
-
return {
|
|
10
|
-
data: filteredTokens,
|
|
11
|
-
isLoading: isAccountsLoading || isCachedBalancesLoading
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
const useAccountsData = (selectedChainId, formType, isAllNetworks, allTokens) => {
|
|
15
6
|
const { chains: allChains, isLoading: isChainsLoading, getChainById } = useChains(formType);
|
|
16
7
|
const currentChain = useMemo(() => {
|
|
17
8
|
return selectedChainId ? getChainById(selectedChainId, allChains) : void 0;
|
|
@@ -43,15 +34,11 @@ const useAccountsData = (selectedChainId, formType, isAllNetworks, allTokens) =>
|
|
|
43
34
|
const accountChains = chains?.filter((chain) => account.chainType === chain?.chainType);
|
|
44
35
|
if (accountChains) {
|
|
45
36
|
const chainIdSet = new Set(accountChains.map((chain) => chain.id));
|
|
46
|
-
|
|
37
|
+
acc[account.address] = Object.entries(allTokens).reduce((tokenAcc, [chainIdStr, tokens]) => {
|
|
47
38
|
const chainId = Number(chainIdStr);
|
|
48
39
|
if (chainIdSet.has(chainId)) tokenAcc[chainId] = tokens;
|
|
49
40
|
return tokenAcc;
|
|
50
41
|
}, {});
|
|
51
|
-
acc[account.address] = {
|
|
52
|
-
chainType: account.chainType,
|
|
53
|
-
tokens: filteredTokens
|
|
54
|
-
};
|
|
55
42
|
}
|
|
56
43
|
}
|
|
57
44
|
return acc;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAccountsBalancesData.js","names":[],"sources":["../../../src/hooks/useAccountsBalancesData.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"useAccountsBalancesData.js","names":[],"sources":["../../../src/hooks/useAccountsBalancesData.ts"],"sourcesContent":["import type { TokenExtended } from '@lifi/sdk'\nimport { useAccount } from '@lifi/wallet-management'\nimport { useMemo } from 'react'\nimport type { FormType } from '../stores/form/types.js'\nimport { useChains } from './useChains.js'\n\nexport const useAccountsBalancesData = (\n selectedChainId?: number,\n formType?: FormType,\n isAllNetworks?: boolean,\n allTokens?: Record<number, TokenExtended[]>\n): {\n data: Record<string, Record<number, TokenExtended[]>> | undefined\n isLoading: boolean\n} => {\n const {\n chains: allChains,\n isLoading: isChainsLoading,\n getChainById,\n } = useChains(formType)\n const currentChain = useMemo(() => {\n return selectedChainId\n ? getChainById(selectedChainId, allChains)\n : undefined\n }, [selectedChainId, allChains, getChainById])\n const chains = useMemo(() => {\n return isAllNetworks ? allChains : currentChain ? [currentChain] : undefined\n }, [allChains, isAllNetworks, currentChain])\n\n const { accounts: allAccounts, account: currentAccount } = useAccount(\n isAllNetworks ? undefined : { chainType: currentChain?.chainType }\n )\n const accounts = useMemo(() => {\n return isAllNetworks\n ? allAccounts\n : currentAccount\n ? [currentAccount]\n : undefined\n }, [allAccounts, currentAccount, isAllNetworks])\n\n const accountsWithTokens = useMemo(() => {\n if (!chains || !allTokens || !accounts?.length) {\n return undefined\n }\n return accounts\n ?.filter((account) => account.address)\n .reduce(\n (acc, account) => {\n if (account.address) {\n const accountChains = chains?.filter(\n (chain) => account.chainType === chain?.chainType\n )\n if (accountChains) {\n const chainIdSet = new Set(accountChains.map((chain) => chain.id))\n acc[account.address] = Object.entries(allTokens).reduce(\n (tokenAcc, [chainIdStr, tokens]) => {\n const chainId = Number(chainIdStr)\n if (chainIdSet.has(chainId)) {\n tokenAcc[chainId] = tokens\n }\n return tokenAcc\n },\n {} as Record<number, TokenExtended[]>\n )\n }\n }\n return acc\n },\n {} as Record<string, Record<number, TokenExtended[]>>\n )\n }, [accounts, chains, allTokens])\n\n return {\n data: accountsWithTokens,\n isLoading: isChainsLoading,\n }\n}\n"],"mappings":";;;;AAMA,MAAa,2BACX,iBACA,UACA,eACA,cAIG;CACH,MAAM,EACJ,QAAQ,WACR,WAAW,iBACX,iBACE,UAAU,QAAQ;CACtB,MAAM,eAAe,cAAc;EACjC,OAAO,kBACH,aAAa,iBAAiB,SAAS,IACvC,KAAA;CACN,GAAG;EAAC;EAAiB;EAAW;CAAY,CAAC;CAC7C,MAAM,SAAS,cAAc;EAC3B,OAAO,gBAAgB,YAAY,eAAe,CAAC,YAAY,IAAI,KAAA;CACrE,GAAG;EAAC;EAAW;EAAe;CAAY,CAAC;CAE3C,MAAM,EAAE,UAAU,aAAa,SAAS,mBAAmB,WACzD,gBAAgB,KAAA,IAAY,EAAE,WAAW,cAAc,UAAU,CACnE;CACA,MAAM,WAAW,cAAc;EAC7B,OAAO,gBACH,cACA,iBACE,CAAC,cAAc,IACf,KAAA;CACR,GAAG;EAAC;EAAa;EAAgB;CAAa,CAAC;CAkC/C,OAAO;EACL,MAjCyB,cAAc;GACvC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,QACtC;GAEF,OAAO,UACH,QAAQ,YAAY,QAAQ,OAAO,CAAC,CACrC,QACE,KAAK,YAAY;IAChB,IAAI,QAAQ,SAAS;KACnB,MAAM,gBAAgB,QAAQ,QAC3B,UAAU,QAAQ,cAAc,OAAO,SAC1C;KACA,IAAI,eAAe;MACjB,MAAM,aAAa,IAAI,IAAI,cAAc,KAAK,UAAU,MAAM,EAAE,CAAC;MACjE,IAAI,QAAQ,WAAW,OAAO,QAAQ,SAAS,CAAC,CAAC,QAC9C,UAAU,CAAC,YAAY,YAAY;OAClC,MAAM,UAAU,OAAO,UAAU;OACjC,IAAI,WAAW,IAAI,OAAO,GACxB,SAAS,WAAW;OAEtB,OAAO;MACT,GACA,CAAC,CACH;KACF;IACF;IACA,OAAO;GACT,GACA,CAAC,CACH;EACJ,GAAG;GAAC;GAAU;GAAQ;EAAS,CAGN;EACvB,WAAW;CACb;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToAddressAutoPopulate.js","names":[],"sources":["../../../src/hooks/useToAddressAutoPopulate.ts"],"sourcesContent":["import { useAccount } from '@lifi/wallet-management'\nimport { useChainTypeFromAddress } from '@lifi/widget-provider'\nimport { useCallback } from 'react'\nimport { useBookmarkActions } from '../stores/bookmarks/useBookmarkActions.js'\nimport type { FormType } from '../stores/form/types.js'\nimport { useFieldActions } from '../stores/form/useFieldActions.js'\nimport { useAvailableChains } from './useAvailableChains.js'\n\ntype UpdateToAddressArgs = {\n formType: FormType\n selectedToAddress?: string\n selectedChainId?: number\n selectedOppositeTokenAddress?: string\n selectedOppositeChainId?: number\n}\n\n/**\n * Automatically populates toAddress field if bridging across ecosystems and compatible wallet is connected\n */\nexport const useToAddressAutoPopulate = (): ((\n args: UpdateToAddressArgs\n) => string | undefined) => {\n const { setFieldValue } = useFieldActions()\n const { setSelectedBookmark } = useBookmarkActions()\n const { getChainById } = useAvailableChains()\n const { accounts } = useAccount()\n const { getChainTypeFromAddress } = useChainTypeFromAddress()\n\n return useCallback(\n ({\n formType,\n selectedToAddress,\n selectedChainId,\n selectedOppositeTokenAddress,\n selectedOppositeChainId,\n }: UpdateToAddressArgs) => {\n if (\n !selectedOppositeTokenAddress ||\n !selectedOppositeChainId ||\n !selectedChainId ||\n !accounts?.length\n ) {\n return\n }\n const selectedChain = getChainById?.(selectedChainId)\n const selectedOppositeChain = getChainById?.(selectedOppositeChainId)\n // Proceed if both chains are defined and of different ecosystem types (indicating cross-ecosystem bridging)\n if (\n !selectedChain ||\n !selectedOppositeChain ||\n selectedChain.chainType === selectedOppositeChain.chainType\n ) {\n return\n }\n // Identify the destination chain type based on the bridge direction ('from' or 'to')\n const destinationChainType =\n formType === 'from'\n ? selectedOppositeChain.chainType\n : selectedChain.chainType\n // If toAddress is already selected, verify that it matches the destination chain type\n if (selectedToAddress) {\n const selectedToAddressChainType =\n getChainTypeFromAddress(selectedToAddress)\n if (destinationChainType === selectedToAddressChainType) {\n return\n }\n }\n // Find connected account compatible with the destination chain type\n const destinationAccount = accounts?.find(\n (account) => account.chainType === destinationChainType\n )\n // If a compatible destination account is found, set toAddress as if selecting it from the \"Send to Wallet\" connected wallets page\n if (destinationAccount?.address) {\n setFieldValue('toAddress', destinationAccount.address, {\n isDirty: false,\n isTouched: true,\n })\n setSelectedBookmark({\n name: destinationAccount.connector?.name,\n address: destinationAccount.address,\n chainType: destinationAccount.chainType,\n isConnectedAccount: true,\n })\n return destinationAccount.address\n }\n },\n [\n accounts,\n getChainById,\n setFieldValue,\n setSelectedBookmark,\n getChainTypeFromAddress,\n ]\n )\n}\n"],"mappings":";;;;;;;;;;AAmBA,MAAa,iCAEe;CAC1B,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,EAAE,wBAAwB,mBAAmB;CACnD,MAAM,EAAE,iBAAiB,mBAAmB;CAC5C,MAAM,EAAE,aAAa,WAAW;CAChC,MAAM,EAAE,4BAA4B,wBAAwB;CAE5D,OAAO,aACJ,EACC,UACA,mBACA,iBACA,8BACA,8BACyB;EACzB,IACE,CAAC,gCACD,CAAC,2BACD,CAAC,mBACD,CAAC,UAAU,QAEX;EAEF,MAAM,gBAAgB,eAAe,eAAe;EACpD,MAAM,wBAAwB,eAAe,uBAAuB;EAEpE,IACE,CAAC,iBACD,CAAC,yBACD,cAAc,cAAc,sBAAsB,WAElD;EAGF,MAAM,uBACJ,aAAa,SACT,sBAAsB,YACtB,cAAc;EAEpB,IAAI;
|
|
1
|
+
{"version":3,"file":"useToAddressAutoPopulate.js","names":[],"sources":["../../../src/hooks/useToAddressAutoPopulate.ts"],"sourcesContent":["import { useAccount } from '@lifi/wallet-management'\nimport { useChainTypeFromAddress } from '@lifi/widget-provider'\nimport { useCallback } from 'react'\nimport { useBookmarkActions } from '../stores/bookmarks/useBookmarkActions.js'\nimport type { FormType } from '../stores/form/types.js'\nimport { useFieldActions } from '../stores/form/useFieldActions.js'\nimport { useAvailableChains } from './useAvailableChains.js'\n\ntype UpdateToAddressArgs = {\n formType: FormType\n selectedToAddress?: string\n selectedChainId?: number\n selectedOppositeTokenAddress?: string\n selectedOppositeChainId?: number\n}\n\n/**\n * Automatically populates toAddress field if bridging across ecosystems and compatible wallet is connected\n */\nexport const useToAddressAutoPopulate = (): ((\n args: UpdateToAddressArgs\n) => string | undefined) => {\n const { setFieldValue } = useFieldActions()\n const { setSelectedBookmark } = useBookmarkActions()\n const { getChainById } = useAvailableChains()\n const { accounts } = useAccount()\n const { getChainTypeFromAddress } = useChainTypeFromAddress()\n\n return useCallback(\n ({\n formType,\n selectedToAddress,\n selectedChainId,\n selectedOppositeTokenAddress,\n selectedOppositeChainId,\n }: UpdateToAddressArgs) => {\n if (\n !selectedOppositeTokenAddress ||\n !selectedOppositeChainId ||\n !selectedChainId ||\n !accounts?.length\n ) {\n return\n }\n const selectedChain = getChainById?.(selectedChainId)\n const selectedOppositeChain = getChainById?.(selectedOppositeChainId)\n // Proceed if both chains are defined and of different ecosystem types (indicating cross-ecosystem bridging)\n if (\n !selectedChain ||\n !selectedOppositeChain ||\n selectedChain.chainType === selectedOppositeChain.chainType\n ) {\n return\n }\n // Identify the destination chain type based on the bridge direction ('from' or 'to')\n const destinationChainType =\n formType === 'from'\n ? selectedOppositeChain.chainType\n : selectedChain.chainType\n // If toAddress is already selected, verify that it matches the destination chain type\n if (selectedToAddress) {\n const selectedToAddressChainType =\n getChainTypeFromAddress(selectedToAddress)\n if (destinationChainType === selectedToAddressChainType) {\n return\n }\n }\n // Find connected account compatible with the destination chain type\n const destinationAccount = accounts?.find(\n (account) => account.chainType === destinationChainType\n )\n // If a compatible destination account is found, set toAddress as if selecting it from the \"Send to Wallet\" connected wallets page\n if (destinationAccount?.address) {\n setFieldValue('toAddress', destinationAccount.address, {\n isDirty: false,\n isTouched: true,\n })\n setSelectedBookmark({\n name: destinationAccount.connector?.name,\n address: destinationAccount.address,\n chainType: destinationAccount.chainType,\n isConnectedAccount: true,\n })\n return destinationAccount.address\n }\n },\n [\n accounts,\n getChainById,\n setFieldValue,\n setSelectedBookmark,\n getChainTypeFromAddress,\n ]\n )\n}\n"],"mappings":";;;;;;;;;;AAmBA,MAAa,iCAEe;CAC1B,MAAM,EAAE,kBAAkB,gBAAgB;CAC1C,MAAM,EAAE,wBAAwB,mBAAmB;CACnD,MAAM,EAAE,iBAAiB,mBAAmB;CAC5C,MAAM,EAAE,aAAa,WAAW;CAChC,MAAM,EAAE,4BAA4B,wBAAwB;CAE5D,OAAO,aACJ,EACC,UACA,mBACA,iBACA,8BACA,8BACyB;EACzB,IACE,CAAC,gCACD,CAAC,2BACD,CAAC,mBACD,CAAC,UAAU,QAEX;EAEF,MAAM,gBAAgB,eAAe,eAAe;EACpD,MAAM,wBAAwB,eAAe,uBAAuB;EAEpE,IACE,CAAC,iBACD,CAAC,yBACD,cAAc,cAAc,sBAAsB,WAElD;EAGF,MAAM,uBACJ,aAAa,SACT,sBAAsB,YACtB,cAAc;EAEpB,IAAI,mBAGE;OAAA,yBADF,wBAAwB,iBAC4B,GACpD;EAAA;EAIJ,MAAM,qBAAqB,UAAU,MAClC,YAAY,QAAQ,cAAc,oBACrC;EAEA,IAAI,oBAAoB,SAAS;GAC/B,cAAc,aAAa,mBAAmB,SAAS;IACrD,SAAS;IACT,WAAW;GACb,CAAC;GACD,oBAAoB;IAClB,MAAM,mBAAmB,WAAW;IACpC,SAAS,mBAAmB;IAC5B,WAAW,mBAAmB;IAC9B,oBAAoB;GACtB,CAAC;GACD,OAAO,mBAAmB;EAC5B;CACF,GACA;EACE;EACA;EACA;EACA;EACA;CACF,CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTokenBalances.js","names":[],"sources":["../../../src/hooks/useTokenBalances.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormType } from '../stores/form/types.js'\nimport { useSettings } from '../stores/settings/useSettings.js'\nimport type { TokenAmount } from '../types/token.js'\nimport { formatTokenPrice } from '../utils/format.js'\nimport { isSearchMatch, processTokenList } from '../utils/tokenList.js'\nimport { useAccountsBalancesData } from './useAccountsBalancesData.js'\nimport { useDisplayedTokens } from './useDisplayedTokens.js'\nimport { useTokenBalancesQueries } from './useTokenBalancesQueries.js'\n\nexport const useTokenBalances = (\n selectedChainId?: number,\n formType?: FormType,\n isAllNetworks?: boolean,\n search?: string\n): {\n tokens: TokenAmount[]\n withCategories: boolean\n withPinnedTokens: boolean\n isTokensLoading: boolean\n isSearchLoading: boolean\n isBalanceLoading: boolean\n} => {\n const { hiddenUI, tokens: configTokens } = useWidgetConfig()\n const {\n allTokens,\n displayedTokensList,\n isPinnedToken,\n isTokensLoading,\n isSearchLoading,\n } = useDisplayedTokens(selectedChainId, formType, isAllNetworks, search)\n\n const { data: accountsWithAllTokens, isLoading: isAccountsLoading } =\n useAccountsBalancesData(selectedChainId, formType, isAllNetworks, allTokens)\n\n const isBalanceLoadingEnabled =\n Boolean(accountsWithAllTokens) && !isAccountsLoading\n\n const { data: allTokensWithBalances, isLoading: isBalanceQueriesLoading } =\n useTokenBalancesQueries(accountsWithAllTokens, isBalanceLoadingEnabled)\n\n const { smallBalanceThreshold } = useSettings(['smallBalanceThreshold'])\n\n const isBalanceLoading =\n (isBalanceQueriesLoading || isAccountsLoading) &&\n !allTokensWithBalances?.length\n\n const displayedTokensWithBalances = useMemo(() => {\n const balancesByChain = isAllNetworks\n ? allTokensWithBalances\n : selectedChainId\n ? allTokensWithBalances?.filter((t) => t.chainId === selectedChainId)\n : undefined\n const displayedTokensSet = new Set(\n displayedTokensList?.map(\n (t) => `${t.chainId}-${t.address.toLowerCase()}`\n ) || []\n )\n\n const hideSmallBalances =\n !!smallBalanceThreshold && !hiddenUI?.hideSmallBalances\n const threshold = hideSmallBalances\n ? Number.parseFloat(smallBalanceThreshold)\n : undefined\n\n if (!balancesByChain) {\n return undefined\n }\n\n return balancesByChain.reduce<typeof balancesByChain>((acc, token) => {\n const tokenKey = `${token.chainId}-${token.address.toLowerCase()}`\n // Check if token is in displayed list and has amount\n const isInDisplayedList = displayedTokensSet.has(tokenKey) && token.amount\n // Check if it matches search (for cached appended tokens)\n const matchesSearch = isSearchMatch(token, search)\n\n // Filter: only include tokens that match our criteria\n if (!isInDisplayedList && !matchesSearch) {\n return acc\n }\n\n // Apply small balance threshold transformation if enabled\n let processedToken = token\n if (\n hideSmallBalances &&\n threshold !== undefined &&\n threshold >= 0 &&\n token.amount\n ) {\n const balanceUSD = formatTokenPrice(\n token.amount,\n token.priceUSD,\n token.decimals\n )\n if (balanceUSD < threshold) {\n processedToken = {\n ...token,\n amount: 0n,\n }\n }\n }\n\n acc.push(processedToken)\n return acc\n }, [])\n }, [\n allTokensWithBalances,\n displayedTokensList,\n search,\n selectedChainId,\n isAllNetworks,\n smallBalanceThreshold,\n hiddenUI,\n ])\n\n const { processedTokens, withCategories, withPinnedTokens } = useMemo(() => {\n return processTokenList(\n isBalanceLoading,\n isAllNetworks || !!search,\n configTokens,\n selectedChainId,\n displayedTokensList,\n displayedTokensWithBalances,\n isPinnedToken\n )\n }, [\n isBalanceLoading,\n isAllNetworks,\n configTokens,\n selectedChainId,\n displayedTokensList,\n displayedTokensWithBalances,\n search,\n isPinnedToken,\n ])\n\n return {\n tokens: processedTokens ?? [],\n withCategories,\n withPinnedTokens,\n isTokensLoading,\n isSearchLoading,\n isBalanceLoading,\n }\n}\n"],"mappings":";;;;;;;;;AAWA,MAAa,oBACX,iBACA,UACA,eACA,WAQG;CACH,MAAM,EAAE,UAAU,QAAQ,iBAAiB,gBAAgB;CAC3D,MAAM,EACJ,WACA,qBACA,eACA,iBACA,oBACE,mBAAmB,iBAAiB,UAAU,eAAe,MAAM;CAEvE,MAAM,EAAE,MAAM,uBAAuB,WAAW,sBAC9C,wBAAwB,iBAAiB,UAAU,eAAe,SAAS;CAK7E,MAAM,EAAE,MAAM,uBAAuB,WAAW,4BAC9C,wBAAwB,uBAHxB,QAAQ,qBAAqB,KAAK,CAAC,iBAGmC;CAExE,MAAM,EAAE,0BAA0B,YAAY,CAAC,uBAAuB,CAAC;CAEvE,MAAM,oBACH,2BAA2B,sBAC5B,CAAC,uBAAuB;CAE1B,MAAM,8BAA8B,cAAc;EAChD,MAAM,kBAAkB,gBACpB,wBACA,kBACE,uBAAuB,QAAQ,MAAM,EAAE,YAAY,eAAe,IAClE,KAAA;EACN,MAAM,qBAAqB,IAAI,IAC7B,qBAAqB,KAClB,MAAM,GAAG,EAAE,QAAQ,GAAG,EAAE,QAAQ,YAAY,GAC/C,KAAK,CAAC,CACR;EAEA,MAAM,oBACJ,CAAC,CAAC,yBAAyB,CAAC,UAAU;EACxC,MAAM,YAAY,oBACd,OAAO,WAAW,qBAAqB,IACvC,KAAA;EAEJ,IAAI,CAAC,iBACH;EAGF,OAAO,gBAAgB,QAAgC,KAAK,UAAU;GACpE,MAAM,WAAW,GAAG,MAAM,QAAQ,GAAG,MAAM,QAAQ,YAAY;GAE/D,MAAM,oBAAoB,mBAAmB,IAAI,QAAQ,KAAK,MAAM;GAEpE,MAAM,gBAAgB,cAAc,OAAO,MAAM;GAGjD,IAAI,CAAC,qBAAqB,CAAC,eACzB,OAAO;GAIT,IAAI,iBAAiB;GACrB,IACE,qBACA,cAAc,KAAA,KACd,aAAa,KACb,MAAM;
|
|
1
|
+
{"version":3,"file":"useTokenBalances.js","names":[],"sources":["../../../src/hooks/useTokenBalances.ts"],"sourcesContent":["import { useMemo } from 'react'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormType } from '../stores/form/types.js'\nimport { useSettings } from '../stores/settings/useSettings.js'\nimport type { TokenAmount } from '../types/token.js'\nimport { formatTokenPrice } from '../utils/format.js'\nimport { isSearchMatch, processTokenList } from '../utils/tokenList.js'\nimport { useAccountsBalancesData } from './useAccountsBalancesData.js'\nimport { useDisplayedTokens } from './useDisplayedTokens.js'\nimport { useTokenBalancesQueries } from './useTokenBalancesQueries.js'\n\nexport const useTokenBalances = (\n selectedChainId?: number,\n formType?: FormType,\n isAllNetworks?: boolean,\n search?: string\n): {\n tokens: TokenAmount[]\n withCategories: boolean\n withPinnedTokens: boolean\n isTokensLoading: boolean\n isSearchLoading: boolean\n isBalanceLoading: boolean\n} => {\n const { hiddenUI, tokens: configTokens } = useWidgetConfig()\n const {\n allTokens,\n displayedTokensList,\n isPinnedToken,\n isTokensLoading,\n isSearchLoading,\n } = useDisplayedTokens(selectedChainId, formType, isAllNetworks, search)\n\n const { data: accountsWithAllTokens, isLoading: isAccountsLoading } =\n useAccountsBalancesData(selectedChainId, formType, isAllNetworks, allTokens)\n\n const isBalanceLoadingEnabled =\n Boolean(accountsWithAllTokens) && !isAccountsLoading\n\n const { data: allTokensWithBalances, isLoading: isBalanceQueriesLoading } =\n useTokenBalancesQueries(accountsWithAllTokens, isBalanceLoadingEnabled)\n\n const { smallBalanceThreshold } = useSettings(['smallBalanceThreshold'])\n\n const isBalanceLoading =\n (isBalanceQueriesLoading || isAccountsLoading) &&\n !allTokensWithBalances?.length\n\n const displayedTokensWithBalances = useMemo(() => {\n const balancesByChain = isAllNetworks\n ? allTokensWithBalances\n : selectedChainId\n ? allTokensWithBalances?.filter((t) => t.chainId === selectedChainId)\n : undefined\n const displayedTokensSet = new Set(\n displayedTokensList?.map(\n (t) => `${t.chainId}-${t.address.toLowerCase()}`\n ) || []\n )\n\n const hideSmallBalances =\n !!smallBalanceThreshold && !hiddenUI?.hideSmallBalances\n const threshold = hideSmallBalances\n ? Number.parseFloat(smallBalanceThreshold)\n : undefined\n\n if (!balancesByChain) {\n return undefined\n }\n\n return balancesByChain.reduce<typeof balancesByChain>((acc, token) => {\n const tokenKey = `${token.chainId}-${token.address.toLowerCase()}`\n // Check if token is in displayed list and has amount\n const isInDisplayedList = displayedTokensSet.has(tokenKey) && token.amount\n // Check if it matches search (for cached appended tokens)\n const matchesSearch = isSearchMatch(token, search)\n\n // Filter: only include tokens that match our criteria\n if (!isInDisplayedList && !matchesSearch) {\n return acc\n }\n\n // Apply small balance threshold transformation if enabled\n let processedToken = token\n if (\n hideSmallBalances &&\n threshold !== undefined &&\n threshold >= 0 &&\n token.amount\n ) {\n const balanceUSD = formatTokenPrice(\n token.amount,\n token.priceUSD,\n token.decimals\n )\n if (balanceUSD < threshold) {\n processedToken = {\n ...token,\n amount: 0n,\n }\n }\n }\n\n acc.push(processedToken)\n return acc\n }, [])\n }, [\n allTokensWithBalances,\n displayedTokensList,\n search,\n selectedChainId,\n isAllNetworks,\n smallBalanceThreshold,\n hiddenUI,\n ])\n\n const { processedTokens, withCategories, withPinnedTokens } = useMemo(() => {\n return processTokenList(\n isBalanceLoading,\n isAllNetworks || !!search,\n configTokens,\n selectedChainId,\n displayedTokensList,\n displayedTokensWithBalances,\n isPinnedToken\n )\n }, [\n isBalanceLoading,\n isAllNetworks,\n configTokens,\n selectedChainId,\n displayedTokensList,\n displayedTokensWithBalances,\n search,\n isPinnedToken,\n ])\n\n return {\n tokens: processedTokens ?? [],\n withCategories,\n withPinnedTokens,\n isTokensLoading,\n isSearchLoading,\n isBalanceLoading,\n }\n}\n"],"mappings":";;;;;;;;;AAWA,MAAa,oBACX,iBACA,UACA,eACA,WAQG;CACH,MAAM,EAAE,UAAU,QAAQ,iBAAiB,gBAAgB;CAC3D,MAAM,EACJ,WACA,qBACA,eACA,iBACA,oBACE,mBAAmB,iBAAiB,UAAU,eAAe,MAAM;CAEvE,MAAM,EAAE,MAAM,uBAAuB,WAAW,sBAC9C,wBAAwB,iBAAiB,UAAU,eAAe,SAAS;CAK7E,MAAM,EAAE,MAAM,uBAAuB,WAAW,4BAC9C,wBAAwB,uBAHxB,QAAQ,qBAAqB,KAAK,CAAC,iBAGmC;CAExE,MAAM,EAAE,0BAA0B,YAAY,CAAC,uBAAuB,CAAC;CAEvE,MAAM,oBACH,2BAA2B,sBAC5B,CAAC,uBAAuB;CAE1B,MAAM,8BAA8B,cAAc;EAChD,MAAM,kBAAkB,gBACpB,wBACA,kBACE,uBAAuB,QAAQ,MAAM,EAAE,YAAY,eAAe,IAClE,KAAA;EACN,MAAM,qBAAqB,IAAI,IAC7B,qBAAqB,KAClB,MAAM,GAAG,EAAE,QAAQ,GAAG,EAAE,QAAQ,YAAY,GAC/C,KAAK,CAAC,CACR;EAEA,MAAM,oBACJ,CAAC,CAAC,yBAAyB,CAAC,UAAU;EACxC,MAAM,YAAY,oBACd,OAAO,WAAW,qBAAqB,IACvC,KAAA;EAEJ,IAAI,CAAC,iBACH;EAGF,OAAO,gBAAgB,QAAgC,KAAK,UAAU;GACpE,MAAM,WAAW,GAAG,MAAM,QAAQ,GAAG,MAAM,QAAQ,YAAY;GAE/D,MAAM,oBAAoB,mBAAmB,IAAI,QAAQ,KAAK,MAAM;GAEpE,MAAM,gBAAgB,cAAc,OAAO,MAAM;GAGjD,IAAI,CAAC,qBAAqB,CAAC,eACzB,OAAO;GAIT,IAAI,iBAAiB;GACrB,IACE,qBACA,cAAc,KAAA,KACd,aAAa,KACb,MAAM,QAEa;QAAA,iBACjB,MAAM,QACN,MAAM,UACN,MAAM,QAEK,IAAI,WACf,iBAAiB;KACf,GAAG;KACH,QAAQ;IACV;GAAA;GAIJ,IAAI,KAAK,cAAc;GACvB,OAAO;EACT,GAAG,CAAC,CAAC;CACP,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,iBAAiB,gBAAgB,qBAAqB,cAAc;EAC1E,OAAO,iBACL,kBACA,iBAAiB,CAAC,CAAC,QACnB,cACA,iBACA,qBACA,6BACA,aACF;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,OAAO;EACL,QAAQ,mBAAmB,CAAC;EAC5B;EACA;EACA;EACA;EACA;CACF;AACF"}
|
|
@@ -3,9 +3,10 @@ import { useSDKClient } from "../providers/SDKClientProvider.js";
|
|
|
3
3
|
import { getQueryKey } from "../utils/queries.js";
|
|
4
4
|
import { getTokenBalances } from "@lifi/sdk";
|
|
5
5
|
import { useMemo, useRef } from "react";
|
|
6
|
-
import { useQueries } from "@tanstack/react-query";
|
|
6
|
+
import { keepPreviousData, useQueries } from "@tanstack/react-query";
|
|
7
7
|
//#region src/hooks/useTokenBalancesQueries.ts
|
|
8
8
|
const defaultRefetchInterval = 32e3;
|
|
9
|
+
const balanceRevealTimeout = 2e3;
|
|
9
10
|
const useTokenBalancesQueries = (accountsWithTokens, isBalanceLoadingEnabled) => {
|
|
10
11
|
const { keyPrefix } = useWidgetConfig();
|
|
11
12
|
const sdkClient = useSDKClient();
|
|
@@ -29,7 +30,8 @@ const useTokenBalancesQueries = (accountsWithTokens, isBalanceLoadingEnabled) =>
|
|
|
29
30
|
enabled: isBalanceLoadingEnabled,
|
|
30
31
|
refetchInterval: defaultRefetchInterval,
|
|
31
32
|
staleTime: defaultRefetchInterval,
|
|
32
|
-
|
|
33
|
+
placeholderData: keepPreviousData,
|
|
34
|
+
retry: false
|
|
33
35
|
};
|
|
34
36
|
}));
|
|
35
37
|
}, [
|
|
@@ -44,7 +46,7 @@ const useTokenBalancesQueries = (accountsWithTokens, isBalanceLoadingEnabled) =>
|
|
|
44
46
|
const allComplete = results.every((result) => result.isSuccess || result.isError);
|
|
45
47
|
if (allComplete) firstLoadStartRef.current = null;
|
|
46
48
|
const timeSinceStart = firstLoadStartRef.current ? now - firstLoadStartRef.current : 0;
|
|
47
|
-
if (allComplete || timeSinceStart >=
|
|
49
|
+
if (allComplete || timeSinceStart >= balanceRevealTimeout) return {
|
|
48
50
|
data: results.flatMap((result) => result.data || []).filter((token) => token.amount),
|
|
49
51
|
isLoading: !allComplete,
|
|
50
52
|
isError: results.some((result) => result.isError)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTokenBalancesQueries.js","names":[],"sources":["../../../src/hooks/useTokenBalancesQueries.ts"],"sourcesContent":["import { getTokenBalances, type TokenExtended } from '@lifi/sdk'\nimport { useQueries } from '@tanstack/react-query'\nimport { useMemo, useRef } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { TokenAmount, TokenAmountExtended } from '../types/token.js'\nimport { getQueryKey } from '../utils/queries.js'\n\nconst defaultRefetchInterval = 32_000\n\nexport const useTokenBalancesQueries = (\n accountsWithTokens?: Record<string, Record<number, TokenExtended[]>>,\n isBalanceLoadingEnabled?: boolean\n): {\n data: TokenAmount[] | undefined\n isLoading: boolean\n isError: boolean\n} => {\n const { keyPrefix } = useWidgetConfig()\n const sdkClient = useSDKClient()\n const firstLoadStartRef = useRef<number | null>(null)\n\n const queryConfig = useMemo(() => {\n if (!accountsWithTokens) {\n return []\n }\n return Object.entries(accountsWithTokens).flatMap(\n ([accountAddress, chainTokens]) =>\n Object.entries(chainTokens).map(([chainIdStr, tokens]) => {\n const chainId = Number(chainIdStr)\n return {\n queryKey: [\n getQueryKey('token-balances', keyPrefix),\n accountAddress,\n chainId,\n tokens.length,\n ],\n queryFn: async (): Promise<TokenAmountExtended[]> => {\n if (!accountAddress || !tokens) {\n return []\n }\n return await getTokenBalances(sdkClient, accountAddress, tokens)\n },\n enabled: isBalanceLoadingEnabled,\n refetchInterval: defaultRefetchInterval,\n staleTime: defaultRefetchInterval,\n keepPreviousData:
|
|
1
|
+
{"version":3,"file":"useTokenBalancesQueries.js","names":[],"sources":["../../../src/hooks/useTokenBalancesQueries.ts"],"sourcesContent":["import { getTokenBalances, type TokenExtended } from '@lifi/sdk'\nimport { keepPreviousData, useQueries } from '@tanstack/react-query'\nimport { useMemo, useRef } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { TokenAmount, TokenAmountExtended } from '../types/token.js'\nimport { getQueryKey } from '../utils/queries.js'\n\nconst defaultRefetchInterval = 32_000\n// Max time to hold the skeleton before revealing balances in the multi-chain view.\n// Sits just below the typical full-settle time so the list reveals once, sorted,\n// instead of reordering as each chain streams in.\nconst balanceRevealTimeout = 2_000\n\nexport const useTokenBalancesQueries = (\n accountsWithTokens?: Record<string, Record<number, TokenExtended[]>>,\n isBalanceLoadingEnabled?: boolean\n): {\n data: TokenAmount[] | undefined\n isLoading: boolean\n isError: boolean\n} => {\n const { keyPrefix } = useWidgetConfig()\n const sdkClient = useSDKClient()\n const firstLoadStartRef = useRef<number | null>(null)\n\n const queryConfig = useMemo(() => {\n if (!accountsWithTokens) {\n return []\n }\n return Object.entries(accountsWithTokens).flatMap(\n ([accountAddress, chainTokens]) =>\n Object.entries(chainTokens).map(([chainIdStr, tokens]) => {\n const chainId = Number(chainIdStr)\n return {\n queryKey: [\n getQueryKey('token-balances', keyPrefix),\n accountAddress,\n chainId,\n tokens.length,\n ],\n queryFn: async (): Promise<TokenAmountExtended[]> => {\n if (!accountAddress || !tokens) {\n return []\n }\n return await getTokenBalances(sdkClient, accountAddress, tokens)\n },\n enabled: isBalanceLoadingEnabled,\n refetchInterval: defaultRefetchInterval,\n staleTime: defaultRefetchInterval,\n placeholderData: keepPreviousData,\n // Resolve a failed chain immediately instead of retrying past the reveal\n // window (retries would pop the chain in late and re-sort the list).\n retry: false,\n }\n })\n )\n }, [accountsWithTokens, isBalanceLoadingEnabled, keyPrefix, sdkClient])\n\n const result = useQueries({\n queries: queryConfig,\n combine: (results) => {\n const now = Date.now()\n\n const hasLoadingQueries = results.some((result) => result.isLoading)\n if (hasLoadingQueries && firstLoadStartRef.current === null) {\n firstLoadStartRef.current = now\n }\n\n const allComplete = results.every(\n (result) => result.isSuccess || result.isError\n )\n\n // Reset the start time when all queries complete\n if (allComplete) {\n firstLoadStartRef.current = null\n }\n\n // Calculate time since first load started\n const timeSinceStart = firstLoadStartRef.current\n ? now - firstLoadStartRef.current\n : 0\n\n // Return results once all queries complete, or once the reveal timeout elapses\n const shouldReturnResults =\n allComplete || timeSinceStart >= balanceRevealTimeout\n\n if (shouldReturnResults) {\n const data: TokenAmount[] = results\n .flatMap((result) => result.data || [])\n .filter((token) => token.amount)\n return {\n data,\n isLoading: !allComplete,\n isError: results.some((result) => result.isError),\n }\n }\n\n return {\n data: undefined,\n isLoading: true,\n isError: false,\n }\n },\n })\n\n return result\n}\n"],"mappings":";;;;;;;AAQA,MAAM,yBAAyB;AAI/B,MAAM,uBAAuB;AAE7B,MAAa,2BACX,oBACA,4BAKG;CACH,MAAM,EAAE,cAAc,gBAAgB;CACtC,MAAM,YAAY,aAAa;CAC/B,MAAM,oBAAoB,OAAsB,IAAI;CAkFpD,OA/Ce,WAAW;EACxB,SAlCkB,cAAc;GAChC,IAAI,CAAC,oBACH,OAAO,CAAC;GAEV,OAAO,OAAO,QAAQ,kBAAkB,CAAC,CAAC,SACvC,CAAC,gBAAgB,iBAChB,OAAO,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,YAAY,YAAY;IACxD,MAAM,UAAU,OAAO,UAAU;IACjC,OAAO;KACL,UAAU;MACR,YAAY,kBAAkB,SAAS;MACvC;MACA;MACA,OAAO;KACT;KACA,SAAS,YAA4C;MACnD,IAAI,CAAC,kBAAkB,CAAC,QACtB,OAAO,CAAC;MAEV,OAAO,MAAM,iBAAiB,WAAW,gBAAgB,MAAM;KACjE;KACA,SAAS;KACT,iBAAiB;KACjB,WAAW;KACX,iBAAiB;KAGjB,OAAO;IACT;GACF,CAAC,CACL;EACF,GAAG;GAAC;GAAoB;GAAyB;GAAW;EAAS,CAGhD;EACnB,UAAU,YAAY;GACpB,MAAM,MAAM,KAAK,IAAI;GAGrB,IAD0B,QAAQ,MAAM,WAAW,OAAO,SACtC,KAAK,kBAAkB,YAAY,MACrD,kBAAkB,UAAU;GAG9B,MAAM,cAAc,QAAQ,OACzB,WAAW,OAAO,aAAa,OAAO,OACzC;GAGA,IAAI,aACF,kBAAkB,UAAU;GAI9B,MAAM,iBAAiB,kBAAkB,UACrC,MAAM,kBAAkB,UACxB;GAMJ,IAFE,eAAe,kBAAkB,sBAMjC,OAAO;IACL,MAJ0B,QACzB,SAAS,WAAW,OAAO,QAAQ,CAAC,CAAC,CAAC,CACtC,QAAQ,UAAU,MAAM,MAEtB;IACH,WAAW,CAAC;IACZ,SAAS,QAAQ,MAAM,WAAW,OAAO,OAAO;GAClD;GAGF,OAAO;IACL,MAAM,KAAA;IACN,WAAW;IACX,SAAS;GACX;EACF;CACF,CAEY;AACd"}
|