@lifi/widget 3.8.0-beta.2 → 3.8.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/CHANGELOG.md +16 -0
- package/dist/esm/components/GasMessage/GasRefuelMessage.js +2 -2
- package/dist/esm/components/GasMessage/GasRefuelMessage.js.map +1 -1
- package/dist/esm/components/Token/Token.js +7 -3
- package/dist/esm/components/Token/Token.js.map +1 -1
- package/dist/esm/components/TransactionDetails.js +8 -6
- package/dist/esm/components/TransactionDetails.js.map +1 -1
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/config/version.js.map +1 -1
- package/dist/esm/hooks/useLanguages.js +2 -2
- package/dist/esm/hooks/useLanguages.js.map +1 -1
- package/dist/esm/hooks/useSettingMonitor.js +3 -2
- package/dist/esm/hooks/useSettingMonitor.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pages/SelectEnabledToolsPage.js +3 -6
- package/dist/esm/pages/SelectEnabledToolsPage.js.map +1 -1
- package/dist/esm/pages/SettingsPage/GasPriceSettings.js +2 -2
- package/dist/esm/pages/SettingsPage/GasPriceSettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/RoutePrioritySettings.js +2 -2
- package/dist/esm/pages/SettingsPage/RoutePrioritySettings.js.map +1 -1
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.js +16 -10
- package/dist/esm/pages/SettingsPage/SlippageSettings/SlippageSettings.js.map +1 -1
- package/dist/esm/providers/WidgetProvider/WidgetProvider.js +3 -2
- package/dist/esm/providers/WidgetProvider/WidgetProvider.js.map +1 -1
- package/dist/esm/stores/form/types.d.ts +1 -1
- package/dist/esm/stores/form/useFieldActions.d.ts +10 -2
- package/dist/esm/stores/form/useFieldActions.js +39 -1
- package/dist/esm/stores/form/useFieldActions.js.map +1 -1
- package/dist/esm/stores/settings/types.d.ts +5 -2
- package/dist/esm/stores/settings/types.js.map +1 -1
- package/dist/esm/stores/settings/useAppearance.js +3 -2
- package/dist/esm/stores/settings/useAppearance.js.map +1 -1
- package/dist/esm/stores/settings/useSettingsActions.d.ts +9 -0
- package/dist/esm/stores/settings/useSettingsActions.js +77 -0
- package/dist/esm/stores/settings/useSettingsActions.js.map +1 -0
- package/dist/esm/stores/settings/useSettingsStore.d.ts +0 -2
- package/dist/esm/stores/settings/useSettingsStore.js +4 -26
- package/dist/esm/stores/settings/useSettingsStore.js.map +1 -1
- package/dist/esm/stores/settings/utils/getStateValues.d.ts +2 -0
- package/dist/esm/stores/settings/utils/getStateValues.js +15 -0
- package/dist/esm/stores/settings/utils/getStateValues.js.map +1 -0
- package/dist/esm/types/events.d.ts +21 -4
- package/dist/esm/types/events.js +2 -0
- package/dist/esm/types/events.js.map +1 -1
- package/dist/esm/utils/deepEqual.d.ts +2 -0
- package/dist/esm/utils/deepEqual.js +52 -0
- package/dist/esm/utils/deepEqual.js.map +1 -0
- package/dist/esm/utils/getPriceImpact.d.ts +9 -0
- package/dist/esm/utils/getPriceImpact.js +10 -0
- package/dist/esm/utils/getPriceImpact.js.map +1 -0
- package/package.json +5 -5
- package/src/components/GasMessage/GasRefuelMessage.tsx +3 -2
- package/src/components/Token/Token.tsx +7 -8
- package/src/components/TransactionDetails.tsx +8 -17
- package/src/config/version.ts +1 -1
- package/src/hooks/useLanguages.ts +2 -2
- package/src/hooks/useSettingMonitor.ts +2 -2
- package/src/index.ts +1 -0
- package/src/pages/SelectEnabledToolsPage.tsx +6 -10
- package/src/pages/SettingsPage/GasPriceSettings.tsx +2 -2
- package/src/pages/SettingsPage/RoutePrioritySettings.tsx +2 -2
- package/src/pages/SettingsPage/SlippageSettings/SlippageSettings.tsx +31 -21
- package/src/providers/WidgetProvider/WidgetProvider.tsx +5 -3
- package/src/stores/form/types.ts +1 -1
- package/src/stores/form/useFieldActions.ts +73 -2
- package/src/stores/settings/types.ts +7 -2
- package/src/stores/settings/useAppearance.ts +3 -5
- package/src/stores/settings/useSettingsActions.ts +152 -0
- package/src/stores/settings/useSettingsStore.ts +4 -34
- package/src/stores/settings/utils/getStateValues.ts +16 -0
- package/src/types/events.ts +24 -3
- package/src/utils/deepEqual.ts +62 -0
- package/src/utils/getPriceImpact.ts +26 -0
|
@@ -3,13 +3,13 @@ import { useTranslation } from 'react-i18next'
|
|
|
3
3
|
import { CardTabs, Tab } from '../../components/Tabs/Tabs.style.js'
|
|
4
4
|
import { useSettingMonitor } from '../../hooks/useSettingMonitor.js'
|
|
5
5
|
import { useSettings } from '../../stores/settings/useSettings.js'
|
|
6
|
-
import {
|
|
6
|
+
import { useSettingsActions } from '../../stores/settings/useSettingsActions.js'
|
|
7
7
|
import { BadgedValue } from './SettingsCard/BadgedValue.js'
|
|
8
8
|
import { SettingCardExpandable } from './SettingsCard/SettingCardExpandable.js'
|
|
9
9
|
|
|
10
10
|
export const GasPriceSettings: React.FC = () => {
|
|
11
11
|
const { t } = useTranslation()
|
|
12
|
-
const setValue =
|
|
12
|
+
const { setValue } = useSettingsActions()
|
|
13
13
|
const { isGasPriceChanged } = useSettingMonitor()
|
|
14
14
|
const { gasPrice } = useSettings(['gasPrice'])
|
|
15
15
|
|
|
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
|
|
4
4
|
import { CardTabs, Tab } from '../../components/Tabs/Tabs.style.js'
|
|
5
5
|
import { useSettingMonitor } from '../../hooks/useSettingMonitor.js'
|
|
6
6
|
import { useSettings } from '../../stores/settings/useSettings.js'
|
|
7
|
-
import {
|
|
7
|
+
import { useSettingsActions } from '../../stores/settings/useSettingsActions.js'
|
|
8
8
|
import { BadgedValue } from './SettingsCard/BadgedValue.js'
|
|
9
9
|
import { SettingCardExpandable } from './SettingsCard/SettingCardExpandable.js'
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ const Priorities: Order[] = ['CHEAPEST', 'FASTEST']
|
|
|
12
12
|
|
|
13
13
|
export const RoutePrioritySettings: React.FC = () => {
|
|
14
14
|
const { t } = useTranslation()
|
|
15
|
-
const setValue =
|
|
15
|
+
const { setValue } = useSettingsActions()
|
|
16
16
|
const { isRoutePriorityChanged } = useSettingMonitor()
|
|
17
17
|
const { routePriority } = useSettings(['routePriority'])
|
|
18
18
|
const currentRoutePriority = routePriority ?? ''
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { Percent, WarningRounded } from '@mui/icons-material'
|
|
2
|
-
import { Box, Typography } from '@mui/material'
|
|
2
|
+
import { Box, Typography, debounce } from '@mui/material'
|
|
3
3
|
import type { ChangeEventHandler, FocusEventHandler } from 'react'
|
|
4
|
-
import { useRef, useState } from 'react'
|
|
4
|
+
import { useCallback, useMemo, useRef, useState } from 'react'
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
import { useSettingMonitor } from '../../../hooks/useSettingMonitor.js'
|
|
7
7
|
import { useSettings } from '../../../stores/settings/useSettings.js'
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
useSettingsStore,
|
|
11
|
-
} from '../../../stores/settings/useSettingsStore.js'
|
|
8
|
+
import { useSettingsActions } from '../../../stores/settings/useSettingsActions.js'
|
|
9
|
+
import { defaultSlippage } from '../../../stores/settings/useSettingsStore.js'
|
|
12
10
|
import { formatSlippage } from '../../../utils/format.js'
|
|
13
11
|
import { BadgedValue } from '../SettingsCard/BadgedValue.js'
|
|
14
12
|
import { SettingCardExpandable } from '../SettingsCard/SettingCardExpandable.js'
|
|
@@ -24,36 +22,48 @@ export const SlippageSettings: React.FC = () => {
|
|
|
24
22
|
const { isSlippageOutsideRecommendedLimits, isSlippageChanged } =
|
|
25
23
|
useSettingMonitor()
|
|
26
24
|
const { slippage } = useSettings(['slippage'])
|
|
27
|
-
const setValue =
|
|
25
|
+
const { setValue } = useSettingsActions()
|
|
28
26
|
const defaultValue = useRef(slippage)
|
|
29
27
|
const [focused, setFocused] = useState<'input' | 'button'>()
|
|
30
28
|
|
|
29
|
+
const customInputValue =
|
|
30
|
+
!slippage || slippage === defaultSlippage ? '' : slippage
|
|
31
|
+
|
|
32
|
+
const [inputValue, setInputValue] = useState(customInputValue)
|
|
33
|
+
|
|
31
34
|
const handleDefaultClick = () => {
|
|
32
35
|
setValue('slippage', formatSlippage(defaultSlippage, defaultValue.current))
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
const
|
|
36
|
-
const { value } = event.target
|
|
38
|
+
const debouncedSetValue = useMemo(() => debounce(setValue, 500), [setValue])
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
const handleInputUpdate: ChangeEventHandler<HTMLInputElement> = useCallback(
|
|
41
|
+
(event) => {
|
|
42
|
+
const { value } = event.target
|
|
43
|
+
|
|
44
|
+
setInputValue(formatSlippage(value, defaultValue.current, true))
|
|
45
|
+
|
|
46
|
+
debouncedSetValue(
|
|
47
|
+
'slippage',
|
|
48
|
+
formatSlippage(value || defaultSlippage, defaultValue.current, true)
|
|
49
|
+
)
|
|
50
|
+
},
|
|
51
|
+
[debouncedSetValue]
|
|
52
|
+
)
|
|
43
53
|
|
|
44
54
|
const handleInputBlur: FocusEventHandler<HTMLInputElement> = (event) => {
|
|
45
55
|
setFocused(undefined)
|
|
46
56
|
|
|
47
57
|
const { value } = event.target
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
const formattedValue = formatSlippage(
|
|
60
|
+
value || defaultSlippage,
|
|
61
|
+
defaultValue.current
|
|
52
62
|
)
|
|
53
|
-
|
|
63
|
+
setInputValue(formattedValue === defaultSlippage ? '' : formattedValue)
|
|
54
64
|
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
setValue('slippage', formattedValue)
|
|
66
|
+
}
|
|
57
67
|
|
|
58
68
|
const badgeColor = isSlippageOutsideRecommendedLimits
|
|
59
69
|
? 'warning'
|
|
@@ -98,7 +108,7 @@ export const SlippageSettings: React.FC = () => {
|
|
|
98
108
|
setFocused('input')
|
|
99
109
|
}}
|
|
100
110
|
onBlur={handleInputBlur}
|
|
101
|
-
value={
|
|
111
|
+
value={inputValue}
|
|
102
112
|
autoComplete="off"
|
|
103
113
|
/>
|
|
104
114
|
</SettingsFieldSet>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { SDKConfig } from '@lifi/sdk'
|
|
2
|
+
import { config, createConfig } from '@lifi/sdk'
|
|
2
3
|
import { createContext, useContext, useId, useMemo } from 'react'
|
|
3
4
|
import { version } from '../../config/version.js'
|
|
4
|
-
import {
|
|
5
|
+
import { useSettingsActions } from '../../stores/settings/useSettingsActions.js'
|
|
5
6
|
import type { WidgetContextProps, WidgetProviderProps } from './types.js'
|
|
6
7
|
|
|
7
8
|
const initialContext: WidgetContextProps = {
|
|
@@ -20,6 +21,7 @@ export const WidgetProvider: React.FC<
|
|
|
20
21
|
React.PropsWithChildren<WidgetProviderProps>
|
|
21
22
|
> = ({ children, config: widgetConfig }) => {
|
|
22
23
|
const elementId = useId()
|
|
24
|
+
const { setDefaultSettings } = useSettingsActions()
|
|
23
25
|
|
|
24
26
|
if (!widgetConfig?.integrator) {
|
|
25
27
|
throw new Error('Required property "integrator" is missing.')
|
|
@@ -69,7 +71,7 @@ export const WidgetProvider: React.FC<
|
|
|
69
71
|
integrator: widgetConfig.integrator,
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
|
-
}, [elementId, widgetConfig])
|
|
74
|
+
}, [elementId, widgetConfig, setDefaultSettings])
|
|
73
75
|
return (
|
|
74
76
|
<WidgetContext.Provider value={value}>{children}</WidgetContext.Provider>
|
|
75
77
|
)
|
package/src/stores/form/types.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
1
2
|
import { shallow } from 'zustand/shallow'
|
|
2
|
-
import
|
|
3
|
+
import { useWidgetEvents } from '../../hooks/useWidgetEvents.js'
|
|
4
|
+
import type { FormFieldChanged } from '../../types/events.js'
|
|
5
|
+
import { WidgetEvent } from '../../types/events.js'
|
|
6
|
+
import type {
|
|
7
|
+
DefaultValues,
|
|
8
|
+
FormActions,
|
|
9
|
+
FormFieldNames,
|
|
10
|
+
GenericFormValue,
|
|
11
|
+
SetOptions,
|
|
12
|
+
} from './types.js'
|
|
3
13
|
import { useFormStore } from './useFormStore.js'
|
|
4
14
|
|
|
5
15
|
export const useFieldActions = () => {
|
|
16
|
+
const emitter = useWidgetEvents()
|
|
6
17
|
const actions = useFormStore<FormActions>(
|
|
7
18
|
(store) => ({
|
|
8
19
|
getFieldValues: store.getFieldValues,
|
|
@@ -16,5 +27,65 @@ export const useFieldActions = () => {
|
|
|
16
27
|
shallow
|
|
17
28
|
)
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
const setFieldValueWithEmittedEvents = useCallback(
|
|
31
|
+
(
|
|
32
|
+
fieldName: FormFieldNames,
|
|
33
|
+
newValue: GenericFormValue,
|
|
34
|
+
options?: SetOptions
|
|
35
|
+
) => {
|
|
36
|
+
const oldValue = actions.getFieldValues(fieldName)[0]
|
|
37
|
+
|
|
38
|
+
actions.setFieldValue(fieldName, newValue, options)
|
|
39
|
+
|
|
40
|
+
if (newValue !== oldValue) {
|
|
41
|
+
emitter.emit(WidgetEvent.FormFieldChanged, {
|
|
42
|
+
fieldName,
|
|
43
|
+
newValue,
|
|
44
|
+
oldValue,
|
|
45
|
+
} as FormFieldChanged)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
[actions, emitter]
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const setUserAndDefaultValuesWithEmittedEvents = useCallback(
|
|
52
|
+
(formValues: Partial<DefaultValues>) => {
|
|
53
|
+
const formValuesKeys = Object.keys(formValues) as FormFieldNames[]
|
|
54
|
+
|
|
55
|
+
const changedValues = formValuesKeys.reduce(
|
|
56
|
+
(accum, fieldName) => {
|
|
57
|
+
const oldValue = actions.getFieldValues(fieldName)[0]
|
|
58
|
+
const newValue = formValues[fieldName]
|
|
59
|
+
|
|
60
|
+
if (newValue !== oldValue) {
|
|
61
|
+
accum.push({ fieldName, newValue, oldValue })
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return accum
|
|
65
|
+
},
|
|
66
|
+
[] as {
|
|
67
|
+
fieldName: FormFieldNames
|
|
68
|
+
newValue: GenericFormValue
|
|
69
|
+
oldValue: GenericFormValue
|
|
70
|
+
}[]
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
actions.setUserAndDefaultValues(formValues)
|
|
74
|
+
|
|
75
|
+
changedValues.forEach(({ fieldName, newValue, oldValue }) => {
|
|
76
|
+
emitter.emit(WidgetEvent.FormFieldChanged, {
|
|
77
|
+
fieldName,
|
|
78
|
+
newValue,
|
|
79
|
+
oldValue,
|
|
80
|
+
} as FormFieldChanged)
|
|
81
|
+
})
|
|
82
|
+
},
|
|
83
|
+
[actions, emitter]
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...actions,
|
|
88
|
+
setFieldValue: setFieldValueWithEmittedEvents,
|
|
89
|
+
setUserAndDefaultValues: setUserAndDefaultValuesWithEmittedEvents,
|
|
90
|
+
}
|
|
20
91
|
}
|
|
@@ -9,6 +9,8 @@ export type ValueSetter<S> = <K extends keyof S>(
|
|
|
9
9
|
value: S[Extract<K, string>]
|
|
10
10
|
) => void
|
|
11
11
|
|
|
12
|
+
export type ValueGetter<S> = <K extends keyof S>(key: K) => S[K]
|
|
13
|
+
|
|
12
14
|
export type ValuesSetter<S> = <K extends keyof S>(
|
|
13
15
|
values: Record<K, S[Extract<K, string>]>
|
|
14
16
|
) => void
|
|
@@ -31,9 +33,10 @@ export interface SettingsProps {
|
|
|
31
33
|
_enabledExchanges: Record<string, boolean>
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
export interface
|
|
36
|
+
export interface SettingsActions {
|
|
35
37
|
setValue: ValueSetter<SettingsProps>
|
|
36
|
-
|
|
38
|
+
getValue: ValueGetter<SettingsProps>
|
|
39
|
+
getSettings: () => SettingsProps
|
|
37
40
|
initializeTools(
|
|
38
41
|
toolType: SettingsToolType,
|
|
39
42
|
tools: string[],
|
|
@@ -44,6 +47,8 @@ export interface SettingsState extends SettingsProps {
|
|
|
44
47
|
reset(bridges: string[], exchanges: string[]): void
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
export type SettingsState = SettingsProps & SettingsActions
|
|
51
|
+
|
|
47
52
|
export interface SendToWalletState {
|
|
48
53
|
showSendToWallet: boolean
|
|
49
54
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useSettingsActions } from '../../stores/settings/useSettingsActions.js'
|
|
2
2
|
import type { Appearance } from '../../types/widget.js'
|
|
3
3
|
import { useSettingsStore } from './useSettingsStore.js'
|
|
4
4
|
|
|
@@ -6,10 +6,8 @@ export const useAppearance = (): [
|
|
|
6
6
|
Appearance,
|
|
7
7
|
(appearance: Appearance) => void,
|
|
8
8
|
] => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
shallow
|
|
12
|
-
)
|
|
9
|
+
const { setValue } = useSettingsActions()
|
|
10
|
+
const appearance = useSettingsStore((state) => state.appearance)
|
|
13
11
|
const setAppearance = (appearance: Appearance) => {
|
|
14
12
|
setValue('appearance', appearance)
|
|
15
13
|
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import { shallow } from 'zustand/shallow'
|
|
3
|
+
import type { widgetEvents } from '../../hooks/useWidgetEvents.js'
|
|
4
|
+
import { useWidgetEvents } from '../../hooks/useWidgetEvents.js'
|
|
5
|
+
import { WidgetEvent } from '../../types/events.js'
|
|
6
|
+
import type { WidgetConfig } from '../../types/widget.js'
|
|
7
|
+
import { deepEqual } from '../../utils/deepEqual.js'
|
|
8
|
+
import type {
|
|
9
|
+
SettingsActions,
|
|
10
|
+
SettingsProps,
|
|
11
|
+
SettingsToolType,
|
|
12
|
+
ValueSetter,
|
|
13
|
+
} from './types.js'
|
|
14
|
+
import {
|
|
15
|
+
defaultConfigurableSettings,
|
|
16
|
+
useSettingsStore,
|
|
17
|
+
} from './useSettingsStore.js'
|
|
18
|
+
|
|
19
|
+
const emitEventOnChange = <T extends (...args: any[]) => any>(
|
|
20
|
+
emitter: typeof widgetEvents,
|
|
21
|
+
actions: Omit<SettingsActions, 'initializeTools'>,
|
|
22
|
+
settingFunction: T,
|
|
23
|
+
...args: Parameters<T>
|
|
24
|
+
) => {
|
|
25
|
+
const oldSettings = actions.getSettings()
|
|
26
|
+
|
|
27
|
+
settingFunction(...args)
|
|
28
|
+
|
|
29
|
+
const newSettings = actions.getSettings()
|
|
30
|
+
|
|
31
|
+
if (!deepEqual(oldSettings, newSettings)) {
|
|
32
|
+
;(Object.keys(oldSettings) as (keyof SettingsProps)[]).forEach(
|
|
33
|
+
(toolKey) => {
|
|
34
|
+
if (!deepEqual(oldSettings[toolKey], newSettings[toolKey])) {
|
|
35
|
+
emitter.emit(WidgetEvent.SettingUpdated, {
|
|
36
|
+
setting: toolKey,
|
|
37
|
+
newValue: newSettings[toolKey],
|
|
38
|
+
oldValue: oldSettings[toolKey],
|
|
39
|
+
newSettings: newSettings,
|
|
40
|
+
oldSettings: oldSettings,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const useSettingsActions = () => {
|
|
49
|
+
const emitter = useWidgetEvents()
|
|
50
|
+
const actions = useSettingsStore(
|
|
51
|
+
(state) => ({
|
|
52
|
+
setValue: state.setValue,
|
|
53
|
+
getValue: state.getValue,
|
|
54
|
+
getSettings: state.getSettings,
|
|
55
|
+
reset: state.reset,
|
|
56
|
+
setToolValue: state.setToolValue,
|
|
57
|
+
toggleToolKeys: state.toggleToolKeys,
|
|
58
|
+
}),
|
|
59
|
+
shallow
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
const setValueWithEmittedEvent = useCallback<ValueSetter<SettingsProps>>(
|
|
63
|
+
(value, newValue) => {
|
|
64
|
+
const setting = value as keyof SettingsProps
|
|
65
|
+
emitEventOnChange(emitter, actions, actions.setValue, setting, newValue)
|
|
66
|
+
},
|
|
67
|
+
[emitter, actions]
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const setDefaultSettingsWithEmittedEvents = useCallback(
|
|
71
|
+
(config?: WidgetConfig) => {
|
|
72
|
+
const slippage = actions.getValue('slippage')
|
|
73
|
+
const routePriority = actions.getValue('routePriority')
|
|
74
|
+
const gasPrice = actions.getValue('gasPrice')
|
|
75
|
+
|
|
76
|
+
const defaultSlippage =
|
|
77
|
+
(config?.slippage || config?.sdkConfig?.routeOptions?.slippage || 0) *
|
|
78
|
+
100
|
|
79
|
+
const defaultRoutePriority =
|
|
80
|
+
config?.routePriority || config?.sdkConfig?.routeOptions?.order
|
|
81
|
+
|
|
82
|
+
defaultConfigurableSettings.slippage = (
|
|
83
|
+
defaultSlippage || defaultConfigurableSettings.slippage
|
|
84
|
+
)?.toString()
|
|
85
|
+
|
|
86
|
+
defaultConfigurableSettings.routePriority =
|
|
87
|
+
defaultRoutePriority || defaultConfigurableSettings.routePriority
|
|
88
|
+
|
|
89
|
+
if (!slippage) {
|
|
90
|
+
setValueWithEmittedEvent(
|
|
91
|
+
'slippage',
|
|
92
|
+
defaultConfigurableSettings.slippage
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
if (!routePriority) {
|
|
96
|
+
setValueWithEmittedEvent(
|
|
97
|
+
'routePriority',
|
|
98
|
+
defaultConfigurableSettings.routePriority
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
if (!gasPrice) {
|
|
102
|
+
setValueWithEmittedEvent(
|
|
103
|
+
'gasPrice',
|
|
104
|
+
defaultConfigurableSettings.gasPrice
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
[actions, setValueWithEmittedEvent]
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
const resetWithEmittedEvents = useCallback(
|
|
112
|
+
(bridges: string[], exchanges: string[]) => {
|
|
113
|
+
emitEventOnChange(emitter, actions, actions.reset, bridges, exchanges)
|
|
114
|
+
},
|
|
115
|
+
[emitter, actions]
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
const setToolValueWithEmittedEvents = useCallback(
|
|
119
|
+
(toolType: SettingsToolType, tool: string, value: boolean) => {
|
|
120
|
+
emitEventOnChange(
|
|
121
|
+
emitter,
|
|
122
|
+
actions,
|
|
123
|
+
actions.setToolValue,
|
|
124
|
+
toolType,
|
|
125
|
+
tool,
|
|
126
|
+
value
|
|
127
|
+
)
|
|
128
|
+
},
|
|
129
|
+
[emitter, actions]
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
const toggleToolKeysWithEmittedEvents = useCallback(
|
|
133
|
+
(toolType: SettingsToolType, toolKeys: string[]) => {
|
|
134
|
+
emitEventOnChange(
|
|
135
|
+
emitter,
|
|
136
|
+
actions,
|
|
137
|
+
actions.toggleToolKeys,
|
|
138
|
+
toolType,
|
|
139
|
+
toolKeys
|
|
140
|
+
)
|
|
141
|
+
},
|
|
142
|
+
[emitter, actions]
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
setValue: setValueWithEmittedEvent,
|
|
147
|
+
setDefaultSettings: setDefaultSettingsWithEmittedEvents,
|
|
148
|
+
resetSettings: resetWithEmittedEvents,
|
|
149
|
+
setToolValue: setToolValueWithEmittedEvents,
|
|
150
|
+
toggleToolKeys: toggleToolKeysWithEmittedEvents,
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { StateCreator } from 'zustand'
|
|
2
2
|
import { persist } from 'zustand/middleware'
|
|
3
3
|
import { createWithEqualityFn } from 'zustand/traditional'
|
|
4
|
-
import type { WidgetConfig } from '../../types/widget.js'
|
|
5
4
|
import type { SettingsProps, SettingsState } from './types.js'
|
|
6
5
|
import { SettingsToolTypes } from './types.js'
|
|
6
|
+
import { getStateValues } from './utils/getStateValues.js'
|
|
7
7
|
|
|
8
8
|
export const defaultSlippage = '0.5'
|
|
9
9
|
|
|
@@ -36,16 +36,8 @@ export const useSettingsStore = createWithEqualityFn<SettingsState>(
|
|
|
36
36
|
set(() => ({
|
|
37
37
|
[key]: value,
|
|
38
38
|
})),
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const updatedState: SettingsProps = { ...state }
|
|
42
|
-
for (const key in values) {
|
|
43
|
-
if (Object.hasOwn(state, key)) {
|
|
44
|
-
updatedState[key] = values[key]
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return updatedState
|
|
48
|
-
}),
|
|
39
|
+
getSettings: () => getStateValues(get()),
|
|
40
|
+
getValue: (key) => get()[key],
|
|
49
41
|
initializeTools: (toolType, tools, reset) => {
|
|
50
42
|
if (!tools.length) {
|
|
51
43
|
return
|
|
@@ -141,6 +133,7 @@ export const useSettingsStore = createWithEqualityFn<SettingsState>(
|
|
|
141
133
|
}))
|
|
142
134
|
get().initializeTools('Bridges', bridges, true)
|
|
143
135
|
get().initializeTools('Exchanges', exchanges, true)
|
|
136
|
+
return { ...get() }
|
|
144
137
|
},
|
|
145
138
|
}),
|
|
146
139
|
{
|
|
@@ -187,26 +180,3 @@ export const useSettingsStore = createWithEqualityFn<SettingsState>(
|
|
|
187
180
|
) as StateCreator<SettingsState, [], [], SettingsState>,
|
|
188
181
|
Object.is
|
|
189
182
|
)
|
|
190
|
-
|
|
191
|
-
export const setDefaultSettings = (config?: WidgetConfig) => {
|
|
192
|
-
const { slippage, routePriority, setValue, gasPrice } =
|
|
193
|
-
useSettingsStore.getState()
|
|
194
|
-
const defaultSlippage =
|
|
195
|
-
(config?.slippage || config?.sdkConfig?.routeOptions?.slippage || 0) * 100
|
|
196
|
-
const defaultRoutePriority =
|
|
197
|
-
config?.routePriority || config?.sdkConfig?.routeOptions?.order
|
|
198
|
-
defaultConfigurableSettings.slippage = (
|
|
199
|
-
defaultSlippage || defaultConfigurableSettings.slippage
|
|
200
|
-
)?.toString()
|
|
201
|
-
defaultConfigurableSettings.routePriority =
|
|
202
|
-
defaultRoutePriority || defaultConfigurableSettings.routePriority
|
|
203
|
-
if (!slippage) {
|
|
204
|
-
setValue('slippage', defaultConfigurableSettings.slippage)
|
|
205
|
-
}
|
|
206
|
-
if (!routePriority) {
|
|
207
|
-
setValue('routePriority', defaultConfigurableSettings.routePriority)
|
|
208
|
-
}
|
|
209
|
-
if (!gasPrice) {
|
|
210
|
-
setValue('gasPrice', defaultConfigurableSettings.gasPrice)
|
|
211
|
-
}
|
|
212
|
-
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SettingsProps, SettingsState } from '../types.js'
|
|
2
|
+
|
|
3
|
+
export const getStateValues = (state: SettingsState): SettingsProps => ({
|
|
4
|
+
appearance: state.appearance,
|
|
5
|
+
gasPrice: state.gasPrice,
|
|
6
|
+
language: state.language,
|
|
7
|
+
routePriority: state.routePriority,
|
|
8
|
+
enabledAutoRefuel: state.enabledAutoRefuel,
|
|
9
|
+
slippage: state.slippage,
|
|
10
|
+
disabledBridges: [...state.disabledBridges],
|
|
11
|
+
enabledBridges: [...state.enabledBridges],
|
|
12
|
+
_enabledBridges: { ...state._enabledBridges },
|
|
13
|
+
disabledExchanges: [...state.disabledExchanges],
|
|
14
|
+
enabledExchanges: [...state.enabledExchanges],
|
|
15
|
+
_enabledExchanges: { ...state._enabledExchanges },
|
|
16
|
+
})
|
package/src/types/events.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ChainId, ChainType, Process, Route } from '@lifi/sdk'
|
|
2
|
+
import type { DefaultValues } from '../stores/form/types.js'
|
|
3
|
+
import type { SettingsProps } from '../stores/settings/types.js'
|
|
2
4
|
import type { NavigationRouteType } from '../utils/navigationRoutes.js'
|
|
3
5
|
|
|
4
6
|
export enum WidgetEvent {
|
|
@@ -22,6 +24,8 @@ export enum WidgetEvent {
|
|
|
22
24
|
WalletConnected = 'walletConnected',
|
|
23
25
|
WidgetExpanded = 'widgetExpanded',
|
|
24
26
|
PageEntered = 'pageEntered',
|
|
27
|
+
FormFieldChanged = 'formFieldChanged',
|
|
28
|
+
SettingUpdated = 'settingUpdated',
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
export type WidgetEvents = {
|
|
@@ -35,13 +39,12 @@ export type WidgetEvents = {
|
|
|
35
39
|
sourceChainTokenSelected: ChainTokenSelected
|
|
36
40
|
destinationChainTokenSelected: ChainTokenSelected
|
|
37
41
|
sendToWalletToggled: boolean
|
|
42
|
+
formFieldChanged: FormFieldChanged
|
|
38
43
|
reviewTransactionPageEntered?: Route
|
|
39
|
-
/**
|
|
40
|
-
* @deprecated use useWalletManagementEvents hook.
|
|
41
|
-
*/
|
|
42
44
|
walletConnected: WalletConnected
|
|
43
45
|
widgetExpanded: boolean
|
|
44
46
|
pageEntered: NavigationRouteType
|
|
47
|
+
settingUpdated: SettingUpdated
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
export interface ContactSupport {
|
|
@@ -71,3 +74,21 @@ export interface WalletConnected {
|
|
|
71
74
|
chainId?: number
|
|
72
75
|
chainType?: ChainType
|
|
73
76
|
}
|
|
77
|
+
|
|
78
|
+
export type FormFieldChanged = {
|
|
79
|
+
[K in keyof DefaultValues]: {
|
|
80
|
+
fieldName: K
|
|
81
|
+
newValue: DefaultValues[K]
|
|
82
|
+
oldValue: DefaultValues[K]
|
|
83
|
+
}
|
|
84
|
+
}[keyof DefaultValues]
|
|
85
|
+
|
|
86
|
+
export type SettingUpdated<
|
|
87
|
+
K extends keyof SettingsProps = keyof SettingsProps,
|
|
88
|
+
> = {
|
|
89
|
+
setting: K
|
|
90
|
+
newValue: SettingsProps[K]
|
|
91
|
+
oldValue: SettingsProps[K]
|
|
92
|
+
newSettings: SettingsProps
|
|
93
|
+
oldSettings: SettingsProps
|
|
94
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Forked from https://github.com/epoberezkin/fast-deep-equal */
|
|
2
|
+
|
|
3
|
+
export function deepEqual(a: any, b: any) {
|
|
4
|
+
if (a === b) {
|
|
5
|
+
return true
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (a && b && typeof a === 'object' && typeof b === 'object') {
|
|
9
|
+
if (a.constructor !== b.constructor) {
|
|
10
|
+
return false
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let length: number
|
|
14
|
+
let i: number
|
|
15
|
+
|
|
16
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
17
|
+
length = a.length
|
|
18
|
+
if (length !== b.length) {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
for (i = length; i-- !== 0; ) {
|
|
22
|
+
if (!deepEqual(a[i], b[i])) {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (a.valueOf !== Object.prototype.valueOf) {
|
|
30
|
+
return a.valueOf() === b.valueOf()
|
|
31
|
+
}
|
|
32
|
+
if (a.toString !== Object.prototype.toString) {
|
|
33
|
+
return a.toString() === b.toString()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const keys = Object.keys(a)
|
|
37
|
+
length = keys.length
|
|
38
|
+
if (length !== Object.keys(b).length) {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (i = length; i-- !== 0; ) {
|
|
43
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i]!)) {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (i = length; i-- !== 0; ) {
|
|
49
|
+
const key = keys[i]
|
|
50
|
+
|
|
51
|
+
if (key && !deepEqual(a[key], b[key])) {
|
|
52
|
+
return false
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// true if both NaN, false otherwise
|
|
60
|
+
// biome-ignore lint/suspicious/noSelfCompare: <explanation>
|
|
61
|
+
return a !== a && b !== b
|
|
62
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Token } from '@lifi/sdk'
|
|
2
|
+
import { formatTokenAmount, formatTokenPrice } from './format.js'
|
|
3
|
+
|
|
4
|
+
interface GetPriceImpractProps {
|
|
5
|
+
fromToken: Token
|
|
6
|
+
toToken: Token
|
|
7
|
+
fromAmount?: bigint
|
|
8
|
+
toAmount?: bigint
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const getPriceImpact = ({
|
|
12
|
+
fromToken,
|
|
13
|
+
toToken,
|
|
14
|
+
fromAmount,
|
|
15
|
+
toAmount,
|
|
16
|
+
}: GetPriceImpractProps) => {
|
|
17
|
+
const fromTokenAmount = formatTokenAmount(fromAmount, fromToken.decimals)
|
|
18
|
+
const fromTokenPrice = formatTokenPrice(fromTokenAmount, fromToken.priceUSD)
|
|
19
|
+
|
|
20
|
+
const toTokenAmount = formatTokenAmount(toAmount, toToken.decimals)
|
|
21
|
+
const toTokenPrice = formatTokenPrice(toTokenAmount, toToken.priceUSD) || 0.01
|
|
22
|
+
|
|
23
|
+
const priceImpact = toTokenPrice / fromTokenPrice - 1
|
|
24
|
+
|
|
25
|
+
return Number(priceImpact)
|
|
26
|
+
}
|