feat(trading): use mini scroll in deal ticket, market info for and landing dialog (#3269)
This commit is contained in:
parent
e8adff25c4
commit
58c6652e29
@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
|
|||||||
import { useMarketList } from '@vegaprotocol/market-list';
|
import { useMarketList } from '@vegaprotocol/market-list';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
import { Link as UILink } from '@vegaprotocol/ui-toolkit';
|
import { Link as UILink, TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { OnCellClickHandler } from '../select-market';
|
import type { OnCellClickHandler } from '../select-market';
|
||||||
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
import type { MarketMaybeWithDataAndCandles } from '@vegaprotocol/market-list';
|
||||||
import {
|
import {
|
||||||
@ -55,8 +55,8 @@ export const SelectMarketLandingTable = ({
|
|||||||
const showProposed = (markets?.length || 0) <= 5;
|
const showProposed = (markets?.length || 0) <= 5;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<TinyScroll
|
||||||
className="max-h-[60vh] overflow-x-auto"
|
className="max-h-[60vh] overflow-x-auto -mr-4 pr-4"
|
||||||
data-testid="select-market-list"
|
data-testid="select-market-list"
|
||||||
>
|
>
|
||||||
<p className="text-neutral-500 dark:text-neutral-400 mb-4">
|
<p className="text-neutral-500 dark:text-neutral-400 mb-4">
|
||||||
@ -78,7 +78,7 @@ export const SelectMarketLandingTable = ({
|
|||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</TinyScroll>
|
||||||
<div className="mt-4 text-md">
|
<div className="mt-4 text-md">
|
||||||
<Link
|
<Link
|
||||||
to={Links[Routes.MARKETS]()}
|
to={Links[Routes.MARKETS]()}
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
InputError,
|
InputError,
|
||||||
Intent,
|
Intent,
|
||||||
Notification,
|
Notification,
|
||||||
|
TinyScroll,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -160,136 +161,140 @@ export const DealTicket = ({
|
|||||||
if (!order || !normalizedOrder) return null;
|
if (!order || !normalizedOrder) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<TinyScroll className="h-full overflow-auto">
|
||||||
onSubmit={isReadOnly ? undefined : handleSubmit(onSubmit)}
|
<form
|
||||||
className="p-4"
|
onSubmit={isReadOnly ? undefined : handleSubmit(onSubmit)}
|
||||||
noValidate
|
className="p-4"
|
||||||
>
|
noValidate
|
||||||
<Controller
|
>
|
||||||
name="type"
|
<Controller
|
||||||
control={control}
|
name="type"
|
||||||
rules={{
|
control={control}
|
||||||
validate: validateType(
|
rules={{
|
||||||
marketData.marketTradingMode,
|
validate: validateType(
|
||||||
marketData.trigger
|
marketData.marketTradingMode,
|
||||||
),
|
marketData.trigger
|
||||||
}}
|
),
|
||||||
render={() => (
|
}}
|
||||||
<TypeSelector
|
render={() => (
|
||||||
value={order.type}
|
<TypeSelector
|
||||||
onSelect={(type) => {
|
value={order.type}
|
||||||
if (type === OrderType.TYPE_NETWORK) return;
|
onSelect={(type) => {
|
||||||
update({
|
if (type === OrderType.TYPE_NETWORK) return;
|
||||||
type,
|
update({
|
||||||
// when changing type also update the tif to what was last used of new type
|
type,
|
||||||
timeInForce: lastTIF[type] || order.timeInForce,
|
// when changing type also update the tif to what was last used of new type
|
||||||
expiresAt: undefined,
|
timeInForce: lastTIF[type] || order.timeInForce,
|
||||||
});
|
expiresAt: undefined,
|
||||||
clearErrors('expiresAt');
|
});
|
||||||
}}
|
clearErrors('expiresAt');
|
||||||
market={market}
|
}}
|
||||||
marketData={marketData}
|
market={market}
|
||||||
errorMessage={errors.type?.message}
|
marketData={marketData}
|
||||||
/>
|
errorMessage={errors.type?.message}
|
||||||
)}
|
/>
|
||||||
/>
|
)}
|
||||||
<Controller
|
/>
|
||||||
name="side"
|
<Controller
|
||||||
control={control}
|
name="side"
|
||||||
render={() => (
|
control={control}
|
||||||
<SideSelector
|
render={() => (
|
||||||
value={order.side}
|
<SideSelector
|
||||||
onSelect={(side) => {
|
value={order.side}
|
||||||
update({ side });
|
onSelect={(side) => {
|
||||||
}}
|
update({ side });
|
||||||
/>
|
}}
|
||||||
)}
|
/>
|
||||||
/>
|
)}
|
||||||
<DealTicketAmount
|
/>
|
||||||
control={control}
|
<DealTicketAmount
|
||||||
orderType={order.type}
|
control={control}
|
||||||
market={market}
|
orderType={order.type}
|
||||||
marketData={marketData}
|
market={market}
|
||||||
sizeError={errors.size?.message}
|
marketData={marketData}
|
||||||
priceError={errors.price?.message}
|
sizeError={errors.size?.message}
|
||||||
update={update}
|
priceError={errors.price?.message}
|
||||||
size={order.size}
|
update={update}
|
||||||
price={order.price}
|
size={order.size}
|
||||||
/>
|
price={order.price}
|
||||||
<Controller
|
/>
|
||||||
name="timeInForce"
|
<Controller
|
||||||
control={control}
|
name="timeInForce"
|
||||||
rules={{
|
control={control}
|
||||||
validate: validateTimeInForce(
|
rules={{
|
||||||
marketData.marketTradingMode,
|
validate: validateTimeInForce(
|
||||||
marketData.trigger
|
marketData.marketTradingMode,
|
||||||
),
|
marketData.trigger
|
||||||
}}
|
),
|
||||||
render={() => (
|
}}
|
||||||
<TimeInForceSelector
|
render={() => (
|
||||||
value={order.timeInForce}
|
<TimeInForceSelector
|
||||||
orderType={order.type}
|
value={order.timeInForce}
|
||||||
onSelect={(timeInForce) => {
|
orderType={order.type}
|
||||||
update({ timeInForce });
|
onSelect={(timeInForce) => {
|
||||||
// Set tif value for the given order type, so that when switching
|
update({ timeInForce });
|
||||||
// types we know the last used TIF for the given order type
|
// Set tif value for the given order type, so that when switching
|
||||||
setLastTIF((curr) => ({
|
// types we know the last used TIF for the given order type
|
||||||
...curr,
|
setLastTIF((curr) => ({
|
||||||
[order.type]: timeInForce,
|
...curr,
|
||||||
expiresAt: undefined,
|
[order.type]: timeInForce,
|
||||||
}));
|
expiresAt: undefined,
|
||||||
clearErrors('expiresAt');
|
}));
|
||||||
}}
|
clearErrors('expiresAt');
|
||||||
market={market}
|
}}
|
||||||
marketData={marketData}
|
market={market}
|
||||||
errorMessage={errors.timeInForce?.message}
|
marketData={marketData}
|
||||||
/>
|
errorMessage={errors.timeInForce?.message}
|
||||||
)}
|
/>
|
||||||
/>
|
)}
|
||||||
{order.type === Schema.OrderType.TYPE_LIMIT &&
|
/>
|
||||||
order.timeInForce === Schema.OrderTimeInForce.TIME_IN_FORCE_GTT && (
|
{order.type === Schema.OrderType.TYPE_LIMIT &&
|
||||||
<Controller
|
order.timeInForce === Schema.OrderTimeInForce.TIME_IN_FORCE_GTT && (
|
||||||
name="expiresAt"
|
<Controller
|
||||||
control={control}
|
name="expiresAt"
|
||||||
rules={{
|
control={control}
|
||||||
validate: validateExpiration,
|
rules={{
|
||||||
}}
|
validate: validateExpiration,
|
||||||
render={() => (
|
}}
|
||||||
<ExpirySelector
|
render={() => (
|
||||||
value={order.expiresAt}
|
<ExpirySelector
|
||||||
onSelect={(expiresAt) =>
|
value={order.expiresAt}
|
||||||
update({
|
onSelect={(expiresAt) =>
|
||||||
expiresAt: expiresAt || undefined,
|
update({
|
||||||
})
|
expiresAt: expiresAt || undefined,
|
||||||
}
|
})
|
||||||
errorMessage={errors.expiresAt?.message}
|
}
|
||||||
/>
|
errorMessage={errors.expiresAt?.message}
|
||||||
)}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
/>
|
||||||
<SummaryMessage
|
)}
|
||||||
errorMessage={errors.summary?.message}
|
<SummaryMessage
|
||||||
asset={asset}
|
errorMessage={errors.summary?.message}
|
||||||
marketTradingMode={marketData.marketTradingMode}
|
asset={asset}
|
||||||
balance={balance}
|
marketTradingMode={marketData.marketTradingMode}
|
||||||
margin={totalMargin}
|
balance={balance}
|
||||||
isReadOnly={isReadOnly}
|
margin={totalMargin}
|
||||||
pubKey={pubKey}
|
isReadOnly={isReadOnly}
|
||||||
onClickCollateral={onClickCollateral}
|
pubKey={pubKey}
|
||||||
/>
|
onClickCollateral={onClickCollateral}
|
||||||
<DealTicketButton
|
/>
|
||||||
disabled={Object.keys(errors).length >= 1 || isReadOnly}
|
<DealTicketButton
|
||||||
variant={order.side === Schema.Side.SIDE_BUY ? 'ternary' : 'secondary'}
|
disabled={Object.keys(errors).length >= 1 || isReadOnly}
|
||||||
/>
|
variant={
|
||||||
<DealTicketFeeDetails
|
order.side === Schema.Side.SIDE_BUY ? 'ternary' : 'secondary'
|
||||||
order={normalizedOrder}
|
}
|
||||||
market={market}
|
/>
|
||||||
marketData={marketData}
|
<DealTicketFeeDetails
|
||||||
margin={margin}
|
order={normalizedOrder}
|
||||||
totalMargin={totalMargin}
|
market={market}
|
||||||
balance={marginAccountBalance}
|
marketData={marketData}
|
||||||
/>
|
margin={margin}
|
||||||
</form>
|
totalMargin={totalMargin}
|
||||||
|
balance={marginAccountBalance}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</TinyScroll>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import styles from './orderbook.module.scss';
|
|
||||||
import colors from 'tailwindcss/colors';
|
import colors from 'tailwindcss/colors';
|
||||||
import { useEffect, useRef, useState, useCallback, Fragment } from 'react';
|
import { useEffect, useRef, useState, useCallback, Fragment } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
@ -14,7 +13,7 @@ import {
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { OrderbookRow } from './orderbook-row';
|
import { OrderbookRow } from './orderbook-row';
|
||||||
import { createRow } from './orderbook-data';
|
import { createRow } from './orderbook-data';
|
||||||
import { Checkbox, Icon, Splash } from '@vegaprotocol/ui-toolkit';
|
import { Checkbox, Icon, Splash, TinyScroll } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { OrderbookData, OrderbookRowData } from './orderbook-data';
|
import type { OrderbookData, OrderbookRowData } from './orderbook-data';
|
||||||
|
|
||||||
interface OrderbookProps extends OrderbookData {
|
interface OrderbookProps extends OrderbookData {
|
||||||
@ -547,8 +546,8 @@ export const Orderbook = ({
|
|||||||
{t('Cumulative vol')}
|
{t('Cumulative vol')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<TinyScroll
|
||||||
className={`h-full overflow-auto relative ${styles['scroll']}`}
|
className="h-full overflow-auto relative"
|
||||||
onScroll={onScroll}
|
onScroll={onScroll}
|
||||||
ref={scrollElement}
|
ref={scrollElement}
|
||||||
data-testid="scroll"
|
data-testid="scroll"
|
||||||
@ -580,7 +579,7 @@ export const Orderbook = ({
|
|||||||
testId={'best-static-offer-price'}
|
testId={'best-static-offer-price'}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</TinyScroll>
|
||||||
<div
|
<div
|
||||||
className="absolute bottom-0 grid grid-cols-4 gap-2 border-t border-default mt-2 z-10 bg-white dark:bg-black w-full"
|
className="absolute bottom-0 grid grid-cols-4 gap-2 border-t border-default mt-2 z-10 bg-white dark:bg-black w-full"
|
||||||
ref={footerElement}
|
ref={footerElement}
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
ExternalLink,
|
ExternalLink,
|
||||||
Link as UILink,
|
Link as UILink,
|
||||||
Splash,
|
Splash,
|
||||||
|
TinyScroll,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { generatePath, Link } from 'react-router-dom';
|
import { generatePath, Link } from 'react-router-dom';
|
||||||
@ -71,7 +72,9 @@ export const MarketInfoContainer = ({
|
|||||||
return (
|
return (
|
||||||
<AsyncRenderer data={data} loading={loading} error={error} reload={reload}>
|
<AsyncRenderer data={data} loading={loading} error={error} reload={reload}>
|
||||||
{data ? (
|
{data ? (
|
||||||
<Info market={data} onSelect={(id) => onSelect?.(id)} />
|
<TinyScroll className="h-full overflow-auto">
|
||||||
|
<Info market={data} onSelect={(id) => onSelect?.(id)} />
|
||||||
|
</TinyScroll>
|
||||||
) : (
|
) : (
|
||||||
<Splash>
|
<Splash>
|
||||||
<p>{t('Could not load market')}</p>
|
<p>{t('Could not load market')}</p>
|
||||||
|
@ -40,6 +40,7 @@ export * from './tabs';
|
|||||||
export * from './text-area';
|
export * from './text-area';
|
||||||
export * from './theme-switcher';
|
export * from './theme-switcher';
|
||||||
export * from './thumbs';
|
export * from './thumbs';
|
||||||
|
export * from './tiny-scroll';
|
||||||
export * from './toast';
|
export * from './toast';
|
||||||
export * from './toggle';
|
export * from './toggle';
|
||||||
export * from './tooltip';
|
export * from './tooltip';
|
||||||
|
1
libs/ui-toolkit/src/components/tiny-scroll/index.tsx
Normal file
1
libs/ui-toolkit/src/components/tiny-scroll/index.tsx
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './tiny-scroll';
|
20
libs/ui-toolkit/src/components/tiny-scroll/tiny-scroll.tsx
Normal file
20
libs/ui-toolkit/src/components/tiny-scroll/tiny-scroll.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import styles from './tiny-scroll.module.scss';
|
||||||
|
import { forwardRef } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import type { HTMLAttributes, ReactNode } from 'react';
|
||||||
|
|
||||||
|
export interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TinyScroll = forwardRef<HTMLDivElement, Props>(
|
||||||
|
({ children, className, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={classNames(className, styles['scroll'])}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user