@lifi/widget 4.1.0 → 4.3.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/AppDefault.js +14 -0
- package/dist/esm/AppDefault.js.map +1 -1
- package/dist/esm/components/AmountInput/AmountInput.js +2 -1
- package/dist/esm/components/AmountInput/AmountInput.js.map +1 -1
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +4 -2
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.style.js +1 -1
- package/dist/esm/components/AmountInput/AmountInputEndAdornment.style.js.map +1 -1
- package/dist/esm/components/AmountInput/PriceFormHelperText.js +4 -2
- package/dist/esm/components/AmountInput/PriceFormHelperText.js.map +1 -1
- package/dist/esm/components/AmountInputCard/AmountInputCard.style.js +98 -0
- package/dist/esm/components/AmountInputCard/AmountInputCard.style.js.map +1 -0
- package/dist/esm/components/AmountInputCard/AmountInputCardPair.js +25 -0
- package/dist/esm/components/AmountInputCard/AmountInputCardPair.js.map +1 -0
- package/dist/esm/components/AmountInputCard/BalanceDisplay.js +35 -0
- package/dist/esm/components/AmountInputCard/BalanceDisplay.js.map +1 -0
- package/dist/esm/components/AmountInputCard/BalanceDisplay.style.js +11 -0
- package/dist/esm/components/AmountInputCard/BalanceDisplay.style.js.map +1 -0
- package/dist/esm/components/AmountInputCard/FiatValueToggle.js +41 -0
- package/dist/esm/components/AmountInputCard/FiatValueToggle.js.map +1 -0
- package/dist/esm/components/AmountInputCard/PercentageChips.js +80 -0
- package/dist/esm/components/AmountInputCard/PercentageChips.js.map +1 -0
- package/dist/esm/components/AmountInputCard/PercentageChips.style.js +43 -0
- package/dist/esm/components/AmountInputCard/PercentageChips.style.js.map +1 -0
- package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js +137 -0
- package/dist/esm/components/AmountInputCard/ReceiveAmountCard.js.map +1 -0
- package/dist/esm/components/AmountInputCard/SendAmountCard.js +102 -0
- package/dist/esm/components/AmountInputCard/SendAmountCard.js.map +1 -0
- package/dist/esm/components/Avatar/Avatar.js +12 -3
- package/dist/esm/components/Avatar/Avatar.js.map +1 -1
- package/dist/esm/components/Chains/VirtualizedChainList.js +2 -1
- package/dist/esm/components/Chains/VirtualizedChainList.js.map +1 -1
- package/dist/esm/components/Header/HeaderNavigationTabs.js +14 -1
- package/dist/esm/components/Header/HeaderNavigationTabs.js.map +1 -1
- package/dist/esm/components/IconCircle/IconCircle.style.js +1 -1
- package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.js +99 -0
- package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.js.map +1 -0
- package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.style.js +52 -0
- package/dist/esm/components/LimitOrderSettings/LimitOrderSettings.style.js.map +1 -0
- package/dist/esm/components/LimitPriceCard/LimitPriceCard.js +115 -0
- package/dist/esm/components/LimitPriceCard/LimitPriceCard.js.map +1 -0
- package/dist/esm/components/LimitPriceCard/LimitPriceCard.style.js +89 -0
- package/dist/esm/components/LimitPriceCard/LimitPriceCard.style.js.map +1 -0
- package/dist/esm/components/LimitPriceCard/LimitPricePresets.js +91 -0
- package/dist/esm/components/LimitPriceCard/LimitPricePresets.js.map +1 -0
- package/dist/esm/components/RouteCard/RouteProviderCard.js +118 -0
- package/dist/esm/components/RouteCard/RouteProviderCard.js.map +1 -0
- package/dist/esm/components/Routes/LimitOrderRoutes.js +34 -0
- package/dist/esm/components/Routes/LimitOrderRoutes.js.map +1 -0
- package/dist/esm/components/Routes/Routes.js +2 -2
- package/dist/esm/components/Routes/Routes.js.map +1 -1
- package/dist/esm/components/SettingsPanel/SettingsPanel.js +51 -0
- package/dist/esm/components/SettingsPanel/SettingsPanel.js.map +1 -0
- package/dist/esm/components/SettingsPanel/SettingsPanel.style.js +33 -0
- package/dist/esm/components/SettingsPanel/SettingsPanel.style.js.map +1 -0
- package/dist/esm/components/SettingsPanel/utils.js +14 -0
- package/dist/esm/components/SettingsPanel/utils.js.map +1 -0
- package/dist/esm/components/SwapButton/SwapButton.js +50 -0
- package/dist/esm/components/SwapButton/SwapButton.js.map +1 -0
- package/dist/esm/components/SwapButton/SwapButton.style.js +24 -0
- package/dist/esm/components/SwapButton/SwapButton.style.js.map +1 -0
- package/dist/esm/components/TokenPillButton/TokenPillButton.js +52 -0
- package/dist/esm/components/TokenPillButton/TokenPillButton.js.map +1 -0
- package/dist/esm/components/TokenPillButton/TokenPillButton.style.js +39 -0
- package/dist/esm/components/TokenPillButton/TokenPillButton.style.js.map +1 -0
- 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/useChainSearch.js +2 -1
- package/dist/esm/hooks/useChainSearch.js.map +1 -1
- package/dist/esm/hooks/useFilteredByTokenBalances.js +4 -1
- package/dist/esm/hooks/useFilteredByTokenBalances.js.map +1 -1
- package/dist/esm/hooks/useLimitMarketRate.js +24 -0
- package/dist/esm/hooks/useLimitMarketRate.js.map +1 -0
- package/dist/esm/hooks/useLinkedLimitFields.js +49 -0
- package/dist/esm/hooks/useLinkedLimitFields.js.map +1 -0
- package/dist/esm/hooks/useRoutes.js +23 -6
- package/dist/esm/hooks/useRoutes.js.map +1 -1
- package/dist/esm/hooks/useTokens.js +16 -14
- package/dist/esm/hooks/useTokens.js.map +1 -1
- package/dist/esm/hooks/useWideVariant.js +5 -2
- package/dist/esm/hooks/useWideVariant.js.map +1 -1
- package/dist/esm/i18n/en.json +22 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/pages/MainPage/LimitPageContent.js +23 -0
- package/dist/esm/pages/MainPage/LimitPageContent.js.map +1 -0
- package/dist/esm/pages/MainPage/MainPage.js +19 -22
- package/dist/esm/pages/MainPage/MainPage.js.map +1 -1
- package/dist/esm/pages/MainPage/MainPageActions.js +28 -0
- package/dist/esm/pages/MainPage/MainPageActions.js.map +1 -0
- package/dist/esm/pages/MainPage/ReviewButton.js +9 -2
- package/dist/esm/pages/MainPage/ReviewButton.js.map +1 -1
- package/dist/esm/pages/RoutePriorityPage.js +48 -0
- package/dist/esm/pages/RoutePriorityPage.js.map +1 -0
- package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js +2 -2
- package/dist/esm/pages/SettingsPage/BridgeAndExchangeSettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/RoutePrioritySettings.js +12 -27
- package/dist/esm/pages/SettingsPage/RoutePrioritySettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippagePage.js +133 -0
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippagePage.js.map +1 -0
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.js +14 -72
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.style.js +26 -14
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.style.js.map +1 -1
- package/dist/esm/pages/SettingsPage/ThemeSettings.js +4 -0
- package/dist/esm/pages/SettingsPage/ThemeSettings.js.map +1 -1
- package/dist/esm/pages/TransactionPage/TransactionReview.js +4 -1
- package/dist/esm/pages/TransactionPage/TransactionReview.js.map +1 -1
- package/dist/esm/providers/I18nProvider/I18nProvider.js +1 -1
- package/dist/esm/providers/I18nProvider/enResource.d.ts +1 -1
- package/dist/esm/providers/I18nProvider/enResource.js +1 -1
- package/dist/esm/providers/I18nProvider/types.d.ts +2 -2
- package/dist/esm/providers/SDKClientProvider.js +25 -24
- package/dist/esm/providers/SDKClientProvider.js.map +1 -1
- package/dist/esm/providers/WidgetProvider/WidgetProvider.js +22 -21
- package/dist/esm/providers/WidgetProvider/WidgetProvider.js.map +1 -1
- package/dist/esm/stores/form/URLSearchParamsBuilder.js +14 -3
- package/dist/esm/stores/form/URLSearchParamsBuilder.js.map +1 -1
- package/dist/esm/stores/form/createFormStore.js +6 -2
- package/dist/esm/stores/form/createFormStore.js.map +1 -1
- package/dist/esm/stores/form/getDefaultValuesFromQueryString.js +3 -0
- package/dist/esm/stores/form/getDefaultValuesFromQueryString.js.map +1 -1
- package/dist/esm/stores/form/types.d.ts +9 -1
- package/dist/esm/stores/form/types.d.ts.map +1 -1
- package/dist/esm/stores/form/types.js.map +1 -1
- package/dist/esm/stores/form/useClearAmountFields.js +1 -0
- package/dist/esm/stores/form/useClearAmountFields.js.map +1 -1
- package/dist/esm/stores/navigationTabs/useNavigationTabsStore.js +4 -2
- package/dist/esm/stores/navigationTabs/useNavigationTabsStore.js.map +1 -1
- package/dist/esm/stores/navigationTabs/utils.js +38 -8
- package/dist/esm/stores/navigationTabs/utils.js.map +1 -1
- package/dist/esm/types/events.d.ts +10 -1
- package/dist/esm/types/events.d.ts.map +1 -1
- package/dist/esm/types/events.js +2 -0
- package/dist/esm/types/events.js.map +1 -1
- package/dist/esm/types/widget.d.ts +10 -0
- package/dist/esm/types/widget.d.ts.map +1 -1
- package/dist/esm/types/widget.js.map +1 -1
- package/dist/esm/utils/format.d.ts +1 -1
- package/dist/esm/utils/format.d.ts.map +1 -1
- package/dist/esm/utils/format.js +2 -2
- package/dist/esm/utils/format.js.map +1 -1
- package/dist/esm/utils/limitOrder.js +61 -0
- package/dist/esm/utils/limitOrder.js.map +1 -0
- package/dist/esm/utils/navigationRoutes.d.ts +2 -0
- package/dist/esm/utils/navigationRoutes.d.ts.map +1 -1
- package/dist/esm/utils/navigationRoutes.js +6 -0
- package/dist/esm/utils/navigationRoutes.js.map +1 -1
- package/dist/esm/utils/token.js +38 -3
- package/dist/esm/utils/token.js.map +1 -1
- package/package.json +11 -11
- package/src/AppDefault.tsx +16 -0
- package/src/components/AmountInput/AmountInputEndAdornment.style.ts +1 -1
- package/src/components/AmountInput/AmountInputEndAdornment.tsx +5 -2
- package/src/components/AmountInputCard/AmountInputCard.style.tsx +157 -0
- package/src/components/AmountInputCard/AmountInputCardPair.tsx +25 -0
- package/src/components/AmountInputCard/BalanceDisplay.style.tsx +9 -0
- package/src/components/AmountInputCard/BalanceDisplay.tsx +46 -0
- package/src/components/AmountInputCard/FiatValueToggle.tsx +55 -0
- package/src/components/AmountInputCard/PercentageChips.style.tsx +60 -0
- package/src/components/AmountInputCard/PercentageChips.tsx +100 -0
- package/src/components/AmountInputCard/ReceiveAmountCard.tsx +219 -0
- package/src/components/AmountInputCard/SendAmountCard.tsx +179 -0
- package/src/components/Avatar/Avatar.tsx +8 -3
- package/src/components/Header/HeaderNavigationTabs.tsx +19 -2
- package/src/components/LimitOrderSettings/LimitOrderSettings.style.tsx +69 -0
- package/src/components/LimitOrderSettings/LimitOrderSettings.tsx +124 -0
- package/src/components/LimitPriceCard/LimitPriceCard.style.tsx +103 -0
- package/src/components/LimitPriceCard/LimitPriceCard.tsx +153 -0
- package/src/components/LimitPriceCard/LimitPricePresets.tsx +139 -0
- package/src/components/RouteCard/RouteProviderCard.tsx +113 -0
- package/src/components/Routes/LimitOrderRoutes.tsx +64 -0
- package/src/components/Routes/Routes.tsx +3 -2
- package/src/components/SettingsPanel/SettingsPanel.style.tsx +41 -0
- package/src/components/SettingsPanel/SettingsPanel.tsx +73 -0
- package/src/components/SettingsPanel/utils.ts +27 -0
- package/src/components/SwapButton/SwapButton.style.tsx +28 -0
- package/src/components/SwapButton/SwapButton.tsx +71 -0
- package/src/components/TokenPillButton/TokenPillButton.style.tsx +50 -0
- package/src/components/TokenPillButton/TokenPillButton.tsx +81 -0
- package/src/config/version.ts +1 -1
- package/src/hooks/useFilteredByTokenBalances.ts +7 -2
- package/src/hooks/useLimitMarketRate.ts +39 -0
- package/src/hooks/useLinkedLimitFields.ts +74 -0
- package/src/hooks/useRoutes.ts +45 -4
- package/src/hooks/useWideVariant.ts +8 -2
- package/src/pages/MainPage/LimitPageContent.tsx +18 -0
- package/src/pages/MainPage/MainPage.tsx +43 -30
- package/src/pages/MainPage/MainPageActions.tsx +35 -0
- package/src/pages/MainPage/ReviewButton.tsx +13 -1
- package/src/pages/RoutePriorityPage.tsx +55 -0
- package/src/pages/SettingsPage/RoutePrioritySettings.tsx +14 -38
- package/src/pages/SettingsPage/SlippageSettings/SlippagePage.tsx +176 -0
- package/src/pages/SettingsPage/SlippageSettings/SlippageSettings.style.tsx +32 -25
- package/src/pages/SettingsPage/SlippageSettings/SlippageSettings.tsx +14 -128
- package/src/pages/SettingsPage/ThemeSettings.tsx +4 -0
- package/src/stores/form/URLSearchParamsBuilder.tsx +25 -3
- package/src/stores/form/createFormStore.ts +7 -3
- package/src/stores/form/getDefaultValuesFromQueryString.ts +11 -0
- package/src/stores/form/types.ts +14 -1
- package/src/stores/form/useClearAmountFields.ts +1 -0
- package/src/stores/navigationTabs/types.ts +6 -0
- package/src/stores/navigationTabs/useNavigationTabsStore.tsx +8 -3
- package/src/stores/navigationTabs/utils.ts +67 -5
- package/src/types/events.ts +12 -0
- package/src/types/widget.ts +10 -0
- package/src/utils/format.ts +6 -2
- package/src/utils/limitOrder.ts +88 -0
- package/src/utils/navigationRoutes.ts +6 -0
- package/src/utils/token.ts +71 -20
package/dist/esm/utils/token.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { getConfigItemSets, isFormItemAllowed } from "./item.js";
|
|
2
2
|
//#region src/utils/token.ts
|
|
3
3
|
/**
|
|
4
|
+
* Builds per-chain sets of lowercase token addresses from the
|
|
5
|
+
* `tokens.verified` config allowlist.
|
|
6
|
+
*/
|
|
7
|
+
const getVerifiedTokensSets = (configTokens) => {
|
|
8
|
+
if (!configTokens?.verified?.length) return;
|
|
9
|
+
const sets = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const token of configTokens.verified) {
|
|
11
|
+
const chainId = Number(token.chainId);
|
|
12
|
+
let addresses = sets.get(chainId);
|
|
13
|
+
if (!addresses) {
|
|
14
|
+
addresses = /* @__PURE__ */ new Set();
|
|
15
|
+
sets.set(chainId, addresses);
|
|
16
|
+
}
|
|
17
|
+
addresses.add(token.address.toLowerCase());
|
|
18
|
+
}
|
|
19
|
+
return sets;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
4
22
|
* Merges verified tokens with search tokens.
|
|
5
23
|
* Verified tokens take priority - search tokens are only added if they don't already exist.
|
|
6
24
|
*/
|
|
@@ -41,11 +59,28 @@ const filterAllowedTokens = (dataTokens, configTokens, chainsConfig, formType) =
|
|
|
41
59
|
const allChainIds = Array.from(/* @__PURE__ */ new Set([...includedTokens.map((t) => t.chainId), ...Object.keys(dataTokens)])).map((chainId) => Number(chainId));
|
|
42
60
|
const configChainIdsSet = getConfigItemSets(chainsConfig, (chainIds) => new Set(chainIds), formType);
|
|
43
61
|
const allowedChainIds = configChainIdsSet ? allChainIds.filter((chainId) => isFormItemAllowed(chainId, configChainIdsSet, formType)) : allChainIds;
|
|
62
|
+
const verifiedTokensSets = getVerifiedTokensSets(configTokens);
|
|
44
63
|
const allowedTokensByChain = {};
|
|
45
64
|
for (const chainId of allowedChainIds) {
|
|
46
|
-
const
|
|
65
|
+
const chainIncludedTokens = includedTokens.filter((t) => Number(t.chainId) === chainId);
|
|
66
|
+
const includedAddresses = new Set(chainIncludedTokens.map((t) => t.address.toLowerCase()));
|
|
47
67
|
const allowedAddresses = getConfigItemSets(configTokens, (tokens) => new Set(tokens.filter((t) => Number(t.chainId) === chainId).map((t) => t.address.toLowerCase())), formType);
|
|
48
|
-
|
|
68
|
+
const verifiedAddresses = verifiedTokensSets?.get(chainId);
|
|
69
|
+
const chainTokens = [...dataTokens[chainId] ?? [], ...chainIncludedTokens];
|
|
70
|
+
const filtered = [];
|
|
71
|
+
const seenAddresses = /* @__PURE__ */ new Set();
|
|
72
|
+
for (const token of chainTokens) {
|
|
73
|
+
const address = token.address.toLowerCase();
|
|
74
|
+
if (seenAddresses.has(address)) continue;
|
|
75
|
+
seenAddresses.add(address);
|
|
76
|
+
if (!isFormItemAllowed(token, allowedAddresses, formType, (t) => t.address.toLowerCase())) continue;
|
|
77
|
+
if (!token.verified && (includedAddresses.has(address) || verifiedAddresses?.has(address))) filtered.push({
|
|
78
|
+
...token,
|
|
79
|
+
verified: true
|
|
80
|
+
});
|
|
81
|
+
else filtered.push(token);
|
|
82
|
+
}
|
|
83
|
+
allowedTokensByChain[chainId] = filtered;
|
|
49
84
|
}
|
|
50
85
|
return allowedTokensByChain;
|
|
51
86
|
};
|
|
@@ -54,6 +89,6 @@ const getExecutionToToken = (route) => ({
|
|
|
54
89
|
amount: BigInt(route.steps.at(-1)?.execution?.toAmount ?? route.steps.at(-1)?.estimate.toAmount ?? route.toAmount)
|
|
55
90
|
});
|
|
56
91
|
//#endregion
|
|
57
|
-
export { filterAllowedTokens, getExecutionToToken, mergeVerifiedWithSearchTokens, updateTokenInCache };
|
|
92
|
+
export { filterAllowedTokens, getExecutionToToken, getVerifiedTokensSets, mergeVerifiedWithSearchTokens, updateTokenInCache };
|
|
58
93
|
|
|
59
94
|
//# sourceMappingURL=token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.js","names":[],"sources":["../../../src/utils/token.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"token.js","names":[],"sources":["../../../src/utils/token.ts"],"sourcesContent":["import type { BaseToken, RouteExtended, Token, TokenAmount } from '@lifi/sdk'\nimport type { FormType } from '../stores/form/types.js'\nimport type { TokensByChain, TokenWithVerified } from '../types/token.js'\nimport type { WidgetChains, WidgetTokens } from '../types/widget.js'\nimport { getConfigItemSets, isFormItemAllowed } from './item.js'\n\n/**\n * Builds per-chain sets of lowercase token addresses from the\n * `tokens.verified` config allowlist.\n */\nexport const getVerifiedTokensSets = (\n configTokens?: WidgetTokens\n): Map<number, Set<string>> | undefined => {\n if (!configTokens?.verified?.length) {\n return undefined\n }\n const sets = new Map<number, Set<string>>()\n for (const token of configTokens.verified) {\n const chainId = Number(token.chainId)\n let addresses = sets.get(chainId)\n if (!addresses) {\n addresses = new Set()\n sets.set(chainId, addresses)\n }\n addresses.add(token.address.toLowerCase())\n }\n return sets\n}\n\n/**\n * Merges verified tokens with search tokens.\n * Verified tokens take priority - search tokens are only added if they don't already exist.\n */\nexport const mergeVerifiedWithSearchTokens = (\n verifiedTokens?: TokensByChain,\n searchTokens?: TokensByChain\n): TokensByChain | undefined => {\n if (!verifiedTokens) {\n return searchTokens\n }\n if (!searchTokens) {\n return verifiedTokens\n }\n\n const result = { ...verifiedTokens }\n\n for (const [chainId, tokens] of Object.entries(searchTokens)) {\n const chainIdNum = Number(chainId)\n const existingTokens = result[chainIdNum] || []\n const existingAddresses = new Set(\n existingTokens.map((t) => t.address.toLowerCase())\n )\n\n const newTokens = tokens.filter(\n (t) => !existingAddresses.has(t.address.toLowerCase())\n )\n\n if (newTokens.length) {\n result[chainIdNum] = [...existingTokens, ...newTokens]\n }\n }\n\n return result\n}\n\n/**\n * Updates a token in the cache by chainId and address.\n * Returns a new cache object with the token updated, or the original if not found.\n */\nexport const updateTokenInCache = (\n data: TokensByChain | undefined,\n token: Token\n): TokensByChain | undefined => {\n if (!data) {\n return data\n }\n const chainTokens = data[token.chainId]\n if (!chainTokens) {\n return data\n }\n const index = chainTokens.findIndex((t) => t.address === token.address)\n if (index < 0) {\n return data\n }\n return {\n ...data,\n [token.chainId]: chainTokens.map((t, i) =>\n i === index ? { ...t, ...token } : t\n ),\n }\n}\n\nexport const filterAllowedTokens = (\n dataTokens: TokensByChain | undefined,\n configTokens?: WidgetTokens,\n chainsConfig?: WidgetChains,\n formType?: FormType\n): TokensByChain | undefined => {\n if (!dataTokens) {\n return\n }\n\n const includedTokens = configTokens?.include || []\n const allChainIds = Array.from(\n new Set([\n ...includedTokens.map((t) => t.chainId),\n ...Object.keys(dataTokens),\n ])\n ).map((chainId) => Number(chainId))\n\n const configChainIdsSet = getConfigItemSets(\n chainsConfig,\n (chainIds: number[]) => new Set(chainIds),\n formType\n )\n\n const allowedChainIds = configChainIdsSet\n ? allChainIds.filter((chainId) =>\n isFormItemAllowed(chainId, configChainIdsSet, formType)\n )\n : allChainIds\n\n const verifiedTokensSets = getVerifiedTokensSets(configTokens)\n\n const allowedTokensByChain: TokensByChain = {}\n for (const chainId of allowedChainIds) {\n const chainIncludedTokens = includedTokens.filter(\n (t) => Number(t.chainId) === chainId\n )\n const includedAddresses = new Set(\n chainIncludedTokens.map((t) => t.address.toLowerCase())\n )\n\n const allowedAddresses = getConfigItemSets(\n configTokens,\n (tokens: BaseToken[]) =>\n new Set(\n tokens\n .filter((t) => Number(t.chainId) === chainId)\n .map((t) => t.address.toLowerCase())\n ),\n formType\n )\n\n const verifiedAddresses = verifiedTokensSets?.get(chainId)\n\n const chainTokens: TokenWithVerified[] = [\n ...(dataTokens[chainId] ?? []),\n ...chainIncludedTokens,\n ]\n\n const filtered: TokenWithVerified[] = []\n const seenAddresses = new Set<string>()\n for (const token of chainTokens) {\n const address = token.address.toLowerCase()\n // Data tokens come first and win over include duplicates,\n // keeping their extended data\n if (seenAddresses.has(address)) {\n continue\n }\n seenAddresses.add(address)\n if (\n !isFormItemAllowed(token, allowedAddresses, formType, (t) =>\n t.address.toLowerCase()\n )\n ) {\n continue\n }\n // Include and verified-allowlist tokens are explicitly set by the\n // integrator, mark them as verified\n if (\n !token.verified &&\n (includedAddresses.has(address) || verifiedAddresses?.has(address))\n ) {\n filtered.push({ ...token, verified: true })\n } else {\n filtered.push(token)\n }\n }\n\n allowedTokensByChain[chainId] = filtered\n }\n\n return allowedTokensByChain\n}\n\nexport const getExecutionToToken = (route: RouteExtended): TokenAmount => ({\n ...(route.steps.at(-1)?.execution?.toToken ?? route.toToken),\n amount: BigInt(\n route.steps.at(-1)?.execution?.toAmount ??\n route.steps.at(-1)?.estimate.toAmount ??\n route.toAmount\n ),\n})\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/widget",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/esm/index.js",
|
|
@@ -34,22 +34,22 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@emotion/react": "^11.14.0",
|
|
36
36
|
"@emotion/styled": "^11.14.1",
|
|
37
|
-
"@lifi/sdk": "^4.
|
|
38
|
-
"@mui/icons-material": "^9.
|
|
39
|
-
"@mui/material": "^9.
|
|
40
|
-
"@mui/system": "^9.
|
|
41
|
-
"@tanstack/react-router": "^1.170.
|
|
42
|
-
"@tanstack/react-virtual": "^3.14.
|
|
37
|
+
"@lifi/sdk": "^4.1.0",
|
|
38
|
+
"@mui/icons-material": "^9.2.0",
|
|
39
|
+
"@mui/material": "^9.2.0",
|
|
40
|
+
"@mui/system": "^9.2.0",
|
|
41
|
+
"@tanstack/react-router": "^1.170.17",
|
|
42
|
+
"@tanstack/react-virtual": "^3.14.5",
|
|
43
43
|
"eventemitter3": "^5.0.4",
|
|
44
|
-
"i18next": "^26.3.
|
|
44
|
+
"i18next": "^26.3.4",
|
|
45
45
|
"microdiff": "^1.5.0",
|
|
46
|
-
"motion": "^12.
|
|
46
|
+
"motion": "^12.42.2",
|
|
47
47
|
"react-i18next": "^17.0.8",
|
|
48
48
|
"react-intersection-observer": "^10.0.3",
|
|
49
49
|
"react-transition-group": "^4.4.5",
|
|
50
50
|
"zustand": "^5.0.14",
|
|
51
|
-
"@lifi/
|
|
52
|
-
"@lifi/
|
|
51
|
+
"@lifi/wallet-management": "4.1.1",
|
|
52
|
+
"@lifi/widget-provider": "4.2.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@tanstack/react-query": ">=5.90.0",
|
package/src/AppDefault.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import { NotFound } from './components/NotFound.js'
|
|
|
12
12
|
import { ActivitiesPage } from './pages/ActivitiesPage/ActivitiesPage.js'
|
|
13
13
|
import { LanguagesPage } from './pages/LanguagesPage.js'
|
|
14
14
|
import { MainPage } from './pages/MainPage/MainPage.js'
|
|
15
|
+
import { RoutePriorityPage } from './pages/RoutePriorityPage.js'
|
|
15
16
|
import { RoutesPage } from './pages/RoutesPage/RoutesPage.js'
|
|
16
17
|
import { SelectChainPage } from './pages/SelectChainPage/SelectChainPage.js'
|
|
17
18
|
import { SelectEnabledToolsPage } from './pages/SelectEnabledToolsPage.js'
|
|
@@ -22,6 +23,7 @@ import { RecentWalletsPage } from './pages/SendToWallet/RecentWalletsPage.js'
|
|
|
22
23
|
import { SendToConfiguredWalletPage } from './pages/SendToWallet/SendToConfiguredWalletPage.js'
|
|
23
24
|
import { SendToWalletPage } from './pages/SendToWallet/SendToWalletPage.js'
|
|
24
25
|
import { SettingsPage } from './pages/SettingsPage/SettingsPage.js'
|
|
26
|
+
import { SlippagePage } from './pages/SettingsPage/SlippageSettings/SlippagePage.js'
|
|
25
27
|
import { TransactionDetailsPage } from './pages/TransactionDetailsPage/TransactionDetailsPage.js'
|
|
26
28
|
import { TransactionPage } from './pages/TransactionPage/TransactionPage.js'
|
|
27
29
|
import { navigationRoutes } from './utils/navigationRoutes.js'
|
|
@@ -66,6 +68,18 @@ const settingsLanguagesRoute = createRoute({
|
|
|
66
68
|
component: LanguagesPage,
|
|
67
69
|
})
|
|
68
70
|
|
|
71
|
+
const settingsRoutePriorityRoute = createRoute({
|
|
72
|
+
getParentRoute: () => settingsLayoutRoute,
|
|
73
|
+
path: navigationRoutes.routePriority,
|
|
74
|
+
component: RoutePriorityPage,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const settingsSlippageRoute = createRoute({
|
|
78
|
+
getParentRoute: () => settingsLayoutRoute,
|
|
79
|
+
path: navigationRoutes.slippage,
|
|
80
|
+
component: SlippagePage,
|
|
81
|
+
})
|
|
82
|
+
|
|
69
83
|
const fromTokenLayoutRoute = createRoute({
|
|
70
84
|
getParentRoute: () => rootRoute,
|
|
71
85
|
path: navigationRoutes.fromToken,
|
|
@@ -214,6 +228,8 @@ const routeTree = rootRoute.addChildren([
|
|
|
214
228
|
settingsLayoutRoute.addChildren([
|
|
215
229
|
settingsIndexRoute,
|
|
216
230
|
settingsLanguagesRoute,
|
|
231
|
+
settingsRoutePriorityRoute,
|
|
232
|
+
settingsSlippageRoute,
|
|
217
233
|
settingsBridgesRoute,
|
|
218
234
|
settingsExchangesRoute,
|
|
219
235
|
]),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatUnits } from '@lifi/sdk'
|
|
2
|
+
import { useAccount } from '@lifi/wallet-management'
|
|
2
3
|
import type React from 'react'
|
|
3
4
|
import { type JSX, memo } from 'react'
|
|
4
5
|
import { useTranslation } from 'react-i18next'
|
|
@@ -25,6 +26,9 @@ export const AmountInputEndAdornment: React.NamedExoticComponent<FormTypeProps>
|
|
|
25
26
|
FormKeyHelper.getTokenKey(formType)
|
|
26
27
|
)
|
|
27
28
|
|
|
29
|
+
const chain = getChainById(chainId)
|
|
30
|
+
const { account } = useAccount({ chainType: chain?.chainType })
|
|
31
|
+
|
|
28
32
|
// We get gas recommendations for the source chain to make sure that after pressing the Max button
|
|
29
33
|
// the user will have enough funds remaining to cover gas costs
|
|
30
34
|
const { data } = useGasRecommendation(chainId)
|
|
@@ -35,7 +39,6 @@ export const AmountInputEndAdornment: React.NamedExoticComponent<FormTypeProps>
|
|
|
35
39
|
if (!token?.amount) {
|
|
36
40
|
return 0n
|
|
37
41
|
}
|
|
38
|
-
const chain = getChainById(chainId)
|
|
39
42
|
let maxAmount = token.amount
|
|
40
43
|
if (chain?.nativeToken.address === tokenAddress && data?.recommended) {
|
|
41
44
|
const recommendedAmount = BigInt(data.recommended.amount)
|
|
@@ -73,7 +76,7 @@ export const AmountInputEndAdornment: React.NamedExoticComponent<FormTypeProps>
|
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
if (formType !== 'from' || !token) {
|
|
79
|
+
if (formType !== 'from' || !token || !account?.isConnected) {
|
|
77
80
|
return null
|
|
78
81
|
}
|
|
79
82
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Box,
|
|
3
|
+
ButtonBase,
|
|
4
|
+
InputBase,
|
|
5
|
+
inputBaseClasses,
|
|
6
|
+
styled,
|
|
7
|
+
Typography,
|
|
8
|
+
} from '@mui/material'
|
|
9
|
+
import type React from 'react'
|
|
10
|
+
import type { FormType } from '../../stores/form/types.js'
|
|
11
|
+
import { InputCard } from '../Card/InputCard.js'
|
|
12
|
+
|
|
13
|
+
export const maxInputFontSize = 30
|
|
14
|
+
export const minInputFontSize = 20
|
|
15
|
+
export const amountHeight = 32
|
|
16
|
+
export const footerFontSize = 12
|
|
17
|
+
|
|
18
|
+
export const AmountCard: React.FC<
|
|
19
|
+
React.ComponentProps<typeof InputCard> & {
|
|
20
|
+
formType?: FormType
|
|
21
|
+
mask?: boolean
|
|
22
|
+
}
|
|
23
|
+
> = styled(InputCard, {
|
|
24
|
+
shouldForwardProp: (prop) => !['formType', 'mask'].includes(prop as string),
|
|
25
|
+
})<{ formType?: FormType; mask?: boolean }>(
|
|
26
|
+
({ theme, formType, mask = true }) => {
|
|
27
|
+
const cardVariant = theme.components?.MuiCard?.defaultProps?.variant
|
|
28
|
+
// Notch faces the swap button between the stacked cards: bottom edge for the
|
|
29
|
+
// top (send) card, top edge for the bottom (receive) card.
|
|
30
|
+
const vertical = formType === 'to' ? '-4px' : 'calc(100% + 4px)'
|
|
31
|
+
return {
|
|
32
|
+
display: 'flex',
|
|
33
|
+
flexDirection: 'column',
|
|
34
|
+
gap: theme.spacing(1.5),
|
|
35
|
+
padding: theme.spacing(2),
|
|
36
|
+
...(cardVariant !== 'outlined' &&
|
|
37
|
+
mask && {
|
|
38
|
+
mask: `radial-gradient(circle 22px at 50% ${vertical}, #fff0 96%, #fff) 100% 100% / 100% 100% no-repeat`,
|
|
39
|
+
}),
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
export const CardHeaderRow: React.FC<React.ComponentProps<typeof Box>> = styled(
|
|
45
|
+
Box
|
|
46
|
+
)(({ theme }) => ({
|
|
47
|
+
display: 'flex',
|
|
48
|
+
justifyContent: 'space-between',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
padding: 0,
|
|
51
|
+
height: theme.spacing(2),
|
|
52
|
+
}))
|
|
53
|
+
|
|
54
|
+
export const CardBodyRow: React.FC<React.ComponentProps<typeof Box>> = styled(
|
|
55
|
+
Box
|
|
56
|
+
)(({ theme }) => ({
|
|
57
|
+
display: 'flex',
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
gap: theme.spacing(2),
|
|
60
|
+
}))
|
|
61
|
+
|
|
62
|
+
export const CardFooterRow: React.FC<React.ComponentProps<typeof Box>> = styled(
|
|
63
|
+
Box
|
|
64
|
+
)(({ theme }) => ({
|
|
65
|
+
display: 'flex',
|
|
66
|
+
justifyContent: 'space-between',
|
|
67
|
+
alignItems: 'center',
|
|
68
|
+
height: theme.spacing(2),
|
|
69
|
+
}))
|
|
70
|
+
|
|
71
|
+
export const LargeInput: React.FC<React.ComponentProps<typeof InputBase>> =
|
|
72
|
+
styled(InputBase)(({ theme }) => ({
|
|
73
|
+
fontSize: maxInputFontSize,
|
|
74
|
+
fontWeight: 700,
|
|
75
|
+
lineHeight: 1.4,
|
|
76
|
+
height: amountHeight,
|
|
77
|
+
flex: 1,
|
|
78
|
+
minWidth: 0,
|
|
79
|
+
boxShadow: 'none',
|
|
80
|
+
[`.${inputBaseClasses.input}`]: {
|
|
81
|
+
height: amountHeight,
|
|
82
|
+
padding: 0,
|
|
83
|
+
},
|
|
84
|
+
[`.${inputBaseClasses.input}::placeholder`]: {
|
|
85
|
+
color: theme.vars.palette.text.primary,
|
|
86
|
+
opacity: 0.5,
|
|
87
|
+
},
|
|
88
|
+
'& input[type="number"]::-webkit-outer-spin-button, & input[type="number"]::-webkit-inner-spin-button':
|
|
89
|
+
{
|
|
90
|
+
WebkitAppearance: 'none',
|
|
91
|
+
margin: 0,
|
|
92
|
+
},
|
|
93
|
+
'& input[type="number"]': {
|
|
94
|
+
MozAppearance: 'textfield',
|
|
95
|
+
},
|
|
96
|
+
[`&.${inputBaseClasses.disabled}`]: {
|
|
97
|
+
color: 'inherit',
|
|
98
|
+
},
|
|
99
|
+
[`.${inputBaseClasses.input}.${inputBaseClasses.disabled}`]: {
|
|
100
|
+
WebkitTextFillColor: 'unset',
|
|
101
|
+
},
|
|
102
|
+
}))
|
|
103
|
+
|
|
104
|
+
export const AmountDisplay: React.FC<React.ComponentProps<typeof Typography>> =
|
|
105
|
+
styled(Typography)(() => ({
|
|
106
|
+
fontSize: maxInputFontSize,
|
|
107
|
+
fontWeight: 700,
|
|
108
|
+
lineHeight: 1.4,
|
|
109
|
+
height: amountHeight,
|
|
110
|
+
display: 'flex',
|
|
111
|
+
alignItems: 'center',
|
|
112
|
+
flex: 1,
|
|
113
|
+
minWidth: 0,
|
|
114
|
+
overflow: 'visible',
|
|
115
|
+
whiteSpace: 'nowrap',
|
|
116
|
+
}))
|
|
117
|
+
|
|
118
|
+
export const FooterText: React.FC<React.ComponentProps<typeof Typography>> =
|
|
119
|
+
styled(Typography)(({ theme }) => ({
|
|
120
|
+
fontSize: footerFontSize,
|
|
121
|
+
fontWeight: 500,
|
|
122
|
+
lineHeight: 1,
|
|
123
|
+
color: theme.vars.palette.text.secondary,
|
|
124
|
+
}))
|
|
125
|
+
|
|
126
|
+
export const CardContainer: React.FC<React.ComponentProps<typeof Box>> = styled(
|
|
127
|
+
Box
|
|
128
|
+
)(() => ({
|
|
129
|
+
display: 'flex',
|
|
130
|
+
flexDirection: 'column',
|
|
131
|
+
position: 'relative',
|
|
132
|
+
}))
|
|
133
|
+
|
|
134
|
+
export const ToggleButton: React.FC<
|
|
135
|
+
React.ComponentProps<typeof ButtonBase> & { clickable?: boolean }
|
|
136
|
+
> = styled(ButtonBase, {
|
|
137
|
+
shouldForwardProp: (prop) => prop !== 'clickable',
|
|
138
|
+
})<{ clickable?: boolean }>(({ theme, clickable }) => ({
|
|
139
|
+
display: 'flex',
|
|
140
|
+
alignItems: 'center',
|
|
141
|
+
gap: theme.spacing(0.25),
|
|
142
|
+
borderRadius: theme.vars.shape.borderRadiusSecondary,
|
|
143
|
+
padding: theme.spacing(0.25, 0.5, 0.25, 0.75),
|
|
144
|
+
marginLeft: theme.spacing(-0.75),
|
|
145
|
+
backgroundColor: 'transparent',
|
|
146
|
+
...(clickable
|
|
147
|
+
? {
|
|
148
|
+
cursor: 'pointer',
|
|
149
|
+
'&:hover': {
|
|
150
|
+
backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
: {
|
|
154
|
+
cursor: 'default',
|
|
155
|
+
pointerEvents: 'none',
|
|
156
|
+
}),
|
|
157
|
+
}))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { BoxProps } from '@mui/material'
|
|
2
|
+
import type React from 'react'
|
|
3
|
+
import type { JSX } from 'react'
|
|
4
|
+
import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'
|
|
5
|
+
import { LimitPriceCard } from '../LimitPriceCard/LimitPriceCard.js'
|
|
6
|
+
import { SwapButton } from '../SwapButton/SwapButton.js'
|
|
7
|
+
import { CardContainer } from './AmountInputCard.style.js'
|
|
8
|
+
import { ReceiveAmountCard } from './ReceiveAmountCard.js'
|
|
9
|
+
import { SendAmountCard } from './SendAmountCard.js'
|
|
10
|
+
|
|
11
|
+
export const AmountInputCardPair: React.FC<BoxProps> = (props): JSX.Element => {
|
|
12
|
+
// Refuel's destination is fixed to native gas, so reversing from/to is
|
|
13
|
+
// meaningless — hide the swap button (and the notch mask it sits in).
|
|
14
|
+
const { mode } = useWidgetConfig()
|
|
15
|
+
const showSwapButton = mode !== 'refuel'
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<CardContainer {...props}>
|
|
19
|
+
{mode === 'limit' ? <LimitPriceCard sx={{ marginBottom: 1 }} /> : null}
|
|
20
|
+
<SendAmountCard mask={showSwapButton} />
|
|
21
|
+
<SwapButton sx={{ visibility: showSwapButton ? 'visible' : 'hidden' }} />
|
|
22
|
+
<ReceiveAmountCard mask={showSwapButton} />
|
|
23
|
+
</CardContainer>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Box, styled } from '@mui/material'
|
|
2
|
+
import type React from 'react'
|
|
3
|
+
|
|
4
|
+
export const BalanceContainer: React.FC<React.ComponentProps<typeof Box>> =
|
|
5
|
+
styled(Box)(({ theme }) => ({
|
|
6
|
+
display: 'flex',
|
|
7
|
+
alignItems: 'center',
|
|
8
|
+
gap: theme.spacing(0.5),
|
|
9
|
+
}))
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import AccountBalanceWalletOutlinedIcon from '@mui/icons-material/AccountBalanceWalletOutlined'
|
|
2
|
+
import { Skeleton } from '@mui/material'
|
|
3
|
+
import { type JSX, memo } from 'react'
|
|
4
|
+
import { useTranslation } from 'react-i18next'
|
|
5
|
+
import { useTokenAddressBalance } from '../../hooks/useTokenAddressBalance.js'
|
|
6
|
+
import type { FormTypeProps } from '../../stores/form/types.js'
|
|
7
|
+
import { FormKeyHelper } from '../../stores/form/types.js'
|
|
8
|
+
import { useFieldValues } from '../../stores/form/useFieldValues.js'
|
|
9
|
+
import { formatTokenAmount } from '../../utils/format.js'
|
|
10
|
+
import { FooterText, footerFontSize } from './AmountInputCard.style.js'
|
|
11
|
+
import { BalanceContainer } from './BalanceDisplay.style.js'
|
|
12
|
+
|
|
13
|
+
export const BalanceDisplay: React.NamedExoticComponent<FormTypeProps> = memo(
|
|
14
|
+
({ formType }: FormTypeProps): JSX.Element | null => {
|
|
15
|
+
const { t } = useTranslation()
|
|
16
|
+
const [chainId, tokenAddress] = useFieldValues(
|
|
17
|
+
FormKeyHelper.getChainKey(formType),
|
|
18
|
+
FormKeyHelper.getTokenKey(formType)
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const { token, isLoading } = useTokenAddressBalance(chainId, tokenAddress)
|
|
22
|
+
|
|
23
|
+
if (isLoading && tokenAddress) {
|
|
24
|
+
return (
|
|
25
|
+
<Skeleton variant="text" width={72} sx={{ fontSize: footerFontSize }} />
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!token?.amount) {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const tokenAmount = formatTokenAmount(token.amount, token.decimals)
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<BalanceContainer>
|
|
37
|
+
<FooterText title={tokenAmount}>
|
|
38
|
+
{t('format.tokenAmount', { value: tokenAmount })}
|
|
39
|
+
</FooterText>
|
|
40
|
+
<AccountBalanceWalletOutlinedIcon
|
|
41
|
+
sx={{ fontSize: 16, color: 'text.secondary' }}
|
|
42
|
+
/>
|
|
43
|
+
</BalanceContainer>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import SwapVertIcon from '@mui/icons-material/SwapVert'
|
|
2
|
+
import { type JSX, memo } from 'react'
|
|
3
|
+
import { useTranslation } from 'react-i18next'
|
|
4
|
+
import { useToken } from '../../hooks/useToken.js'
|
|
5
|
+
import type { FormTypeProps } from '../../stores/form/types.js'
|
|
6
|
+
import { FormKeyHelper } from '../../stores/form/types.js'
|
|
7
|
+
import { useFieldValues } from '../../stores/form/useFieldValues.js'
|
|
8
|
+
import { useInputModeStore } from '../../stores/inputMode/useInputModeStore.js'
|
|
9
|
+
import { formatTokenPrice } from '../../utils/format.js'
|
|
10
|
+
import { FooterText, ToggleButton } from './AmountInputCard.style.js'
|
|
11
|
+
|
|
12
|
+
export const FiatValueToggle: React.NamedExoticComponent<FormTypeProps> = memo(
|
|
13
|
+
({ formType }: FormTypeProps): JSX.Element => {
|
|
14
|
+
const { t } = useTranslation()
|
|
15
|
+
const [chainId, tokenAddress, amount] = useFieldValues(
|
|
16
|
+
FormKeyHelper.getChainKey(formType),
|
|
17
|
+
FormKeyHelper.getTokenKey(formType),
|
|
18
|
+
FormKeyHelper.getAmountKey(formType)
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const { token } = useToken(chainId, tokenAddress)
|
|
22
|
+
const { inputMode, toggleInputMode } = useInputModeStore()
|
|
23
|
+
const currentInputMode = inputMode[formType]
|
|
24
|
+
|
|
25
|
+
const handleToggle = (e: React.MouseEvent): void => {
|
|
26
|
+
e.stopPropagation()
|
|
27
|
+
toggleInputMode(formType)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const canToggle = !!token?.priceUSD
|
|
31
|
+
|
|
32
|
+
const displayValue =
|
|
33
|
+
currentInputMode === 'amount'
|
|
34
|
+
? t('format.currency', {
|
|
35
|
+
value: formatTokenPrice(amount, token?.priceUSD, token?.decimals),
|
|
36
|
+
})
|
|
37
|
+
: t('format.tokenAmount', { value: amount || '0' })
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<ToggleButton
|
|
41
|
+
clickable={canToggle}
|
|
42
|
+
onClick={canToggle ? handleToggle : undefined}
|
|
43
|
+
aria-label={canToggle ? 'Toggle fiat value' : undefined}
|
|
44
|
+
>
|
|
45
|
+
<FooterText>{displayValue}</FooterText>
|
|
46
|
+
{currentInputMode === 'price' && token?.symbol ? (
|
|
47
|
+
<FooterText>{token.symbol}</FooterText>
|
|
48
|
+
) : null}
|
|
49
|
+
{canToggle ? (
|
|
50
|
+
<SwapVertIcon sx={{ fontSize: 14, color: 'text.secondary' }} />
|
|
51
|
+
) : null}
|
|
52
|
+
</ToggleButton>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Box, Button, styled } from '@mui/material'
|
|
2
|
+
import { cardClasses } from '@mui/material/Card'
|
|
3
|
+
import type React from 'react'
|
|
4
|
+
|
|
5
|
+
const chipCount = 4
|
|
6
|
+
const staggerStepMs = 25
|
|
7
|
+
|
|
8
|
+
const revealStagger = Object.fromEntries(
|
|
9
|
+
Array.from({ length: chipCount }, (_, index) => [
|
|
10
|
+
`&[data-delay="${index}"]`,
|
|
11
|
+
{
|
|
12
|
+
[`.${cardClasses.root}:hover &`]: {
|
|
13
|
+
opacity: 1,
|
|
14
|
+
transform: 'scale(1) translateX(0)',
|
|
15
|
+
pointerEvents: 'auto',
|
|
16
|
+
transitionDelay: `${(chipCount - 1 - index) * staggerStepMs}ms`,
|
|
17
|
+
},
|
|
18
|
+
[`.${cardClasses.root}:not(:hover) &`]: {
|
|
19
|
+
transitionDelay: `${index * staggerStepMs}ms`,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
])
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
export const ChipContainer: React.FC<React.ComponentProps<typeof Box>> = styled(
|
|
26
|
+
Box
|
|
27
|
+
)(({ theme }) => ({
|
|
28
|
+
display: 'flex',
|
|
29
|
+
gap: theme.spacing(0.5),
|
|
30
|
+
}))
|
|
31
|
+
|
|
32
|
+
export const Chip: React.FC<React.ComponentProps<typeof Button>> = styled(
|
|
33
|
+
Button
|
|
34
|
+
)(({ theme }) => ({
|
|
35
|
+
minWidth: 0,
|
|
36
|
+
padding: theme.spacing(0.5, 1.5),
|
|
37
|
+
fontSize: 12,
|
|
38
|
+
fontWeight: 700,
|
|
39
|
+
lineHeight: 1.3334,
|
|
40
|
+
backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 4%, transparent)`,
|
|
41
|
+
color: theme.vars.palette.text.primary,
|
|
42
|
+
transition:
|
|
43
|
+
'opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 200ms cubic-bezier(0.4, 0, 0.2, 1), background-color 200ms ease',
|
|
44
|
+
'&:hover': {
|
|
45
|
+
backgroundColor: `color-mix(in srgb, ${theme.vars.palette.common.onBackground} 8%, transparent)`,
|
|
46
|
+
},
|
|
47
|
+
// Reveal-on-hover — only on devices that support hover. On touch there is no
|
|
48
|
+
// hover, so the chips stay permanently visible (the default above) instead of
|
|
49
|
+
// becoming an unreachable dead row.
|
|
50
|
+
'@media (hover: hover)': {
|
|
51
|
+
opacity: 0,
|
|
52
|
+
transform: 'scale(0.85) translateX(10px)',
|
|
53
|
+
pointerEvents: 'none',
|
|
54
|
+
...revealStagger,
|
|
55
|
+
'@media (prefers-reduced-motion: reduce)': {
|
|
56
|
+
transform: 'none !important',
|
|
57
|
+
transitionDelay: '0ms !important',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
}))
|