@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
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import Check from '@mui/icons-material/Check'
|
|
2
|
+
import CloseRounded from '@mui/icons-material/CloseRounded'
|
|
3
|
+
import WarningRounded from '@mui/icons-material/WarningRounded'
|
|
4
|
+
import { Box, Collapse, List, Typography } from '@mui/material'
|
|
5
|
+
import type { ChangeEventHandler, FocusEventHandler } from 'react'
|
|
6
|
+
import { useRef, useState } from 'react'
|
|
7
|
+
import { useTranslation } from 'react-i18next'
|
|
8
|
+
import { ListItemText } from '../../../components/ListItemText.js'
|
|
9
|
+
import { PageContainer } from '../../../components/PageContainer.js'
|
|
10
|
+
import { SettingsListItemButton } from '../../../components/SettingsListItemButton.js'
|
|
11
|
+
import { useHeader } from '../../../hooks/useHeader.js'
|
|
12
|
+
import { useListHeight } from '../../../hooks/useListHeight.js'
|
|
13
|
+
import { useSettingMonitor } from '../../../hooks/useSettingMonitor.js'
|
|
14
|
+
import { defaultSlippage } from '../../../stores/settings/createSettingsStore.js'
|
|
15
|
+
import { useSettings } from '../../../stores/settings/useSettings.js'
|
|
16
|
+
import { useSettingsActions } from '../../../stores/settings/useSettingsActions.js'
|
|
17
|
+
import { formatInputAmount, formatSlippage } from '../../../utils/format.js'
|
|
18
|
+
import {
|
|
19
|
+
SlippageClearButton,
|
|
20
|
+
SlippageInput,
|
|
21
|
+
SlippageLimitsWarningContainer,
|
|
22
|
+
} from './SlippageSettings.style.js'
|
|
23
|
+
|
|
24
|
+
const slippagePresets = ['0.5', '1']
|
|
25
|
+
const maxFractionDigits = 5
|
|
26
|
+
|
|
27
|
+
export const SlippagePage: React.FC = () => {
|
|
28
|
+
const { t } = useTranslation()
|
|
29
|
+
const {
|
|
30
|
+
isSlippageNotRecommended,
|
|
31
|
+
isSlippageUnderRecommendedLimits,
|
|
32
|
+
isSlippageOutsideRecommendedLimits,
|
|
33
|
+
} = useSettingMonitor()
|
|
34
|
+
const { slippage } = useSettings(['slippage'])
|
|
35
|
+
const { setValue } = useSettingsActions()
|
|
36
|
+
const defaultValue = useRef(slippage)
|
|
37
|
+
const listParentRef = useRef<HTMLUListElement | null>(null)
|
|
38
|
+
const { listHeight } = useListHeight({ listParentRef })
|
|
39
|
+
|
|
40
|
+
useHeader(t('settings.slippage'))
|
|
41
|
+
|
|
42
|
+
const isAuto = !slippage || slippage === defaultSlippage
|
|
43
|
+
const isPreset = !!slippage && slippagePresets.includes(slippage)
|
|
44
|
+
const isCustom = !isAuto && !isPreset
|
|
45
|
+
|
|
46
|
+
const [customMode, setCustomMode] = useState(isCustom)
|
|
47
|
+
const [inputValue, setInputValue] = useState(isCustom ? (slippage ?? '') : '')
|
|
48
|
+
|
|
49
|
+
const handleAuto = () => {
|
|
50
|
+
setCustomMode(false)
|
|
51
|
+
setInputValue('')
|
|
52
|
+
setValue('slippage', defaultSlippage)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const handlePreset = (preset: string) => {
|
|
56
|
+
setCustomMode(false)
|
|
57
|
+
setValue('slippage', preset)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const handleCustom = () => {
|
|
61
|
+
setCustomMode(true)
|
|
62
|
+
const initialValue = slippage || ''
|
|
63
|
+
if (initialValue) {
|
|
64
|
+
setInputValue(initialValue)
|
|
65
|
+
setValue('slippage', initialValue)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const formatAndSetSlippage = (value: string, returnInitial = false) => {
|
|
70
|
+
const formattedSlippage = formatSlippage(
|
|
71
|
+
value,
|
|
72
|
+
defaultValue.current,
|
|
73
|
+
returnInitial
|
|
74
|
+
)
|
|
75
|
+
const formattedValue =
|
|
76
|
+
Number(formattedSlippage) === 0 && !returnInitial
|
|
77
|
+
? '0'
|
|
78
|
+
: formatInputAmount(formattedSlippage, maxFractionDigits, returnInitial)
|
|
79
|
+
const maxLength =
|
|
80
|
+
Number(formattedValue) < 10
|
|
81
|
+
? maxFractionDigits + 2
|
|
82
|
+
: maxFractionDigits + 3
|
|
83
|
+
const slicedValue = formattedValue.slice(0, maxLength)
|
|
84
|
+
setInputValue(slicedValue)
|
|
85
|
+
setValue('slippage', slicedValue.length ? slicedValue : defaultSlippage)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const handleInputUpdate: ChangeEventHandler<HTMLInputElement> = (event) => {
|
|
89
|
+
formatAndSetSlippage(event.target.value, true)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const handleInputFocus: FocusEventHandler<HTMLInputElement> = (event) => {
|
|
93
|
+
formatAndSetSlippage(event.target.value)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const handleInputBlur: FocusEventHandler<HTMLInputElement> = (event) => {
|
|
97
|
+
formatAndSetSlippage(event.target.value)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const slippageWarningText = isSlippageOutsideRecommendedLimits
|
|
101
|
+
? t('warning.message.slippageOutsideRecommendedLimits')
|
|
102
|
+
: isSlippageUnderRecommendedLimits
|
|
103
|
+
? t('warning.message.slippageUnderRecommendedLimits')
|
|
104
|
+
: ''
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<PageContainer disableGutters>
|
|
108
|
+
<List
|
|
109
|
+
className="long-list"
|
|
110
|
+
ref={listParentRef}
|
|
111
|
+
style={{ height: listHeight, overflow: 'auto' }}
|
|
112
|
+
sx={{
|
|
113
|
+
padding: 1.5,
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<SettingsListItemButton onClick={handleAuto}>
|
|
117
|
+
<ListItemText
|
|
118
|
+
primary={t('button.auto')}
|
|
119
|
+
secondary={t('settings.slippageAutoDescription')}
|
|
120
|
+
/>
|
|
121
|
+
{!customMode && isAuto && <Check color="primary" />}
|
|
122
|
+
</SettingsListItemButton>
|
|
123
|
+
{slippagePresets.map((preset) => (
|
|
124
|
+
<SettingsListItemButton
|
|
125
|
+
key={preset}
|
|
126
|
+
onClick={() => handlePreset(preset)}
|
|
127
|
+
>
|
|
128
|
+
<ListItemText primary={`${preset}%`} />
|
|
129
|
+
{!customMode && slippage === preset && <Check color="primary" />}
|
|
130
|
+
</SettingsListItemButton>
|
|
131
|
+
))}
|
|
132
|
+
<SettingsListItemButton onClick={handleCustom}>
|
|
133
|
+
<ListItemText primary={t('settings.custom')} />
|
|
134
|
+
{customMode && <Check color="primary" />}
|
|
135
|
+
</SettingsListItemButton>
|
|
136
|
+
<Collapse in={customMode}>
|
|
137
|
+
<Box sx={{ px: 1.5, pt: 1 }}>
|
|
138
|
+
<SlippageInput
|
|
139
|
+
placeholder="0.5"
|
|
140
|
+
inputProps={{ inputMode: 'decimal' }}
|
|
141
|
+
value={inputValue}
|
|
142
|
+
onChange={handleInputUpdate}
|
|
143
|
+
onFocus={handleInputFocus}
|
|
144
|
+
onBlur={handleInputBlur}
|
|
145
|
+
autoComplete="off"
|
|
146
|
+
endAdornment={
|
|
147
|
+
!isAuto && (
|
|
148
|
+
<SlippageClearButton
|
|
149
|
+
size="small"
|
|
150
|
+
onClick={handleAuto}
|
|
151
|
+
aria-label="Clear"
|
|
152
|
+
>
|
|
153
|
+
<CloseRounded fontSize="small" />
|
|
154
|
+
</SlippageClearButton>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
/>
|
|
158
|
+
{isSlippageNotRecommended && (
|
|
159
|
+
<SlippageLimitsWarningContainer>
|
|
160
|
+
<WarningRounded color="warning" />
|
|
161
|
+
<Typography
|
|
162
|
+
sx={{
|
|
163
|
+
fontSize: 13,
|
|
164
|
+
fontWeight: 400,
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
{slippageWarningText}
|
|
168
|
+
</Typography>
|
|
169
|
+
</SlippageLimitsWarningContainer>
|
|
170
|
+
)}
|
|
171
|
+
</Box>
|
|
172
|
+
</Collapse>
|
|
173
|
+
</List>
|
|
174
|
+
</PageContainer>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Theme } from '@mui/material'
|
|
2
2
|
import {
|
|
3
3
|
Box,
|
|
4
|
-
|
|
4
|
+
IconButton,
|
|
5
5
|
InputBase,
|
|
6
6
|
inputBaseClasses,
|
|
7
7
|
styled,
|
|
@@ -36,30 +36,6 @@ interface SettingsControlProps {
|
|
|
36
36
|
selected?: boolean
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export const SettingsDefaultButton: React.FC<
|
|
40
|
-
React.ComponentProps<typeof ButtonBase> & SettingsControlProps
|
|
41
|
-
> = styled(ButtonBase)<SettingsControlProps>(({ theme, selected }) => {
|
|
42
|
-
const settingsControlSelectedStyles = settingsControlSelected(theme)
|
|
43
|
-
const selectedStyle = selected
|
|
44
|
-
? {
|
|
45
|
-
'&:not(:focus)': {
|
|
46
|
-
...settingsControlSelectedStyles,
|
|
47
|
-
},
|
|
48
|
-
}
|
|
49
|
-
: {}
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
height: '100%',
|
|
53
|
-
width: '100%',
|
|
54
|
-
fontSize: '1rem',
|
|
55
|
-
fontWeight: 700,
|
|
56
|
-
'&:focus': {
|
|
57
|
-
...settingsControlSelectedStyles,
|
|
58
|
-
},
|
|
59
|
-
...selectedStyle,
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
|
|
63
39
|
export const SettingsCustomInput: React.FC<
|
|
64
40
|
React.ComponentProps<typeof InputBase> & SettingsControlProps
|
|
65
41
|
> = styled(InputBase)<SettingsControlProps>(({ theme, selected }) => {
|
|
@@ -100,3 +76,34 @@ export const SlippageLimitsWarningContainer: React.FC<
|
|
|
100
76
|
gap: theme.spacing(1.25),
|
|
101
77
|
marginTop: theme.spacing(1.5),
|
|
102
78
|
}))
|
|
79
|
+
|
|
80
|
+
export const SlippageInput: React.FC<React.ComponentProps<typeof InputBase>> =
|
|
81
|
+
styled(InputBase)(({ theme }) => ({
|
|
82
|
+
minHeight: 44,
|
|
83
|
+
width: '100%',
|
|
84
|
+
backgroundColor: theme.vars.palette.background.default,
|
|
85
|
+
border: '1px solid',
|
|
86
|
+
borderColor: theme.vars.palette.divider,
|
|
87
|
+
borderRadius: theme.vars.shape.borderRadius,
|
|
88
|
+
paddingRight: theme.spacing(1),
|
|
89
|
+
[`.${inputBaseClasses.input}`]: {
|
|
90
|
+
padding: theme.spacing(1.5),
|
|
91
|
+
fontSize: 16,
|
|
92
|
+
fontWeight: 500,
|
|
93
|
+
lineHeight: '20px',
|
|
94
|
+
'&::placeholder': {
|
|
95
|
+
opacity: 1,
|
|
96
|
+
color: theme.vars.palette.text.secondary,
|
|
97
|
+
},
|
|
98
|
+
'&::-webkit-outer-spin-button, &::-webkit-inner-spin-button': {
|
|
99
|
+
display: 'none',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
}))
|
|
103
|
+
|
|
104
|
+
export const SlippageClearButton: React.FC<
|
|
105
|
+
React.ComponentProps<typeof IconButton>
|
|
106
|
+
> = styled(IconButton)(({ theme }) => ({
|
|
107
|
+
padding: theme.spacing(0.5),
|
|
108
|
+
flexShrink: 0,
|
|
109
|
+
}))
|
|
@@ -1,82 +1,17 @@
|
|
|
1
1
|
import Percent from '@mui/icons-material/Percent'
|
|
2
|
-
import
|
|
3
|
-
import { Box, Typography } from '@mui/material'
|
|
4
|
-
import type { ChangeEventHandler, FocusEventHandler } from 'react'
|
|
5
|
-
import { useRef, useState } from 'react'
|
|
2
|
+
import { useNavigate } from '@tanstack/react-router'
|
|
6
3
|
import { useTranslation } from 'react-i18next'
|
|
4
|
+
import { CardButton } from '../../../components/Card/CardButton.js'
|
|
7
5
|
import { useSettingMonitor } from '../../../hooks/useSettingMonitor.js'
|
|
8
|
-
import { defaultSlippage } from '../../../stores/settings/createSettingsStore.js'
|
|
9
6
|
import { useSettings } from '../../../stores/settings/useSettings.js'
|
|
10
|
-
import {
|
|
11
|
-
import { formatInputAmount, formatSlippage } from '../../../utils/format.js'
|
|
7
|
+
import { navigationRoutes } from '../../../utils/navigationRoutes.js'
|
|
12
8
|
import { BadgedValue } from '../SettingsCard/BadgedValue.js'
|
|
13
|
-
import { SettingCardExpandable } from '../SettingsCard/SettingCardExpandable.js'
|
|
14
|
-
import {
|
|
15
|
-
SettingsCustomInput,
|
|
16
|
-
SettingsDefaultButton,
|
|
17
|
-
SettingsFieldSet,
|
|
18
|
-
SlippageLimitsWarningContainer,
|
|
19
|
-
} from './SlippageSettings.style.js'
|
|
20
|
-
|
|
21
|
-
const defaultSlippageInputValue = '0.5'
|
|
22
|
-
const maxFractionDigits = 5
|
|
23
9
|
|
|
24
10
|
export const SlippageSettings: React.FC = () => {
|
|
25
11
|
const { t } = useTranslation()
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
isSlippageUnderRecommendedLimits,
|
|
29
|
-
isSlippageOutsideRecommendedLimits,
|
|
30
|
-
isSlippageChanged,
|
|
31
|
-
} = useSettingMonitor()
|
|
12
|
+
const navigate = useNavigate()
|
|
13
|
+
const { isSlippageNotRecommended, isSlippageChanged } = useSettingMonitor()
|
|
32
14
|
const { slippage } = useSettings(['slippage'])
|
|
33
|
-
const { setValue } = useSettingsActions()
|
|
34
|
-
const defaultValue = useRef(slippage)
|
|
35
|
-
const [focused, setFocused] = useState<'input' | 'button'>()
|
|
36
|
-
|
|
37
|
-
const customInputValue =
|
|
38
|
-
!slippage || slippage === defaultSlippage
|
|
39
|
-
? defaultSlippageInputValue
|
|
40
|
-
: slippage
|
|
41
|
-
|
|
42
|
-
const [inputValue, setInputValue] = useState(customInputValue)
|
|
43
|
-
|
|
44
|
-
const handleDefaultClick = () => {
|
|
45
|
-
setValue('slippage', defaultSlippage)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const formatAndSetSlippage = (value: string, returnInitial = false) => {
|
|
49
|
-
const formattedSlippage = formatSlippage(
|
|
50
|
-
value,
|
|
51
|
-
defaultValue.current,
|
|
52
|
-
returnInitial
|
|
53
|
-
)
|
|
54
|
-
const formattedValue =
|
|
55
|
-
Number(formattedSlippage) === 0 && !returnInitial
|
|
56
|
-
? '0'
|
|
57
|
-
: formatInputAmount(formattedSlippage, maxFractionDigits, returnInitial)
|
|
58
|
-
const maxLength =
|
|
59
|
-
Number(formattedValue) < 10
|
|
60
|
-
? maxFractionDigits + 2
|
|
61
|
-
: maxFractionDigits + 3
|
|
62
|
-
const slicedValue = formattedValue.slice(0, maxLength)
|
|
63
|
-
setInputValue(slicedValue)
|
|
64
|
-
setValue('slippage', slicedValue.length ? slicedValue : defaultSlippage)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const handleInputUpdate: ChangeEventHandler<HTMLInputElement> = (event) => {
|
|
68
|
-
formatAndSetSlippage(event.target.value, true)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const handleInputFocus: FocusEventHandler<HTMLInputElement> = (event) => {
|
|
72
|
-
setFocused('input')
|
|
73
|
-
formatAndSetSlippage(event.target.value)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const handleInputBlur: FocusEventHandler<HTMLInputElement> = (event) => {
|
|
77
|
-
setFocused(undefined)
|
|
78
|
-
formatAndSetSlippage(event.target.value)
|
|
79
|
-
}
|
|
80
15
|
|
|
81
16
|
const badgeColor = isSlippageNotRecommended
|
|
82
17
|
? 'warning'
|
|
@@ -84,68 +19,19 @@ export const SlippageSettings: React.FC = () => {
|
|
|
84
19
|
? 'info'
|
|
85
20
|
: undefined
|
|
86
21
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
? t('warning.message.slippageUnderRecommendedLimits')
|
|
91
|
-
: ''
|
|
22
|
+
const handleClick = () => {
|
|
23
|
+
navigate({ to: navigationRoutes.slippage })
|
|
24
|
+
}
|
|
92
25
|
|
|
93
26
|
return (
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
<BadgedValue badgeColor={badgeColor} showBadge={!!badgeColor}>
|
|
97
|
-
{slippage ? `${slippage}%` : t('button.auto')}
|
|
98
|
-
</BadgedValue>
|
|
99
|
-
}
|
|
27
|
+
<CardButton
|
|
28
|
+
onClick={handleClick}
|
|
100
29
|
icon={<Percent />}
|
|
101
30
|
title={t('settings.slippage')}
|
|
102
31
|
>
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
>
|
|
108
|
-
<SettingsFieldSet>
|
|
109
|
-
<SettingsDefaultButton
|
|
110
|
-
selected={defaultSlippage === slippage && focused !== 'input'}
|
|
111
|
-
onFocus={() => {
|
|
112
|
-
setFocused('button')
|
|
113
|
-
}}
|
|
114
|
-
onBlur={() => {
|
|
115
|
-
setFocused(undefined)
|
|
116
|
-
}}
|
|
117
|
-
onClick={handleDefaultClick}
|
|
118
|
-
disableRipple
|
|
119
|
-
>
|
|
120
|
-
{t('button.auto')}
|
|
121
|
-
</SettingsDefaultButton>
|
|
122
|
-
<SettingsCustomInput
|
|
123
|
-
selected={defaultSlippage !== slippage && focused !== 'button'}
|
|
124
|
-
placeholder={focused === 'input' ? '' : t('settings.custom')}
|
|
125
|
-
inputProps={{
|
|
126
|
-
inputMode: 'decimal',
|
|
127
|
-
}}
|
|
128
|
-
onChange={handleInputUpdate}
|
|
129
|
-
onFocus={handleInputFocus}
|
|
130
|
-
value={inputValue}
|
|
131
|
-
autoComplete="off"
|
|
132
|
-
onBlur={handleInputBlur}
|
|
133
|
-
/>
|
|
134
|
-
</SettingsFieldSet>
|
|
135
|
-
{isSlippageNotRecommended && (
|
|
136
|
-
<SlippageLimitsWarningContainer>
|
|
137
|
-
<WarningRounded color="warning" />
|
|
138
|
-
<Typography
|
|
139
|
-
sx={{
|
|
140
|
-
fontSize: 13,
|
|
141
|
-
fontWeight: 400,
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
{slippageWarningText}
|
|
145
|
-
</Typography>
|
|
146
|
-
</SlippageLimitsWarningContainer>
|
|
147
|
-
)}
|
|
148
|
-
</Box>
|
|
149
|
-
</SettingCardExpandable>
|
|
32
|
+
<BadgedValue badgeColor={badgeColor} showBadge={!!badgeColor}>
|
|
33
|
+
{slippage ? `${slippage}%` : t('button.auto')}
|
|
34
|
+
</BadgedValue>
|
|
35
|
+
</CardButton>
|
|
150
36
|
)
|
|
151
37
|
}
|
|
@@ -5,7 +5,9 @@ import { Tooltip, useColorScheme } from '@mui/material'
|
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
import { CardValue } from '../../components/Card/CardButton.style.js'
|
|
7
7
|
import { CardTabs, Tab } from '../../components/Tabs/Tabs.style.js'
|
|
8
|
+
import { useWidgetEvents } from '../../hooks/useWidgetEvents.js'
|
|
8
9
|
import { useWidgetConfig } from '../../providers/WidgetProvider/WidgetProvider.js'
|
|
10
|
+
import { WidgetEvent } from '../../types/events.js'
|
|
9
11
|
import type { Appearance } from '../../types/widget.js'
|
|
10
12
|
import { SettingCardExpandable } from './SettingsCard/SettingCardExpandable.js'
|
|
11
13
|
|
|
@@ -37,6 +39,7 @@ const ThemeTab: React.FC<ThemeTabProps> = ({
|
|
|
37
39
|
export const ThemeSettings: React.FC = () => {
|
|
38
40
|
const { t } = useTranslation()
|
|
39
41
|
const { mode, setMode } = useColorScheme()
|
|
42
|
+
const widgetEvents = useWidgetEvents()
|
|
40
43
|
const { hiddenUI } = useWidgetConfig()
|
|
41
44
|
|
|
42
45
|
if (hiddenUI?.appearance) {
|
|
@@ -52,6 +55,7 @@ export const ThemeSettings: React.FC = () => {
|
|
|
52
55
|
appearance: Appearance
|
|
53
56
|
) => {
|
|
54
57
|
setMode(appearance)
|
|
58
|
+
widgetEvents.emit(WidgetEvent.AppearanceChanged, appearance)
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
return (
|
|
@@ -18,13 +18,23 @@ const formValueKeys: FormFieldNames[] = [
|
|
|
18
18
|
'toToken',
|
|
19
19
|
]
|
|
20
20
|
|
|
21
|
+
// Limit-order params are only mirrored to the URL while the limit tab is
|
|
22
|
+
// active, and stripped when the user leaves it. Unlike the base keys these are
|
|
23
|
+
// presence-gated (not touched-gated) so the URL fully reproduces the limit
|
|
24
|
+
// order — including the boolean/number fields, which are never "falsy-empty".
|
|
25
|
+
const limitFormValueKeys: FormFieldNames[] = [
|
|
26
|
+
'toAmount',
|
|
27
|
+
'validUntil',
|
|
28
|
+
'partiallyFillable',
|
|
29
|
+
]
|
|
30
|
+
|
|
21
31
|
export const URLSearchParamsBuilder = () => {
|
|
22
32
|
const { pathname } = useLocation()
|
|
23
33
|
const touchedFields = useTouchedFields()
|
|
24
|
-
const values = useFieldValues(...formValueKeys)
|
|
34
|
+
const values = useFieldValues(...formValueKeys, ...limitFormValueKeys)
|
|
25
35
|
const { setSelectedBookmark, addRecentWallet } = useBookmarkActions()
|
|
26
36
|
const { validateAddress } = useAddressValidation()
|
|
27
|
-
const { buildUrl } = useWidgetConfig()
|
|
37
|
+
const { buildUrl, mode } = useWidgetConfig()
|
|
28
38
|
// Using these methods as trying to use the touchedFields and values above
|
|
29
39
|
// often has a lag that can effect the widgets initialisation sequence
|
|
30
40
|
// and accidentally cause values to be wiped from the query string
|
|
@@ -85,9 +95,21 @@ export const URLSearchParamsBuilder = () => {
|
|
|
85
95
|
url.searchParams.delete(key)
|
|
86
96
|
}
|
|
87
97
|
})
|
|
98
|
+
// Limit params live in the URL only while the limit tab is active.
|
|
99
|
+
limitFormValueKeys.forEach((key) => {
|
|
100
|
+
const value = getFieldValues(key)[0]
|
|
101
|
+
// Booleans are always "set" (false is meaningful); strings/numbers use
|
|
102
|
+
// truthiness so an empty toAmount is treated as absent.
|
|
103
|
+
const hasValue = typeof value === 'boolean' ? true : Boolean(value)
|
|
104
|
+
if (mode === 'limit' && hasValue) {
|
|
105
|
+
url.searchParams.set(key, String(value))
|
|
106
|
+
} else {
|
|
107
|
+
url.searchParams.delete(key)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
88
110
|
url.searchParams.sort()
|
|
89
111
|
window.history.replaceState(window.history.state, '', url)
|
|
90
|
-
}, [pathname, touchedFields, values, isTouched, getFieldValues])
|
|
112
|
+
}, [pathname, touchedFields, values, isTouched, getFieldValues, mode])
|
|
91
113
|
|
|
92
114
|
return null
|
|
93
115
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StoreApi, UseBoundStore } from 'zustand'
|
|
2
2
|
import { create } from 'zustand'
|
|
3
|
-
|
|
3
|
+
import { DEFAULT_VALID_UNTIL_SECONDS } from '../../utils/limitOrder.js'
|
|
4
4
|
import type {
|
|
5
5
|
DefaultValues,
|
|
6
6
|
FormFieldArray,
|
|
@@ -14,6 +14,9 @@ export const formDefaultValues: DefaultValues = {
|
|
|
14
14
|
fromAmount: '',
|
|
15
15
|
toAmount: '',
|
|
16
16
|
tokenSearchFilter: '',
|
|
17
|
+
priceInverted: false,
|
|
18
|
+
validUntil: DEFAULT_VALID_UNTIL_SECONDS,
|
|
19
|
+
partiallyFillable: true,
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
const defaultValueToFormValue = <T>(value: T): FormValueControl<T> => ({
|
|
@@ -32,7 +35,8 @@ const valuesToFormValues = (defaultValues: DefaultValues): FormValues => {
|
|
|
32
35
|
)
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
const isString = (str:
|
|
38
|
+
const isString = (str: unknown): str is string =>
|
|
39
|
+
typeof str === 'string' || str instanceof String
|
|
36
40
|
|
|
37
41
|
const getUpdatedTouchedFields = (userValues: FormValues) => {
|
|
38
42
|
return (Object.keys(userValues) as FormFieldNames[]).reduce(
|
|
@@ -58,7 +62,7 @@ const mergeDefaultFormValues = (
|
|
|
58
62
|
),
|
|
59
63
|
isDirty: !!(userValues[key]?.isDirty || defaultValues[key]?.isTouched),
|
|
60
64
|
value:
|
|
61
|
-
userValues[key]?.value
|
|
65
|
+
userValues[key]?.value !== undefined && userValues[key]?.value !== ''
|
|
62
66
|
? userValues[key]?.value
|
|
63
67
|
: defaultValues[key]?.value,
|
|
64
68
|
}
|
|
@@ -41,6 +41,17 @@ export const getDefaultValuesFromQueryString = ({
|
|
|
41
41
|
...(Number.isFinite(Number.parseFloat(searchParams.fromAmount))
|
|
42
42
|
? { fromAmount: formatInputAmount(searchParams.fromAmount) }
|
|
43
43
|
: {}),
|
|
44
|
+
...(Number.isFinite(Number.parseFloat(searchParams.toAmount))
|
|
45
|
+
? { toAmount: formatInputAmount(searchParams.toAmount) }
|
|
46
|
+
: {}),
|
|
47
|
+
// Limit-order params (written only while on the limit tab).
|
|
48
|
+
...(Number.isFinite(Number.parseInt(searchParams.validUntil, 10))
|
|
49
|
+
? { validUntil: Number.parseInt(searchParams.validUntil, 10) }
|
|
50
|
+
: {}),
|
|
51
|
+
...(searchParams.partiallyFillable === 'true' ||
|
|
52
|
+
searchParams.partiallyFillable === 'false'
|
|
53
|
+
? { partiallyFillable: searchParams.partiallyFillable === 'true' }
|
|
54
|
+
: {}),
|
|
44
55
|
...(includeToAddress && searchParams.toAddress
|
|
45
56
|
? { toAddress: searchParams.toAddress }
|
|
46
57
|
: {}),
|
package/src/stores/form/types.ts
CHANGED
|
@@ -14,9 +14,22 @@ export interface DefaultFieldValues {
|
|
|
14
14
|
export interface DefaultValues extends DefaultFieldValues {
|
|
15
15
|
contractCalls?: ContractCall[]
|
|
16
16
|
tokenSearchFilter: string
|
|
17
|
+
/** Limit-order: when true, the price is displayed/entered inverted. */
|
|
18
|
+
priceInverted: boolean
|
|
19
|
+
/** Limit-order: order validity as a duration in seconds. */
|
|
20
|
+
validUntil: number
|
|
21
|
+
/** Limit-order: whether the order may be partially filled. */
|
|
22
|
+
partiallyFillable: boolean
|
|
23
|
+
/** Limit-order: id of the route the user picked. */
|
|
24
|
+
selectedRouteId?: string
|
|
17
25
|
}
|
|
18
26
|
|
|
19
|
-
export type GenericFormValue =
|
|
27
|
+
export type GenericFormValue =
|
|
28
|
+
| string
|
|
29
|
+
| number
|
|
30
|
+
| boolean
|
|
31
|
+
| ContractCall[]
|
|
32
|
+
| undefined
|
|
20
33
|
export interface FormValueControl<T> {
|
|
21
34
|
isTouched: boolean
|
|
22
35
|
isDirty: boolean
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { StoreApi, UseBoundStore } from 'zustand'
|
|
2
2
|
import type {
|
|
3
|
+
DefaultUI,
|
|
3
4
|
ModeOptions,
|
|
4
5
|
NavigationTabKey,
|
|
6
|
+
RequiredUIConfig,
|
|
5
7
|
WidgetMode,
|
|
6
8
|
WidgetVariant,
|
|
7
9
|
} from '../../types/widget.js'
|
|
@@ -14,6 +16,10 @@ export interface NavigationTab {
|
|
|
14
16
|
/** When omitted, the tab inherits `config.mode`. */
|
|
15
17
|
mode?: WidgetMode
|
|
16
18
|
modeOptions?: ModeOptions
|
|
19
|
+
/** Layered over `config.defaultUI` while the tab is active. */
|
|
20
|
+
defaultUI?: DefaultUI
|
|
21
|
+
/** Layered over `config.requiredUI` while the tab is active. */
|
|
22
|
+
requiredUI?: RequiredUIConfig
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
export interface NavigationTabsState {
|
|
@@ -21,8 +21,10 @@ import type { NavigationTabsState, NavigationTabsStore } from './types.js'
|
|
|
21
21
|
import {
|
|
22
22
|
getInitialActiveTab,
|
|
23
23
|
getNavigationTabKeys,
|
|
24
|
+
getTabDefaultUI,
|
|
24
25
|
getTabMode,
|
|
25
26
|
getTabModeOptions,
|
|
27
|
+
getTabRequiredUI,
|
|
26
28
|
getTabSplitMode,
|
|
27
29
|
getTabVariant,
|
|
28
30
|
} from './utils.js'
|
|
@@ -49,9 +51,10 @@ export function NavigationTabsStoreProvider({
|
|
|
49
51
|
signatureRef.current = signature
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
// Override the widget config with the active tab's mode, variant
|
|
53
|
-
// modeOptions (each falling back to the config), so
|
|
54
|
-
// reads tab-driven config transparently. No-op when
|
|
54
|
+
// Override the widget config with the active tab's mode, variant,
|
|
55
|
+
// modeOptions, defaultUI and requiredUI (each falling back to the config), so
|
|
56
|
+
// the rest of the widget reads tab-driven config transparently. No-op when
|
|
57
|
+
// there is no active tab.
|
|
55
58
|
const widgetConfig = useWidgetConfig()
|
|
56
59
|
const activeTab = store((state) => state.activeTab)
|
|
57
60
|
const tabConfig = useMemo(() => {
|
|
@@ -63,6 +66,8 @@ export function NavigationTabsStoreProvider({
|
|
|
63
66
|
mode: getTabMode(widgetConfig, activeTab),
|
|
64
67
|
variant: getTabVariant(widgetConfig, activeTab),
|
|
65
68
|
modeOptions: getTabModeOptions(widgetConfig, activeTab),
|
|
69
|
+
defaultUI: getTabDefaultUI(widgetConfig, activeTab),
|
|
70
|
+
requiredUI: getTabRequiredUI(widgetConfig, activeTab),
|
|
66
71
|
}
|
|
67
72
|
}, [widgetConfig, activeTab])
|
|
68
73
|
|