@lifi/widget 1.1.2 → 1.2.1
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/App.js +9 -1
- package/AppProvider.js +7 -2
- package/components/Header/Header.js +1 -1
- package/components/Header/NavigationHeader.js +5 -3
- package/components/Header/WalletHeader.js +19 -3
- package/components/Initializer.d.ts +2 -0
- package/components/Initializer.js +5 -0
- package/components/StepToken.js +1 -1
- package/components/SwapButton/SwapButton.js +5 -2
- package/components/SwapInProgress/SwapInProgress.js +1 -1
- package/components/SwapRoutes/SwapRoutes.js +2 -1
- package/components/TextFitter/TextFitter.js +9 -5
- package/hooks/index.d.ts +1 -3
- package/hooks/index.js +1 -3
- package/hooks/useContentHeight.js +18 -10
- package/hooks/useHasSufficientBalance.js +1 -1
- package/hooks/useInitializer.d.ts +1 -0
- package/hooks/useInitializer.js +5 -0
- package/hooks/{useRouteExecution/useRouteExecution.d.ts → useRouteExecution.d.ts} +1 -1
- package/hooks/{useRouteExecution/useRouteExecution.js → useRouteExecution.js} +5 -5
- package/hooks/useSwapRoutes.js +9 -7
- package/hooks/useTools.d.ts +1 -0
- package/hooks/useTools.js +14 -0
- package/i18n/en/translation.json +0 -2
- package/i18n/index.d.ts +0 -2
- package/package.json +6 -6
- package/pages/SelectTokenPage/ChainSelect.js +1 -1
- package/pages/SettingsPage/AdvancedPreferences.js +5 -4
- package/pages/SettingsPage/ColorSchemeButtonGroup.js +1 -1
- package/pages/SettingsPage/EnabledBridgesSelect.js +11 -6
- package/pages/SettingsPage/EnabledExchangesSelect.js +10 -6
- package/pages/SettingsPage/GasPriceSelect.js +4 -4
- package/pages/SettingsPage/RoutePrioritySelect.js +4 -4
- package/pages/SettingsPage/SlippageInput.js +7 -10
- package/pages/SwapPage/ExecutionItem.js +1 -1
- package/pages/SwapPage/StatusBottomSheet.d.ts +1 -1
- package/pages/SwapPage/StatusBottomSheet.style.d.ts +1 -1
- package/pages/SwapPage/StepItem.js +1 -1
- package/pages/SwapPage/StepTimer.js +3 -2
- package/pages/SwapRoutesPage/SwapRoutesPage.js +2 -1
- package/providers/SwapFormProvider/SwapFormProvider.d.ts +0 -3
- package/providers/SwapFormProvider/SwapFormProvider.js +0 -3
- package/providers/SwapFormProvider/types.d.ts +0 -19
- package/providers/SwapFormProvider/types.js +0 -9
- package/providers/ThemeProvider/ThemeProvider.js +1 -1
- package/providers/WalletProvider/WalletProvider.js +46 -13
- package/providers/WalletProvider/types.d.ts +2 -1
- package/providers/WidgetProvider/types.d.ts +2 -2
- package/stores/index.d.ts +2 -0
- package/stores/index.js +2 -0
- package/stores/route/index.d.ts +5 -0
- package/stores/route/index.js +5 -0
- package/{hooks/useRouteExecution → stores/route}/types.d.ts +0 -0
- package/{hooks/useRouteExecution → stores/route}/types.js +0 -0
- package/stores/route/useCurrentRoute.d.ts +2 -0
- package/stores/route/useCurrentRoute.js +5 -0
- package/stores/route/useExecutingRoutes.d.ts +1 -0
- package/stores/route/useExecutingRoutes.js +4 -0
- package/{hooks/useRouteExecution → stores/route}/useRouteStore.d.ts +3 -5
- package/{hooks/useRouteExecution → stores/route}/useRouteStore.js +16 -26
- package/stores/route/useSetExecutableRoute.d.ts +1 -0
- package/stores/route/useSetExecutableRoute.js +4 -0
- package/stores/settings/index.d.ts +5 -0
- package/stores/settings/index.js +5 -0
- package/stores/settings/types.d.ts +23 -0
- package/stores/settings/types.js +1 -0
- package/stores/settings/useAppearance.d.ts +2 -0
- package/stores/settings/useAppearance.js +7 -0
- package/stores/settings/useSetSettings.d.ts +5 -0
- package/stores/settings/useSetSettings.js +5 -0
- package/stores/settings/useSettings.d.ts +2 -0
- package/stores/settings/useSettings.js +8 -0
- package/stores/settings/useSettingsStore.d.ts +25 -0
- package/stores/settings/useSettingsStore.js +84 -0
- package/types/widget.d.ts +33 -24
- package/utils/format.d.ts +1 -1
- package/utils/format.js +1 -1
- package/utils/routes.d.ts +1 -0
- package/utils/routes.js +7 -6
- package/hooks/useBridges.d.ts +0 -1
- package/hooks/useBridges.js +0 -12
- package/hooks/useExchanges.d.ts +0 -1
- package/hooks/useExchanges.js +0 -12
- package/hooks/useRouteExecution/index.d.ts +0 -3
- package/hooks/useRouteExecution/index.js +0 -3
- package/hooks/useSettings/index.d.ts +0 -2
- package/hooks/useSettings/index.js +0 -2
- package/hooks/useSettings/types.d.ts +0 -5
- package/hooks/useSettings/types.js +0 -1
- package/hooks/useSettings/useSettingsStore.d.ts +0 -13
- package/hooks/useSettings/useSettingsStore.js +0 -22
- package/pages/MainPage/SendToRecipientForm.d.ts +0 -2
- package/pages/MainPage/SendToRecipientForm.js +0 -20
package/App.js
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
2
3
|
import { Route, Routes } from 'react-router-dom';
|
|
3
4
|
import { AppProvider } from './AppProvider';
|
|
4
5
|
import { AppContainer } from './components/AppContainer';
|
|
5
6
|
import { Header } from './components/Header';
|
|
7
|
+
import { Initializer } from './components/Initializer';
|
|
6
8
|
import { MainPage } from './pages/MainPage';
|
|
7
9
|
import { SelectTokenPage } from './pages/SelectTokenPage';
|
|
8
10
|
import { SelectWalletPage } from './pages/SelectWalletPage';
|
|
9
11
|
import { SettingsPage } from './pages/SettingsPage';
|
|
10
12
|
import { SwapPage } from './pages/SwapPage';
|
|
11
13
|
import { SwapRoutesPage } from './pages/SwapRoutesPage';
|
|
14
|
+
import { useWallet } from './providers/WalletProvider';
|
|
12
15
|
import { routes } from './utils/routes';
|
|
13
16
|
export const App = ({ config }) => {
|
|
14
17
|
return (_jsx(AppProvider, Object.assign({ config: config }, { children: _jsx(AppDefault, {}) })));
|
|
15
18
|
};
|
|
16
19
|
export const AppDefault = () => {
|
|
17
|
-
|
|
20
|
+
const { attemptEagerConnect } = useWallet();
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
attemptEagerConnect();
|
|
23
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
24
|
+
}, []);
|
|
25
|
+
return (_jsxs(AppContainer, { children: [_jsx(Header, {}), _jsxs(Routes, { children: [_jsx(Route, { path: routes.home, element: _jsx(MainPage, {}) }), _jsx(Route, { path: routes.selectWallet, element: _jsx(SelectWalletPage, {}) }), _jsx(Route, { path: routes.settings, element: _jsx(SettingsPage, {}) }), _jsx(Route, { path: routes.fromToken, element: _jsx(SelectTokenPage, { formType: "from" }) }), _jsx(Route, { path: routes.toToken, element: _jsx(SelectTokenPage, { formType: "to" }) }), _jsx(Route, { path: routes.swapRoutes, element: _jsx(SwapRoutesPage, {}) }), _jsx(Route, { path: `${routes.swapRoutes}/${routes.swap}`, element: _jsx(SwapPage, {}) }), _jsx(Route, { path: routes.swap, element: _jsx(SwapPage, {}) })] }), _jsx(Initializer, {})] }));
|
|
18
26
|
};
|
package/AppProvider.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/* eslint-disable camelcase */
|
|
3
|
+
/* eslint-disable react/jsx-pascal-case */
|
|
4
|
+
import { Fragment } from 'react';
|
|
2
5
|
import { QueryClientProvider } from 'react-query';
|
|
3
|
-
import { MemoryRouter } from 'react-router-dom';
|
|
6
|
+
import { MemoryRouter, useInRouterContext } from 'react-router-dom';
|
|
4
7
|
import { queryClient } from './config/queryClient';
|
|
5
8
|
import { SwapFormProvider } from './providers/SwapFormProvider';
|
|
6
9
|
import { ThemeProvider } from './providers/ThemeProvider';
|
|
@@ -8,5 +11,7 @@ import { WalletProvider } from './providers/WalletProvider';
|
|
|
8
11
|
import { WidgetProvider } from './providers/WidgetProvider';
|
|
9
12
|
const QueryProvider = QueryClientProvider;
|
|
10
13
|
export const AppProvider = ({ children, config, }) => {
|
|
11
|
-
|
|
14
|
+
const inRouterContext = useInRouterContext();
|
|
15
|
+
const Router = inRouterContext ? Fragment : MemoryRouter;
|
|
16
|
+
return (_jsx(WidgetProvider, Object.assign({ config: config }, { children: _jsx(ThemeProvider, { children: _jsx(QueryProvider, Object.assign({ client: queryClient }, { children: _jsx(Router, { children: _jsx(WalletProvider, { children: _jsx(SwapFormProvider, { children: children }) }) }) })) }) })));
|
|
12
17
|
};
|
|
@@ -12,6 +12,6 @@ const stickyHeaderRoutes = [
|
|
|
12
12
|
];
|
|
13
13
|
const HeaderContainer = ({ children }) => {
|
|
14
14
|
const { pathname } = useLocation();
|
|
15
|
-
return (_jsx(Container, Object.assign({ id: ElementId.Header, sticky: stickyHeaderRoutes.includes(
|
|
15
|
+
return (_jsx(Container, Object.assign({ id: ElementId.Header, sticky: stickyHeaderRoutes.some((route) => pathname.includes(route)) }, { children: children })));
|
|
16
16
|
};
|
|
17
17
|
export const Header = () => (_jsxs(HeaderContainer, { children: [_jsx(WalletHeader, {}), _jsx(NavigationHeader, {})] }));
|
|
@@ -3,7 +3,7 @@ import { ArrowBack as ArrowBackIcon, Settings as SettingsIcon, } from '@mui/icon
|
|
|
3
3
|
import { Box, IconButton, Typography } from '@mui/material';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
|
|
6
|
-
import { routes } from '../../utils/routes';
|
|
6
|
+
import { routes, routesValues } from '../../utils/routes';
|
|
7
7
|
import { SwapRoutesUpdateProgress } from '../SwapRoutes/SwapRoutesUpdateProgress';
|
|
8
8
|
import { HeaderAppBar } from './Header.style';
|
|
9
9
|
const backButtonRoutes = [
|
|
@@ -17,6 +17,8 @@ const backButtonRoutes = [
|
|
|
17
17
|
export const NavigationHeader = () => {
|
|
18
18
|
const { t } = useTranslation();
|
|
19
19
|
const { pathname } = useLocation();
|
|
20
|
+
const path = pathname.substring(pathname.lastIndexOf('/') + 1);
|
|
21
|
+
const hasPath = routesValues.includes(path);
|
|
20
22
|
const navigate = useNavigate();
|
|
21
23
|
const handleSettings = () => {
|
|
22
24
|
navigate(routes.settings);
|
|
@@ -25,7 +27,7 @@ export const NavigationHeader = () => {
|
|
|
25
27
|
navigate(-1);
|
|
26
28
|
};
|
|
27
29
|
const handleHeaderTitle = () => {
|
|
28
|
-
switch (
|
|
30
|
+
switch (path) {
|
|
29
31
|
case routes.selectWallet:
|
|
30
32
|
return t(`header.selectWallet`);
|
|
31
33
|
case routes.settings:
|
|
@@ -42,5 +44,5 @@ export const NavigationHeader = () => {
|
|
|
42
44
|
return t(`header.swap`);
|
|
43
45
|
}
|
|
44
46
|
};
|
|
45
|
-
return (_jsxs(HeaderAppBar, Object.assign({ elevation: 0 }, { children: [backButtonRoutes.includes(
|
|
47
|
+
return (_jsxs(HeaderAppBar, Object.assign({ elevation: 0 }, { children: [backButtonRoutes.includes(path) ? (_jsx(IconButton, Object.assign({ size: "medium", "aria-label": "settings", edge: "start", onClick: handleBack }, { children: _jsx(ArrowBackIcon, {}) }))) : null, _jsx(Typography, Object.assign({ fontSize: hasPath ? 24 : 32, align: hasPath ? 'center' : 'left', fontWeight: "700", flex: 1, noWrap: true }, { children: handleHeaderTitle() })), _jsxs(Routes, { children: [_jsx(Route, { path: routes.swapRoutes, element: _jsx(SwapRoutesUpdateProgress, { size: "medium", edge: "end", sx: { marginRight: -1 } }) }), _jsx(Route, { path: routes.home, element: _jsx(IconButton, Object.assign({ size: "medium", "aria-label": "settings", edge: "end", onClick: handleSettings }, { children: _jsx(SettingsIcon, {}) })) }), _jsx(Route, { path: "/:empty", element: _jsx(Box, { width: 28, height: 48 }) })] })] })));
|
|
46
48
|
};
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
1
10
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
11
|
import { AccountBalanceWallet as AccountBalanceWalletIcon, Logout as LogoutIcon, } from '@mui/icons-material';
|
|
3
12
|
import { Box, IconButton, Typography } from '@mui/material';
|
|
4
13
|
import { useTranslation } from 'react-i18next';
|
|
5
14
|
import { useLocation, useNavigate } from 'react-router-dom';
|
|
6
15
|
import { useWallet } from '../../providers/WalletProvider';
|
|
16
|
+
import { useWidgetConfig } from '../../providers/WidgetProvider';
|
|
7
17
|
import { routes } from '../../utils/routes';
|
|
8
18
|
import { HeaderAppBar } from './Header.style';
|
|
9
19
|
export const WalletHeader = () => {
|
|
@@ -20,9 +30,15 @@ export const WalletHeader = () => {
|
|
|
20
30
|
};
|
|
21
31
|
const ConnectButton = () => {
|
|
22
32
|
const { pathname } = useLocation();
|
|
33
|
+
const config = useWidgetConfig();
|
|
34
|
+
const { connect: walletConnect } = useWallet();
|
|
23
35
|
const navigate = useNavigate();
|
|
24
|
-
const connect = () => {
|
|
36
|
+
const connect = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
if (config.disableInternalWalletManagement) {
|
|
38
|
+
yield walletConnect();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
25
41
|
navigate(routes.selectWallet);
|
|
26
|
-
};
|
|
27
|
-
return (_jsx(IconButton, Object.assign({ size: "medium", "aria-label": "disconnect", edge: "end", onClick: pathname
|
|
42
|
+
});
|
|
43
|
+
return (_jsx(IconButton, Object.assign({ size: "medium", "aria-label": "disconnect", edge: "end", onClick: !pathname.includes(routes.selectWallet) ? connect : undefined }, { children: _jsx(AccountBalanceWalletIcon, {}) })));
|
|
28
44
|
};
|
package/components/StepToken.js
CHANGED
|
@@ -15,7 +15,7 @@ import { formatTokenAmount } from '../utils/format';
|
|
|
15
15
|
import { TextFitter } from './TextFitter';
|
|
16
16
|
export const StepToken = (_a) => {
|
|
17
17
|
var { token } = _a, other = __rest(_a, ["token"]);
|
|
18
|
-
return (_jsxs(Box, Object.assign({ flex: 1 }, other, { children: [_jsxs(Box, Object.assign({ display: "flex", flex: 1 }, { children: [_jsx(Avatar, Object.assign({ src: token.logoURI, alt: token.symbol, sx: { marginRight: 2 } }, { children: token.symbol[0] })), _jsx(TextFitter, Object.assign({
|
|
18
|
+
return (_jsxs(Box, Object.assign({ flex: 1 }, other, { children: [_jsxs(Box, Object.assign({ display: "flex", flex: 1 }, { children: [_jsx(Avatar, Object.assign({ src: token.logoURI, alt: token.symbol, sx: { marginRight: 2 } }, { children: token.symbol[0] })), _jsx(TextFitter, Object.assign({ height: 32, textStyle: {
|
|
19
19
|
fontWeight: 700,
|
|
20
20
|
} }, { children: formatTokenAmount(token.amount, token.decimals) }))] })), _jsx(Typography, Object.assign({ fontSize: 14, lineHeight: 1, fontWeight: "500", color: "text.secondary", mr: 1, ml: 6 }, { children: token.symbol }))] })));
|
|
21
21
|
};
|
|
@@ -12,9 +12,10 @@ import { ChainId } from '@lifinance/sdk';
|
|
|
12
12
|
import { useWatch } from 'react-hook-form';
|
|
13
13
|
import { useTranslation } from 'react-i18next';
|
|
14
14
|
import { useNavigate } from 'react-router-dom';
|
|
15
|
-
import { useChains,
|
|
15
|
+
import { useChains, useHasSufficientBalance, useSwapRoutes } from '../../hooks';
|
|
16
16
|
import { SwapFormKeyHelper } from '../../providers/SwapFormProvider';
|
|
17
17
|
import { useWallet } from '../../providers/WalletProvider';
|
|
18
|
+
import { useCurrentRoute, useSetExecutableRoute } from '../../stores';
|
|
18
19
|
import { routes } from '../../utils/routes';
|
|
19
20
|
import { ButtonTooltip } from './ButtonTooltip';
|
|
20
21
|
import { Button } from './SwapButton.style';
|
|
@@ -43,7 +44,9 @@ export const SwapButton = () => {
|
|
|
43
44
|
else if (currentRoute &&
|
|
44
45
|
(swapRoutes === null || swapRoutes === void 0 ? void 0 : swapRoutes.some((route) => route.id === currentRoute.id))) {
|
|
45
46
|
setExecutableRoute(currentRoute);
|
|
46
|
-
navigate(routes.swap, {
|
|
47
|
+
navigate(routes.swap, {
|
|
48
|
+
state: { routeId: currentRoute.id },
|
|
49
|
+
});
|
|
47
50
|
}
|
|
48
51
|
});
|
|
49
52
|
const getButtonText = () => {
|
|
@@ -4,7 +4,7 @@ import { AvatarGroup, Box, Stack } from '@mui/material';
|
|
|
4
4
|
import { useCallback } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { useNavigate } from 'react-router-dom';
|
|
7
|
-
import { useExecutingRoutes } from '../../
|
|
7
|
+
import { useExecutingRoutes } from '../../stores';
|
|
8
8
|
import { routes } from '../../utils/routes';
|
|
9
9
|
import { CardTitle } from '../Card';
|
|
10
10
|
import { Card, RouteAvatar, RouteCard } from './SwapInProgress.style';
|
|
@@ -5,7 +5,8 @@ import { Box, IconButton, Skeleton } from '@mui/material';
|
|
|
5
5
|
import { useCallback } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { useNavigate } from 'react-router-dom';
|
|
8
|
-
import {
|
|
8
|
+
import { useSwapRoutes } from '../../hooks';
|
|
9
|
+
import { useCurrentRoute } from '../../stores';
|
|
9
10
|
import { routes } from '../../utils/routes';
|
|
10
11
|
import { CardContainer, CardTitle } from '../Card';
|
|
11
12
|
import { SwapRouteCard } from '../SwapRouteCard';
|
|
@@ -11,7 +11,7 @@ export const TextFitter = ({ children, width = '100%', height, maxHeight, preser
|
|
|
11
11
|
const theme = useTheme();
|
|
12
12
|
const textRef = useRef(null);
|
|
13
13
|
const [viewBox, setViewBox] = useState(initialState);
|
|
14
|
-
const [textRect, setTextRect] = useState(initialState);
|
|
14
|
+
// const [textRect, setTextRect] = useState<Partial<DOMRect>>(initialState);
|
|
15
15
|
const calculateBox = useCallback(() => {
|
|
16
16
|
if (!textRef.current) {
|
|
17
17
|
return;
|
|
@@ -25,7 +25,7 @@ export const TextFitter = ({ children, width = '100%', height, maxHeight, preser
|
|
|
25
25
|
box.height -= box.height * cropBottom;
|
|
26
26
|
}
|
|
27
27
|
setViewBox(box);
|
|
28
|
-
setTextRect(textRef.current.getBoundingClientRect());
|
|
28
|
+
// setTextRect(textRef.current.getBoundingClientRect());
|
|
29
29
|
onFit === null || onFit === void 0 ? void 0 : onFit();
|
|
30
30
|
}, [cropBottom, cropTop, onFit]);
|
|
31
31
|
useLayoutEffect(() => {
|
|
@@ -38,7 +38,11 @@ export const TextFitter = ({ children, width = '100%', height, maxHeight, preser
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
}, [calculateBox]);
|
|
41
|
-
return (_jsx("svg", Object.assign({ style: svgStyle, viewBox: `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`, width: width, height:
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
return (_jsx("svg", Object.assign({ style: svgStyle, viewBox: `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`, width: width, height: height,
|
|
42
|
+
// height={
|
|
43
|
+
// textRect.height && maxHeight && textRect.height >= maxHeight
|
|
44
|
+
// ? maxHeight
|
|
45
|
+
// : height
|
|
46
|
+
// }
|
|
47
|
+
preserveAspectRatio: preserveAspectRatio, fill: theme.palette.text.primary }, { children: _jsx("text", Object.assign({ x: 0, y: 0, style: textStyle, ref: textRef }, { children: children })) })));
|
|
44
48
|
};
|
package/hooks/index.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
export * from './useBridges';
|
|
2
1
|
export * from './useChain';
|
|
3
2
|
export * from './useChains';
|
|
4
3
|
export * from './useContentHeight';
|
|
5
4
|
export * from './useDebouncedWatch';
|
|
6
|
-
export * from './useExchanges';
|
|
7
5
|
export * from './useHasSufficientBalance';
|
|
8
6
|
export * from './useRouteExecution';
|
|
9
7
|
export * from './useScrollableContainer';
|
|
10
|
-
export * from './useSettings';
|
|
11
8
|
export * from './useSwapRoutes';
|
|
12
9
|
export * from './useToken';
|
|
13
10
|
export * from './useTokenBalance';
|
|
14
11
|
export * from './useTokenBalances';
|
|
15
12
|
export * from './useTokens';
|
|
13
|
+
export * from './useTools';
|
package/hooks/index.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
export * from './useBridges';
|
|
2
1
|
export * from './useChain';
|
|
3
2
|
export * from './useChains';
|
|
4
3
|
export * from './useContentHeight';
|
|
5
4
|
export * from './useDebouncedWatch';
|
|
6
|
-
export * from './useExchanges';
|
|
7
5
|
export * from './useHasSufficientBalance';
|
|
8
6
|
export * from './useRouteExecution';
|
|
9
7
|
export * from './useScrollableContainer';
|
|
10
|
-
export * from './useSettings';
|
|
11
8
|
export * from './useSwapRoutes';
|
|
12
9
|
export * from './useToken';
|
|
13
10
|
export * from './useTokenBalance';
|
|
14
11
|
export * from './useTokenBalances';
|
|
15
12
|
export * from './useTokens';
|
|
13
|
+
export * from './useTools';
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useLayoutEffect, useState } from 'react';
|
|
2
2
|
import { ElementId } from '../utils/elements';
|
|
3
|
+
const getContentHeight = () => {
|
|
4
|
+
const headerElement = document.getElementById(ElementId.Header);
|
|
5
|
+
const containerElement = document.getElementById(ElementId.ScrollableContainer);
|
|
6
|
+
if (!containerElement || !headerElement) {
|
|
7
|
+
console.warn(`Can't find ${ElementId.ScrollableContainer} or ${ElementId.Header} id.`);
|
|
8
|
+
return 0;
|
|
9
|
+
}
|
|
10
|
+
const { height: containerHeight } = containerElement.getBoundingClientRect();
|
|
11
|
+
const { height: headerHeight } = headerElement.getBoundingClientRect();
|
|
12
|
+
return containerHeight - headerHeight;
|
|
13
|
+
};
|
|
3
14
|
export const useContentHeight = () => {
|
|
4
|
-
const [contentHeight] = useState(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
throw Error(`Can't find ${ElementId.ScrollableContainer} or ${ElementId.Header} id.`);
|
|
15
|
+
const [contentHeight, setContentHeight] = useState(getContentHeight);
|
|
16
|
+
useLayoutEffect(() => {
|
|
17
|
+
if (!contentHeight) {
|
|
18
|
+
setContentHeight(getContentHeight());
|
|
9
19
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return containerHeight - headerHeight;
|
|
13
|
-
});
|
|
20
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21
|
+
}, []);
|
|
14
22
|
return contentHeight;
|
|
15
23
|
};
|
|
@@ -3,7 +3,7 @@ import Big from 'big.js';
|
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
4
|
import { useWatch } from 'react-hook-form';
|
|
5
5
|
import { SwapFormKeyHelper } from '../providers/SwapFormProvider';
|
|
6
|
-
import { useCurrentRoute } from '
|
|
6
|
+
import { useCurrentRoute } from '../stores';
|
|
7
7
|
import { useTokenBalances } from './useTokenBalances';
|
|
8
8
|
export const useHasSufficientBalance = () => {
|
|
9
9
|
var _a;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useInitializer: () => void;
|
|
@@ -10,13 +10,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { useCallback, useEffect } from 'react';
|
|
11
11
|
import { useMutation } from 'react-query';
|
|
12
12
|
import shallow from 'zustand/shallow';
|
|
13
|
-
import { LiFi } from '
|
|
14
|
-
import { useWallet } from '
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
13
|
+
import { LiFi } from '../lifi';
|
|
14
|
+
import { useWallet } from '../providers/WalletProvider';
|
|
15
|
+
import { useRouteStore } from '../stores';
|
|
16
|
+
import { deepClone } from '../utils/deepClone';
|
|
17
17
|
export const useRouteExecution = (routeId) => {
|
|
18
18
|
const { account, switchChain } = useWallet();
|
|
19
|
-
const { route, status } = useRouteStore((state) => state.routes[routeId]);
|
|
19
|
+
const { route, status } = useRouteStore((state) => { var _a; return (_a = state.routes[routeId]) !== null && _a !== void 0 ? _a : {}; });
|
|
20
20
|
const [updateRoute, restartRoute, removeRoute] = useRouteStore((state) => [state.updateRoute, state.restartRoute, state.removeRoute], shallow);
|
|
21
21
|
const updateCallback = (updatedRoute) => {
|
|
22
22
|
console.log('Route updated.', updatedRoute);
|
package/hooks/useSwapRoutes.js
CHANGED
|
@@ -14,23 +14,25 @@ import { useDebouncedWatch, useToken } from '.';
|
|
|
14
14
|
import { LiFi } from '../lifi';
|
|
15
15
|
import { SwapFormKey } from '../providers/SwapFormProvider';
|
|
16
16
|
import { useWallet } from '../providers/WalletProvider';
|
|
17
|
-
import { useCurrentRoute } from '
|
|
17
|
+
import { useCurrentRoute, useSettings } from '../stores';
|
|
18
18
|
const refetchTime = 60000;
|
|
19
19
|
export const useSwapRoutes = () => {
|
|
20
20
|
var _a;
|
|
21
21
|
const { account } = useWallet();
|
|
22
22
|
const queryClient = useQueryClient();
|
|
23
23
|
const [currentRoute, setCurrentRoute] = useCurrentRoute();
|
|
24
|
-
const
|
|
24
|
+
const { slippage, enabledBridges, enabledExchanges, routePriority } = useSettings([
|
|
25
|
+
'slippage',
|
|
26
|
+
'routePriority',
|
|
27
|
+
'enabledBridges',
|
|
28
|
+
'enabledExchanges',
|
|
29
|
+
]);
|
|
30
|
+
const [fromChainId, fromTokenAddress, toChainId, toTokenAddress] = useWatch({
|
|
25
31
|
name: [
|
|
26
32
|
SwapFormKey.FromChain,
|
|
27
33
|
SwapFormKey.FromToken,
|
|
28
34
|
SwapFormKey.ToChain,
|
|
29
35
|
SwapFormKey.ToToken,
|
|
30
|
-
SwapFormKey.Slippage,
|
|
31
|
-
SwapFormKey.EnabledBridges,
|
|
32
|
-
SwapFormKey.EnabledExchanges,
|
|
33
|
-
SwapFormKey.RoutePriority,
|
|
34
36
|
],
|
|
35
37
|
});
|
|
36
38
|
const [fromTokenAmount] = useDebouncedWatch([SwapFormKey.FromAmount], 500);
|
|
@@ -42,7 +44,7 @@ export const useSwapRoutes = () => {
|
|
|
42
44
|
Boolean(toTokenAddress) &&
|
|
43
45
|
Boolean(fromTokenAmount) &&
|
|
44
46
|
!isNaN(fromTokenAmount) &&
|
|
45
|
-
!isNaN(slippage);
|
|
47
|
+
!Number.isNaN(slippage);
|
|
46
48
|
const queryKey = [
|
|
47
49
|
'routes',
|
|
48
50
|
account.address,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useTools: () => import("@lifinance/types").ToolsResponse | undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
import { useQuery } from 'react-query';
|
|
3
|
+
import { LiFi } from '../lifi';
|
|
4
|
+
import { useSettingsStore } from '../stores';
|
|
5
|
+
export const useTools = () => {
|
|
6
|
+
const initializeTools = useSettingsStore((state) => state.initializeTools);
|
|
7
|
+
const { data } = useQuery(['tools'], ({ signal }) => LiFi.getTools(undefined, { signal }), {
|
|
8
|
+
onSuccess(data) {
|
|
9
|
+
initializeTools('Bridges', data.bridges.map((bridge) => bridge.key));
|
|
10
|
+
initializeTools('Exchanges', data.exchanges.map((exchange) => exchange.key));
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
return data;
|
|
14
|
+
};
|
package/i18n/en/translation.json
CHANGED
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"approximateCurrency": "\u2248 {{value, currency(currency: USD)}}",
|
|
38
38
|
"currency": "{{value, currency(currency: USD)}}",
|
|
39
39
|
"sendToRecipient": "Send to recipient",
|
|
40
|
-
"recipientsAddress": "Recipient's {{chain}} address",
|
|
41
40
|
"addressConfirmation": "I confirm that the address above is correct",
|
|
42
41
|
"gas": "gas fee",
|
|
43
42
|
"minutes": "minutes",
|
|
@@ -126,7 +125,6 @@
|
|
|
126
125
|
"fast": "Fast"
|
|
127
126
|
},
|
|
128
127
|
"advancedPreferences": "Advanced preferences",
|
|
129
|
-
"bridgePrioritization": "Bridge prioritization",
|
|
130
128
|
"enabledBridges": "Enabled bridges",
|
|
131
129
|
"selectEnabledBridges": "Select enabled bridges",
|
|
132
130
|
"enabledExchanges": "Enabled exchanges",
|
package/i18n/index.d.ts
CHANGED
|
@@ -40,7 +40,6 @@ export declare const resources: {
|
|
|
40
40
|
approximateCurrency: string;
|
|
41
41
|
currency: string;
|
|
42
42
|
sendToRecipient: string;
|
|
43
|
-
recipientsAddress: string;
|
|
44
43
|
addressConfirmation: string;
|
|
45
44
|
gas: string;
|
|
46
45
|
minutes: string;
|
|
@@ -129,7 +128,6 @@ export declare const resources: {
|
|
|
129
128
|
fast: string;
|
|
130
129
|
};
|
|
131
130
|
advancedPreferences: string;
|
|
132
|
-
bridgePrioritization: string;
|
|
133
131
|
enabledBridges: string;
|
|
134
132
|
selectEnabledBridges: string;
|
|
135
133
|
enabledExchanges: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/widget",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./index.js",
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"lifi"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@emotion/react": "^11.9.
|
|
41
|
-
"@emotion/styled": "^11.
|
|
40
|
+
"@emotion/react": "^11.9.3",
|
|
41
|
+
"@emotion/styled": "^11.9.3",
|
|
42
42
|
"@ethersproject/experimental": "^5.6.2",
|
|
43
43
|
"@ethersproject/providers": "^5.6.8",
|
|
44
|
-
"@lifi/wallet-management": "^1.0.
|
|
44
|
+
"@lifi/wallet-management": "^1.0.3",
|
|
45
45
|
"@lifinance/sdk": "^1.0.0-beta.11",
|
|
46
46
|
"@mui/icons-material": "^5.8.3",
|
|
47
47
|
"@mui/lab": "^5.0.0-alpha.85",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"immer": "^9.0.14",
|
|
52
52
|
"react": "^18.1.0",
|
|
53
53
|
"react-dom": "^18.1.0",
|
|
54
|
-
"react-hook-form": "^7.
|
|
55
|
-
"react-i18next": "^11.
|
|
54
|
+
"react-hook-form": "^7.32.0",
|
|
55
|
+
"react-i18next": "^11.17.1",
|
|
56
56
|
"react-query": "^4.0.0-beta.23",
|
|
57
57
|
"react-resize-detector": "^7.1.1",
|
|
58
58
|
"react-router-dom": "^6.3.0",
|
|
@@ -21,5 +21,5 @@ export const ChainSelect = ({ formType }) => {
|
|
|
21
21
|
setValue(SwapFormKeyHelper.getTokenKey(formType), '');
|
|
22
22
|
setValue(SwapFormKeyHelper.getAmountKey(formType), '');
|
|
23
23
|
};
|
|
24
|
-
return !isLoading ? (_jsxs(CardContainer, { children: [_jsx(CardTitle, { children: t(`swap.selectChain`) }), _jsx(FormControl, Object.assign({ fullWidth: true }, { children: _jsx(Select, Object.assign({ labelId: "label", MenuProps: { elevation: 2 }, defaultValue: formType === 'from' ? fromChain : toChain, value: chainId, onChange: handleChain, IconComponent: KeyboardArrowDownIcon }, { children: chains === null || chains === void 0 ? void 0 : chains.map((chain) => (_jsxs(MenuItem, Object.assign({ value: chain.id }, { children: [_jsx(ListItemAvatar, { children: _jsx(Avatar, Object.assign({ src: chain.logoURI, alt: chain.key }, { children: chain.name[0] })) }), chain.name] }), chain.key))) })) }))] })) : (_jsx(Skeleton, { variant: "rectangular", width: "100%", height:
|
|
24
|
+
return !isLoading ? (_jsxs(CardContainer, { children: [_jsx(CardTitle, { children: t(`swap.selectChain`) }), _jsx(FormControl, Object.assign({ fullWidth: true }, { children: _jsx(Select, Object.assign({ labelId: "label", MenuProps: { elevation: 2 }, defaultValue: formType === 'from' ? fromChain : toChain, value: chainId, onChange: handleChain, IconComponent: KeyboardArrowDownIcon }, { children: chains === null || chains === void 0 ? void 0 : chains.map((chain) => (_jsxs(MenuItem, Object.assign({ value: chain.id }, { children: [_jsx(ListItemAvatar, { children: _jsx(Avatar, Object.assign({ src: chain.logoURI, alt: chain.key }, { children: chain.name[0] })) }), chain.name] }), chain.key))) })) }))] })) : (_jsx(Skeleton, { variant: "rectangular", width: "100%", height: 98, sx: { borderRadius: 1 } }));
|
|
25
25
|
};
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Typography } from '@mui/material';
|
|
3
|
-
import { useState } from 'react';
|
|
4
3
|
import { useTranslation } from 'react-i18next';
|
|
5
4
|
import { Switch } from '../../components/Switch';
|
|
5
|
+
import { useSetSettings, useSettings } from '../../stores';
|
|
6
6
|
import { EnabledBridgesSelect } from './EnabledBridgesSelect';
|
|
7
7
|
import { EnabledExchangesSelect } from './EnabledExchangesSelect';
|
|
8
8
|
export const AdvancedPreferences = () => {
|
|
9
9
|
const { t } = useTranslation();
|
|
10
|
-
const [
|
|
10
|
+
const [setValue] = useSetSettings();
|
|
11
|
+
const { advancedPreferences } = useSettings(['advancedPreferences']);
|
|
11
12
|
const handleAdvancedPreferences = (_, checked) => {
|
|
12
|
-
|
|
13
|
+
setValue('advancedPreferences', checked);
|
|
13
14
|
};
|
|
14
15
|
return (_jsxs(Box, Object.assign({ p: 3 }, { children: [_jsxs(Box, Object.assign({ sx: {
|
|
15
16
|
display: 'flex',
|
|
16
17
|
justifyContent: 'space-between',
|
|
17
18
|
alignItems: 'center',
|
|
18
|
-
} }, { children: [_jsx(Box, Object.assign({ sx: { display: 'flex', alignItems: 'center' } }, { children: _jsx(Typography, Object.assign({ variant: "subtitle1", color: "text.primary", lineHeight: "normal" }, { children: t(`settings.advancedPreferences`) })) })), _jsx(Switch, {
|
|
19
|
+
} }, { children: [_jsx(Box, Object.assign({ sx: { display: 'flex', alignItems: 'center' } }, { children: _jsx(Typography, Object.assign({ variant: "subtitle1", color: "text.primary", lineHeight: "normal" }, { children: t(`settings.advancedPreferences`) })) })), _jsx(Switch, { checked: advancedPreferences, onChange: handleAdvancedPreferences })] })), advancedPreferences && (_jsxs(Box, Object.assign({ mt: 3, mb: 1 }, { children: [_jsx(EnabledBridgesSelect, {}), _jsx(Box, Object.assign({ mt: 2 }, { children: _jsx(EnabledExchangesSelect, {}) }))] })))] })));
|
|
19
20
|
};
|
|
@@ -2,8 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Brightness4 as Brightness4Icon, DarkMode as DarkModeIcon, LightMode as LightModeIcon, } from '@mui/icons-material';
|
|
3
3
|
import { Box, ToggleButtonGroup } from '@mui/material';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
import { useAppearance } from '../../hooks';
|
|
6
5
|
import { useWidgetConfig } from '../../providers/WidgetProvider';
|
|
6
|
+
import { useAppearance } from '../../stores';
|
|
7
7
|
import { ToggleButton } from './ColorSchemeButtonGroup.style';
|
|
8
8
|
export const ColorSchemeButtonGroup = () => {
|
|
9
9
|
const { t } = useTranslation();
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { KeyboardArrowDown as KeyboardArrowDownIcon } from '@mui/icons-material';
|
|
3
3
|
import { Box, Chip, FormControl, MenuItem, Skeleton } from '@mui/material';
|
|
4
|
-
import { useFormContext } from 'react-hook-form';
|
|
5
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import shallow from 'zustand/shallow';
|
|
6
6
|
import { CardContainer, CardTitle } from '../../components/Card';
|
|
7
7
|
import { Select } from '../../components/Select';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { useTools } from '../../hooks';
|
|
9
|
+
import { useSettingsStore } from '../../stores';
|
|
10
10
|
export const EnabledBridgesSelect = () => {
|
|
11
|
+
var _a;
|
|
11
12
|
const { t } = useTranslation();
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
return bridges.length ? (_jsxs(CardContainer, { children: [_jsx(CardTitle, { children: t(`settings.enabledBridges`) }), _jsx(FormControl, Object.assign({ fullWidth: true }, { children: _jsx(Select, Object.assign({ multiple: true, placeholder: t(`settings.selectEnabledBridges`),
|
|
13
|
+
const tools = useTools();
|
|
14
|
+
const [enabledBridges, setTools] = useSettingsStore((state) => [state.enabledBridges, state.setTools], shallow);
|
|
15
|
+
return (tools === null || tools === void 0 ? void 0 : tools.bridges.length) ? (_jsxs(CardContainer, { children: [_jsx(CardTitle, { children: t(`settings.enabledBridges`) }), _jsx(FormControl, Object.assign({ fullWidth: true }, { children: _jsx(Select, Object.assign({ multiple: true, placeholder: t(`settings.selectEnabledBridges`), MenuProps: { elevation: 2 }, IconComponent: KeyboardArrowDownIcon, value: enabledBridges !== null && enabledBridges !== void 0 ? enabledBridges : [], onChange: (event) => {
|
|
16
|
+
if (tools === null || tools === void 0 ? void 0 : tools.bridges) {
|
|
17
|
+
setTools('Bridges', event.target.value, tools.bridges);
|
|
18
|
+
}
|
|
19
|
+
}, renderValue: (selected) => (_jsx(Box, Object.assign({ sx: { display: 'flex', flexWrap: 'wrap', gap: 0.5 } }, { children: selected.map((value) => (_jsx(Chip, { label: value }, value))) }))) }, { children: (_a = tools === null || tools === void 0 ? void 0 : tools.bridges) === null || _a === void 0 ? void 0 : _a.map((bridge) => (_jsx(MenuItem, Object.assign({ value: bridge.key }, { children: bridge.key }), bridge.key))) })) }))] })) : (_jsx(Skeleton, { variant: "rectangular", width: "100%", height: 134, sx: { borderRadius: 1 } }));
|
|
15
20
|
};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { KeyboardArrowDown as KeyboardArrowDownIcon } from '@mui/icons-material';
|
|
3
3
|
import { Box, Chip, FormControl, MenuItem, Skeleton } from '@mui/material';
|
|
4
|
-
import { useFormContext } from 'react-hook-form';
|
|
5
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import shallow from 'zustand/shallow';
|
|
6
6
|
import { CardContainer, CardTitle } from '../../components/Card';
|
|
7
7
|
import { Select } from '../../components/Select';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { useTools } from '../../hooks';
|
|
9
|
+
import { useSettingsStore } from '../../stores';
|
|
10
10
|
export const EnabledExchangesSelect = () => {
|
|
11
11
|
const { t } = useTranslation();
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
return exchanges.length ? (_jsxs(CardContainer, { children: [_jsx(CardTitle, { children: t(`settings.enabledExchanges`) }), _jsx(FormControl, Object.assign({ fullWidth: true }, { children: _jsx(Select, Object.assign({ multiple: true, placeholder: t(`settings.selectEnabledExchanges`),
|
|
12
|
+
const tools = useTools();
|
|
13
|
+
const [enabledExchanges, setTools] = useSettingsStore((state) => [state.enabledExchanges, state.setTools], shallow);
|
|
14
|
+
return (tools === null || tools === void 0 ? void 0 : tools.exchanges.length) ? (_jsxs(CardContainer, { children: [_jsx(CardTitle, { children: t(`settings.enabledExchanges`) }), _jsx(FormControl, Object.assign({ fullWidth: true }, { children: _jsx(Select, Object.assign({ multiple: true, placeholder: t(`settings.selectEnabledExchanges`), value: enabledExchanges !== null && enabledExchanges !== void 0 ? enabledExchanges : [], onChange: (event) => {
|
|
15
|
+
if (tools === null || tools === void 0 ? void 0 : tools.exchanges) {
|
|
16
|
+
setTools('Exchanges', event.target.value, tools.exchanges);
|
|
17
|
+
}
|
|
18
|
+
}, MenuProps: { elevation: 2 }, IconComponent: KeyboardArrowDownIcon, renderValue: (selected) => (_jsx(Box, Object.assign({ sx: { display: 'flex', flexWrap: 'wrap', gap: 0.5 } }, { children: selected.map((value) => (_jsx(Chip, { label: value }, value))) }))) }, { children: tools === null || tools === void 0 ? void 0 : tools.exchanges.map((exchange) => (_jsx(MenuItem, Object.assign({ value: exchange.key }, { children: exchange.key }), exchange.key))) })) }))] })) : (_jsx(Skeleton, { variant: "rectangular", width: "100%", height: 206, sx: { borderRadius: 1 } }));
|
|
15
19
|
};
|