@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
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
DefaultUI,
|
|
2
3
|
InternalNavigationTabKey,
|
|
3
4
|
ModeOptions,
|
|
4
5
|
NavigationTabKey,
|
|
6
|
+
RequiredUIConfig,
|
|
5
7
|
SplitMode,
|
|
6
8
|
SplitNavigationTabKey,
|
|
7
9
|
WidgetConfig,
|
|
@@ -13,26 +15,56 @@ import type { NavigationTab } from './types.js'
|
|
|
13
15
|
|
|
14
16
|
/** Configured navigation tabs by key. Labels are resolved from the key by a hook. */
|
|
15
17
|
const navigationTabsByKey: Record<InternalNavigationTabKey, NavigationTab> = {
|
|
16
|
-
default: {
|
|
18
|
+
default: {
|
|
19
|
+
key: 'default',
|
|
20
|
+
variant: 'wide',
|
|
21
|
+
mode: 'default',
|
|
22
|
+
defaultUI: {
|
|
23
|
+
layout: 'cards',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
17
26
|
private: {
|
|
18
27
|
key: 'private',
|
|
19
28
|
variant: 'compact',
|
|
20
|
-
mode: '
|
|
21
|
-
|
|
29
|
+
mode: 'default',
|
|
30
|
+
defaultUI: {
|
|
31
|
+
layout: 'cards',
|
|
32
|
+
},
|
|
33
|
+
requiredUI: { toAddress: true },
|
|
34
|
+
},
|
|
35
|
+
refuel: {
|
|
36
|
+
key: 'refuel',
|
|
37
|
+
variant: 'wide',
|
|
38
|
+
mode: 'refuel',
|
|
39
|
+
defaultUI: {
|
|
40
|
+
layout: 'cards',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
limit: {
|
|
44
|
+
key: 'limit',
|
|
45
|
+
variant: 'compact',
|
|
46
|
+
mode: 'limit',
|
|
47
|
+
defaultUI: {
|
|
48
|
+
layout: 'cards',
|
|
49
|
+
},
|
|
22
50
|
},
|
|
23
|
-
refuel: { key: 'refuel', variant: 'wide', mode: 'refuel' },
|
|
24
|
-
limit: { key: 'limit', variant: 'compact', mode: 'limit' },
|
|
25
51
|
'swap-advanced': {
|
|
26
52
|
key: 'swap-advanced',
|
|
27
53
|
variant: 'wide',
|
|
28
54
|
mode: 'split',
|
|
29
55
|
modeOptions: { split: 'swap' },
|
|
56
|
+
defaultUI: {
|
|
57
|
+
layout: 'cards',
|
|
58
|
+
},
|
|
30
59
|
},
|
|
31
60
|
'bridge-advanced': {
|
|
32
61
|
key: 'bridge-advanced',
|
|
33
62
|
variant: 'wide',
|
|
34
63
|
mode: 'split',
|
|
35
64
|
modeOptions: { split: 'bridge' },
|
|
65
|
+
defaultUI: {
|
|
66
|
+
layout: 'cards',
|
|
67
|
+
},
|
|
36
68
|
},
|
|
37
69
|
}
|
|
38
70
|
|
|
@@ -132,3 +164,33 @@ export const getTabModeOptions = (
|
|
|
132
164
|
const tab = key ? tabByKey[key] : undefined
|
|
133
165
|
return tab?.modeOptions ?? config.modeOptions
|
|
134
166
|
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Default UI for a tab, layered over the widget config's `defaultUI` so the
|
|
170
|
+
* tab overrides only the fields it sets and inherits the rest.
|
|
171
|
+
*/
|
|
172
|
+
export const getTabDefaultUI = (
|
|
173
|
+
config: WidgetConfig,
|
|
174
|
+
key?: NavigationTabKey
|
|
175
|
+
): DefaultUI | undefined => {
|
|
176
|
+
const tab = key ? tabByKey[key] : undefined
|
|
177
|
+
if (!tab?.defaultUI) {
|
|
178
|
+
return config.defaultUI
|
|
179
|
+
}
|
|
180
|
+
return { ...config.defaultUI, ...tab.defaultUI }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Required UI for a tab, layered over the widget config's `requiredUI` so the
|
|
185
|
+
* tab overrides only the fields it sets and inherits the rest.
|
|
186
|
+
*/
|
|
187
|
+
export const getTabRequiredUI = (
|
|
188
|
+
config: WidgetConfig,
|
|
189
|
+
key?: NavigationTabKey
|
|
190
|
+
): RequiredUIConfig | undefined => {
|
|
191
|
+
const tab = key ? tabByKey[key] : undefined
|
|
192
|
+
if (!tab?.requiredUI) {
|
|
193
|
+
return config.requiredUI
|
|
194
|
+
}
|
|
195
|
+
return { ...config.requiredUI, ...tab.requiredUI }
|
|
196
|
+
}
|
package/src/types/events.ts
CHANGED
|
@@ -3,14 +3,17 @@ import type { DefaultValues } from '../stores/form/types.js'
|
|
|
3
3
|
import type { SettingsProps } from '../stores/settings/types.js'
|
|
4
4
|
import type { NavigationRouteType } from '../utils/navigationRoutes.js'
|
|
5
5
|
import type { TokenAmount } from './token.js'
|
|
6
|
+
import type { Appearance, NavigationTabKey } from './widget.js'
|
|
6
7
|
|
|
7
8
|
export enum WidgetEvent {
|
|
9
|
+
AppearanceChanged = 'appearanceChanged',
|
|
8
10
|
AvailableRoutes = 'availableRoutes',
|
|
9
11
|
ChainPinned = 'chainPinned',
|
|
10
12
|
ContactSupport = 'contactSupport',
|
|
11
13
|
DestinationChainTokenSelected = 'destinationChainTokenSelected',
|
|
12
14
|
FormFieldChanged = 'formFieldChanged',
|
|
13
15
|
LowAddressActivityConfirmed = 'lowAddressActivityConfirmed',
|
|
16
|
+
NavigationTabChanged = 'navigationTabChanged',
|
|
14
17
|
PageEntered = 'pageEntered',
|
|
15
18
|
RouteExecutionCompleted = 'routeExecutionCompleted',
|
|
16
19
|
RouteExecutionFailed = 'routeExecutionFailed',
|
|
@@ -26,12 +29,14 @@ export enum WidgetEvent {
|
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
export type WidgetEvents = {
|
|
32
|
+
appearanceChanged: (data: Appearance) => void
|
|
29
33
|
availableRoutes: (data: Route[]) => void
|
|
30
34
|
chainPinned: (data: ChainPinned) => void
|
|
31
35
|
contactSupport: (data: ContactSupport) => void
|
|
32
36
|
destinationChainTokenSelected: (data: ChainTokenSelected) => void
|
|
33
37
|
formFieldChanged: (data: FormFieldChanged) => void
|
|
34
38
|
lowAddressActivityConfirmed: (data: LowAddressActivityConfirmed) => void
|
|
39
|
+
navigationTabChanged: (data: NavigationTabChanged) => void
|
|
35
40
|
pageEntered: (data: NavigationRouteType) => void
|
|
36
41
|
routeExecutionCompleted: (data: Route) => void
|
|
37
42
|
routeExecutionFailed: (data: RouteExecutionUpdate) => void
|
|
@@ -112,3 +117,10 @@ export type LowAddressActivityConfirmed = {
|
|
|
112
117
|
address: string
|
|
113
118
|
chainId: number
|
|
114
119
|
}
|
|
120
|
+
|
|
121
|
+
export type NavigationTabChanged = {
|
|
122
|
+
/** Key of the now-active tab. */
|
|
123
|
+
tab: NavigationTabKey
|
|
124
|
+
/** Key of the previously active tab, or `undefined` on first render. */
|
|
125
|
+
previousTab?: NavigationTabKey
|
|
126
|
+
}
|
package/src/types/widget.ts
CHANGED
|
@@ -173,6 +173,15 @@ export interface RequiredUIConfig {
|
|
|
173
173
|
export type DefaultUI = {
|
|
174
174
|
transactionDetailsExpanded?: boolean
|
|
175
175
|
navigationHeaderTitleNoWrap?: boolean
|
|
176
|
+
/**
|
|
177
|
+
* Layout for the main form.
|
|
178
|
+
* - `'default'`: the chain/token selectors plus single amount input.
|
|
179
|
+
* - `'cards'`: the redesigned card-based layout — stacked Send/Receive amount
|
|
180
|
+
* cards (`AmountInputCardPair`) with inline token pill selectors and a swap
|
|
181
|
+
* button.
|
|
182
|
+
* @default 'default'
|
|
183
|
+
*/
|
|
184
|
+
layout?: 'default' | 'cards'
|
|
176
185
|
}
|
|
177
186
|
|
|
178
187
|
export interface WidgetWalletConfig {
|
|
@@ -293,6 +302,7 @@ export type WidgetTokens = {
|
|
|
293
302
|
featured?: StaticToken[]
|
|
294
303
|
include?: Token[]
|
|
295
304
|
popular?: StaticToken[]
|
|
305
|
+
verified?: BaseToken[]
|
|
296
306
|
} & AllowDenyItems<BaseToken>
|
|
297
307
|
|
|
298
308
|
export type WidgetLanguages = {
|
package/src/utils/format.ts
CHANGED
|
@@ -175,7 +175,11 @@ const units = [
|
|
|
175
175
|
['second', 1],
|
|
176
176
|
] as const
|
|
177
177
|
|
|
178
|
-
export function formatDuration(
|
|
178
|
+
export function formatDuration(
|
|
179
|
+
seconds: number,
|
|
180
|
+
locale: string,
|
|
181
|
+
unitDisplay: Intl.NumberFormatOptions['unitDisplay'] = 'narrow'
|
|
182
|
+
): string {
|
|
179
183
|
const match = units.find(([, v]) => seconds >= v)
|
|
180
184
|
const amount = match ? Math.floor(seconds / match[1]) : 0
|
|
181
185
|
const unit = match?.[0] ?? 'second'
|
|
@@ -183,7 +187,7 @@ export function formatDuration(seconds: number, locale: string): string {
|
|
|
183
187
|
return amount.toLocaleString(locale, {
|
|
184
188
|
style: 'unit',
|
|
185
189
|
unit,
|
|
186
|
-
unitDisplay
|
|
190
|
+
unitDisplay,
|
|
187
191
|
})
|
|
188
192
|
}
|
|
189
193
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { formatInputAmount } from './format.js'
|
|
2
|
+
|
|
3
|
+
/** Default order validity: 1 day, expressed as a duration in seconds. */
|
|
4
|
+
export const DEFAULT_VALID_UNTIL_SECONDS: number = 24 * 60 * 60
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* High-precision formatter for derived limit-order values. Mirrors the
|
|
8
|
+
* approach used by `priceToTokenAmount` — these are display-level derivations;
|
|
9
|
+
* the route request re-parses amounts via `parseUnits`.
|
|
10
|
+
*/
|
|
11
|
+
const preciseFormatter = new Intl.NumberFormat('en', {
|
|
12
|
+
notation: 'standard',
|
|
13
|
+
roundingPriority: 'morePrecision',
|
|
14
|
+
maximumSignificantDigits: 20,
|
|
15
|
+
maximumFractionDigits: 20,
|
|
16
|
+
useGrouping: false,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
function parsePositive(value?: string): number | undefined {
|
|
20
|
+
if (!value) {
|
|
21
|
+
return undefined
|
|
22
|
+
}
|
|
23
|
+
const parsed = Number.parseFloat(value)
|
|
24
|
+
if (Number.isNaN(parsed) || parsed <= 0) {
|
|
25
|
+
return undefined
|
|
26
|
+
}
|
|
27
|
+
return parsed
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Derive the receive amount: `receiveAmount = sendAmount × limitPrice`.
|
|
32
|
+
* Returns an empty string when either input is missing or invalid.
|
|
33
|
+
*/
|
|
34
|
+
export function deriveReceiveAmount(
|
|
35
|
+
sendAmount?: string,
|
|
36
|
+
limitPrice?: string,
|
|
37
|
+
toDecimals?: number
|
|
38
|
+
): string {
|
|
39
|
+
const send = parsePositive(sendAmount)
|
|
40
|
+
const price = parsePositive(limitPrice)
|
|
41
|
+
if (send === undefined || price === undefined) {
|
|
42
|
+
return ''
|
|
43
|
+
}
|
|
44
|
+
return formatInputAmount(
|
|
45
|
+
preciseFormatter.format(send * price),
|
|
46
|
+
toDecimals ?? null
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Derive the limit price: `limitPrice = receiveAmount ÷ sendAmount`.
|
|
52
|
+
* Returns an empty string when either input is missing or invalid.
|
|
53
|
+
*/
|
|
54
|
+
export function deriveLimitPrice(
|
|
55
|
+
sendAmount?: string,
|
|
56
|
+
receiveAmount?: string
|
|
57
|
+
): string {
|
|
58
|
+
const send = parsePositive(sendAmount)
|
|
59
|
+
const receive = parsePositive(receiveAmount)
|
|
60
|
+
if (send === undefined || receive === undefined) {
|
|
61
|
+
return ''
|
|
62
|
+
}
|
|
63
|
+
return preciseFormatter.format(receive / send)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Invert a price for display flipping: `1 ÷ price`. */
|
|
67
|
+
export function invertPrice(price?: string): string {
|
|
68
|
+
const parsed = parsePositive(price)
|
|
69
|
+
if (parsed === undefined) {
|
|
70
|
+
return ''
|
|
71
|
+
}
|
|
72
|
+
return preciseFormatter.format(1 / parsed)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Apply a percentage offset to a price, e.g. `percent = 2` → `price × 1.02`.
|
|
77
|
+
* Used by the quick-set buttons (+2%, +5%).
|
|
78
|
+
*/
|
|
79
|
+
export function applyPriceOffset(
|
|
80
|
+
price: string | undefined,
|
|
81
|
+
percent: number
|
|
82
|
+
): string {
|
|
83
|
+
const parsed = parsePositive(price)
|
|
84
|
+
if (parsed === undefined) {
|
|
85
|
+
return ''
|
|
86
|
+
}
|
|
87
|
+
return preciseFormatter.format(parsed * (1 + percent / 100))
|
|
88
|
+
}
|
|
@@ -8,6 +8,8 @@ export const navigationRoutes = {
|
|
|
8
8
|
languages: 'languages',
|
|
9
9
|
routes: 'routes',
|
|
10
10
|
settings: 'settings',
|
|
11
|
+
routePriority: 'route-priority',
|
|
12
|
+
slippage: 'slippage',
|
|
11
13
|
toChain: 'to-chain',
|
|
12
14
|
toToken: 'to-token',
|
|
13
15
|
toTokenNative: 'to-token-native',
|
|
@@ -30,6 +32,8 @@ export const stickyHeaderRoutes: string[] = [
|
|
|
30
32
|
navigationRoutes.home,
|
|
31
33
|
navigationRoutes.routes,
|
|
32
34
|
navigationRoutes.settings,
|
|
35
|
+
navigationRoutes.routePriority,
|
|
36
|
+
navigationRoutes.slippage,
|
|
33
37
|
navigationRoutes.toChain,
|
|
34
38
|
navigationRoutes.toTokenNative,
|
|
35
39
|
navigationRoutes.transactionDetails,
|
|
@@ -50,6 +54,8 @@ export const backButtonRoutes: string[] = [
|
|
|
50
54
|
navigationRoutes.fromToken,
|
|
51
55
|
navigationRoutes.routes,
|
|
52
56
|
navigationRoutes.settings,
|
|
57
|
+
navigationRoutes.routePriority,
|
|
58
|
+
navigationRoutes.slippage,
|
|
53
59
|
navigationRoutes.toChain,
|
|
54
60
|
navigationRoutes.toToken,
|
|
55
61
|
navigationRoutes.toTokenNative,
|
package/src/utils/token.ts
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
BaseToken,
|
|
3
|
-
RouteExtended,
|
|
4
|
-
Token,
|
|
5
|
-
TokenAmount,
|
|
6
|
-
TokenExtended,
|
|
7
|
-
} from '@lifi/sdk'
|
|
1
|
+
import type { BaseToken, RouteExtended, Token, TokenAmount } from '@lifi/sdk'
|
|
8
2
|
import type { FormType } from '../stores/form/types.js'
|
|
9
|
-
import type { TokensByChain } from '../types/token.js'
|
|
3
|
+
import type { TokensByChain, TokenWithVerified } from '../types/token.js'
|
|
10
4
|
import type { WidgetChains, WidgetTokens } from '../types/widget.js'
|
|
11
5
|
import { getConfigItemSets, isFormItemAllowed } from './item.js'
|
|
12
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Builds per-chain sets of lowercase token addresses from the
|
|
9
|
+
* `tokens.verified` config allowlist.
|
|
10
|
+
*/
|
|
11
|
+
export const getVerifiedTokensSets = (
|
|
12
|
+
configTokens?: WidgetTokens
|
|
13
|
+
): Map<number, Set<string>> | undefined => {
|
|
14
|
+
if (!configTokens?.verified?.length) {
|
|
15
|
+
return undefined
|
|
16
|
+
}
|
|
17
|
+
const sets = new Map<number, Set<string>>()
|
|
18
|
+
for (const token of configTokens.verified) {
|
|
19
|
+
const chainId = Number(token.chainId)
|
|
20
|
+
let addresses = sets.get(chainId)
|
|
21
|
+
if (!addresses) {
|
|
22
|
+
addresses = new Set()
|
|
23
|
+
sets.set(chainId, addresses)
|
|
24
|
+
}
|
|
25
|
+
addresses.add(token.address.toLowerCase())
|
|
26
|
+
}
|
|
27
|
+
return sets
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
/**
|
|
14
31
|
* Merges verified tokens with search tokens.
|
|
15
32
|
* Verified tokens take priority - search tokens are only added if they don't already exist.
|
|
@@ -74,11 +91,11 @@ export const updateTokenInCache = (
|
|
|
74
91
|
}
|
|
75
92
|
|
|
76
93
|
export const filterAllowedTokens = (
|
|
77
|
-
dataTokens:
|
|
94
|
+
dataTokens: TokensByChain | undefined,
|
|
78
95
|
configTokens?: WidgetTokens,
|
|
79
96
|
chainsConfig?: WidgetChains,
|
|
80
97
|
formType?: FormType
|
|
81
|
-
):
|
|
98
|
+
): TokensByChain | undefined => {
|
|
82
99
|
if (!dataTokens) {
|
|
83
100
|
return
|
|
84
101
|
}
|
|
@@ -103,12 +120,16 @@ export const filterAllowedTokens = (
|
|
|
103
120
|
)
|
|
104
121
|
: allChainIds
|
|
105
122
|
|
|
106
|
-
const
|
|
123
|
+
const verifiedTokensSets = getVerifiedTokensSets(configTokens)
|
|
124
|
+
|
|
125
|
+
const allowedTokensByChain: TokensByChain = {}
|
|
107
126
|
for (const chainId of allowedChainIds) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
127
|
+
const chainIncludedTokens = includedTokens.filter(
|
|
128
|
+
(t) => Number(t.chainId) === chainId
|
|
129
|
+
)
|
|
130
|
+
const includedAddresses = new Set(
|
|
131
|
+
chainIncludedTokens.map((t) => t.address.toLowerCase())
|
|
132
|
+
)
|
|
112
133
|
|
|
113
134
|
const allowedAddresses = getConfigItemSets(
|
|
114
135
|
configTokens,
|
|
@@ -121,11 +142,41 @@ export const filterAllowedTokens = (
|
|
|
121
142
|
formType
|
|
122
143
|
)
|
|
123
144
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
128
|
-
|
|
145
|
+
const verifiedAddresses = verifiedTokensSets?.get(chainId)
|
|
146
|
+
|
|
147
|
+
const chainTokens: TokenWithVerified[] = [
|
|
148
|
+
...(dataTokens[chainId] ?? []),
|
|
149
|
+
...chainIncludedTokens,
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
const filtered: TokenWithVerified[] = []
|
|
153
|
+
const seenAddresses = new Set<string>()
|
|
154
|
+
for (const token of chainTokens) {
|
|
155
|
+
const address = token.address.toLowerCase()
|
|
156
|
+
// Data tokens come first and win over include duplicates,
|
|
157
|
+
// keeping their extended data
|
|
158
|
+
if (seenAddresses.has(address)) {
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
seenAddresses.add(address)
|
|
162
|
+
if (
|
|
163
|
+
!isFormItemAllowed(token, allowedAddresses, formType, (t) =>
|
|
164
|
+
t.address.toLowerCase()
|
|
165
|
+
)
|
|
166
|
+
) {
|
|
167
|
+
continue
|
|
168
|
+
}
|
|
169
|
+
// Include and verified-allowlist tokens are explicitly set by the
|
|
170
|
+
// integrator, mark them as verified
|
|
171
|
+
if (
|
|
172
|
+
!token.verified &&
|
|
173
|
+
(includedAddresses.has(address) || verifiedAddresses?.has(address))
|
|
174
|
+
) {
|
|
175
|
+
filtered.push({ ...token, verified: true })
|
|
176
|
+
} else {
|
|
177
|
+
filtered.push(token)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
129
180
|
|
|
130
181
|
allowedTokensByChain[chainId] = filtered
|
|
131
182
|
}
|