feat(trading): use mini scroll in deal ticket, market info for and landing dialog (#3269)

This commit is contained in:
Bartłomiej Głownia 2023-03-25 01:01:12 +01:00 committed by GitHub
parent e8adff25c4
commit 58c6652e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 169 additions and 140 deletions

View File

@ -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]()}

View File

@ -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>
); );
}; };

View File

@ -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}

View File

@ -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>

View File

@ -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';

View File

@ -0,0 +1 @@
export * from './tiny-scroll';

View 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>
)
);