Compare commits

...
Author SHA1 Message Date
Matthew Russell 3ab1d9a777 chore: remove useMemo and useCallback 2023-07-18 10:35:13 +01:00
maciek d0dfc62a40 Merge remote-tracking branch 'origin/develop' into chore/4069-orderbook-adjustments 2023-07-17 17:04:46 +02:00
maciek e955bd9a00 chore: orderbook adjustments - fix failing int test 2023-07-17 17:04:28 +02:00
maciek 2ab50e385e Merge remote-tracking branch 'origin/develop' into chore/4069-orderbook-adjustments 2023-07-17 15:56:12 +02:00
maciek d9f42df1dc chore: orderbook adjustments - fix linters 2023-07-17 15:55:51 +02:00
maciek b81f40a34a Merge remote-tracking branch 'origin/develop' into chore/4069-orderbook-adjustments 2023-07-17 15:21:04 +02:00
maciek 077fe8eff5 chore: orderbook adjustments - add some next unit tests 2023-07-17 15:20:25 +02:00
maciek ad82eaa2db Merge remote-tracking branch 'origin/develop' into chore/4069-orderbook-adjustments 2023-07-17 14:59:21 +02:00
maciek 8451ade387 chore: orderbook adjustments - refactor tabs component, add a couple of test 2023-07-17 14:58:40 +02:00
maciek ba37af7f12 chore: orderbook adjustments - refactor tabs component, add a couple of test 2023-07-17 14:52:41 +02:00
maciek 8690d95db1 chore: orderbook adjustments - fix linters 2023-07-17 10:57:00 +02:00
maciek a2561376b6 chore: orderbook adjustments - fix failing unit tests 2023-07-17 10:11:35 +02:00
maciek 19ce37a0f0 chore: orderbook adjustments - refactor tabs component for prevent content overflow 2023-07-14 17:50:44 +02:00
maciek 291d88daad Merge remote-tracking branch 'origin/develop' into chore/4069-orderbook-adjustments 2023-07-14 16:12:08 +02:00
maciek af3ad02379 chore: orderbook adjustments - go with next amendments 2023-07-14 16:11:54 +02:00
Bartłomiej Głownia 3ecc74909a feat(3330): add orderbook e2e unit tests 2023-07-14 12:20:50 +02:00
Bartłomiej Głownia 17e4b3461c feat(3330): make volume cells in orderbook update the deal ticket 2023-07-14 11:29:24 +02:00
maciek b9b4f5b05c chore: orderbook adjustments - add next icons and some more adjustments 2023-07-12 17:10:21 +02:00
maciek 6d81e4e4b6 chore: orderbook adjustments 2023-07-12 13:21:44 +02:00
11 changed files with 360 additions and 57 deletions
@@ -9,6 +9,7 @@ const bidCumulative = 'cumulative-vol-9889001';
const midPrice = 'middle-mark-price-4612690000';
const priceResolution = 'resolution';
const dealTicketPrice = 'order-price';
const dealTicketSize = 'order-size';
const resPrice = 'price-990';
describe('order book', { tags: '@smoke' }, () => {
@@ -74,6 +75,12 @@ describe('order book', { tags: '@smoke' }, () => {
cy.getByTestId(dealTicketPrice).should('have.value', '98.94585');
});
it('copy size to deal ticket form', () => {
// 6003-ORDB-009
cy.getByTestId(bidCumulative).click();
cy.getByTestId(dealTicketSize).should('have.value', '7');
});
it('change price resolution', () => {
// 6003-ORDB-008
const resolutions = [
@@ -88,13 +95,14 @@ describe('order book', { tags: '@smoke' }, () => {
'1,000',
'10,000',
];
cy.getByTestId(priceResolution)
.find('option')
cy.getByTestId(priceResolution).click();
cy.get('[role="menu"]')
.find('[role="menuitem"]')
.each(($el, index) => {
expect($el.text()).to.equal(resolutions[index]);
});
cy.getByTestId(priceResolution).select('0.0');
cy.get('[role="menuitem"]').eq(4).click();
cy.getByTestId(resPrice).should('have.text', '99.0');
cy.getByTestId(askPrice).should('not.exist');
cy.getByTestId(bidPrice).should('not.exist');
@@ -66,10 +66,13 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
decimalPlaces={market?.decimalPlaces ?? 0}
positionDecimalPlaces={market?.positionDecimalPlaces ?? 0}
assetSymbol={market?.tradableInstrument.instrument.product.quoteName}
onClick={(price: string) => {
onClick={({ price, size }) => {
if (price) {
updateOrder(marketId, { price });
}
if (size) {
updateOrder(marketId, { size });
}
}}
midPrice={marketData?.midPrice}
/>
+52 -19
View File
@@ -11,10 +11,14 @@ interface OrderbookRowProps {
decimalPlaces: number;
positionDecimalPlaces: number;
price: string;
onClick?: (price: string) => void;
onClick?: (args: { price?: string; size?: string }) => void;
type: VolumeType;
width: number;
}
const HIDE_VOL_WIDTH = 150;
const HIDE_CUMULATIVE_VOL_WIDTH = 220;
const CumulationBar = ({
cumulativeValue = 0,
type,
@@ -26,7 +30,7 @@ const CumulationBar = ({
<div
data-testid={`${VolumeType.bid === type ? 'bid' : 'ask'}-bar`}
className={classNames(
'absolute top-0 left-0 h-full transition-all',
'absolute top-0 left-0 h-full',
type === VolumeType.bid
? 'bg-market-green-300 dark:bg-market-green/50'
: 'bg-market-red-300 dark:bg-market-red/30'
@@ -43,6 +47,7 @@ const CumulativeVol = memo(
testId,
positionDecimalPlaces,
cumulativeValue,
onClick,
}: {
ask?: number;
bid?: number;
@@ -50,6 +55,7 @@ const CumulativeVol = memo(
testId?: string;
className?: string;
positionDecimalPlaces: number;
onClick?: (size?: string | number) => void;
}) => {
const volume = cumulativeValue ? (
<NumericCell
@@ -61,7 +67,15 @@ const CumulativeVol = memo(
/>
) : null;
return (
return onClick && volume ? (
<button
data-testid={testId}
onClick={() => onClick(cumulativeValue)}
className="hover:dark:bg-neutral-800 hover:bg-neutral-200 text-right pr-1"
>
{volume}
</button>
) : (
<div className="pr-1" data-testid={testId}>
{volume}
</div>
@@ -80,16 +94,24 @@ export const OrderbookRow = React.memo(
price,
onClick,
type,
width,
}: OrderbookRowProps) => {
const txtId = type === VolumeType.bid ? 'bid' : 'ask';
const cols =
width >= HIDE_CUMULATIVE_VOL_WIDTH ? 3 : width >= HIDE_VOL_WIDTH ? 2 : 1;
return (
<div className="relative">
<div className="relative pr-1">
<CumulationBar cumulativeValue={cumulativeRelativeValue} type={type} />
<div className="grid gap-1 text-right grid-cols-3">
<div
data-testid={`${txtId}-rows-container`}
className={classNames('grid gap-1 text-right', `grid-cols-${cols}`)}
>
<PriceCell
testId={`price-${price}`}
value={BigInt(price)}
onClick={() => onClick && onClick(addDecimal(price, decimalPlaces))}
onClick={() =>
onClick && onClick({ price: addDecimal(price, decimalPlaces) })
}
valueFormatted={addDecimalsFixedFormatNumber(price, decimalPlaces)}
className={
type === VolumeType.ask
@@ -97,19 +119,30 @@ export const OrderbookRow = React.memo(
: 'text-market-green-600 dark:text-market-green'
}
/>
<NumericCell
testId={`${txtId}-vol-${price}`}
value={value}
valueFormatted={addDecimalsFixedFormatNumber(
value,
positionDecimalPlaces
)}
/>
<CumulativeVol
testId={`cumulative-vol-${price}`}
positionDecimalPlaces={positionDecimalPlaces}
cumulativeValue={cumulativeValue}
/>
{width >= HIDE_VOL_WIDTH && (
<NumericCell
testId={`${txtId}-vol-${price}`}
value={value}
valueFormatted={addDecimalsFixedFormatNumber(
value,
positionDecimalPlaces
)}
/>
)}
{width >= HIDE_CUMULATIVE_VOL_WIDTH && (
<CumulativeVol
testId={`cumulative-vol-${price}`}
onClick={() =>
onClick &&
cumulativeValue &&
onClick({
size: addDecimal(cumulativeValue, positionDecimalPlaces),
})
}
positionDecimalPlaces={positionDecimalPlaces}
cumulativeValue={cumulativeValue}
/>
)}
</div>
</div>
);
+97 -9
View File
@@ -1,4 +1,5 @@
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
import { render, waitFor, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { generateMockData, VolumeType } from './orderbook-data';
import { Orderbook } from './orderbook';
import * as orderbookData from './orderbook-data';
@@ -33,6 +34,7 @@ describe('Orderbook', () => {
const decimalPlaces = 3;
beforeEach(() => {
jest.clearAllMocks();
mockOffsetSize(800, 768);
});
it('markPrice should be in the middle', async () => {
@@ -69,12 +71,17 @@ describe('Orderbook', () => {
await screen.findByTestId(`middle-mark-price-${params.midPrice}`)
).toBeInTheDocument();
// Before resolution change the price is 122.934
await fireEvent.click(await screen.getByTestId('price-122901'));
expect(onClickSpy).toBeCalledWith('122.901');
const resolutionSelect = screen.getByTestId(
'resolution'
) as HTMLSelectElement;
await fireEvent.change(resolutionSelect, { target: { value: '10' } });
await userEvent.click(await screen.getByTestId('price-122901'));
expect(onClickSpy).toBeCalledWith({ price: '122.901' });
await userEvent.click(screen.getByTestId('resolution'));
await waitFor(() => {
expect(screen.getByRole('menu')).toBeInTheDocument();
});
await userEvent.click(screen.getAllByRole('menuitem')[1]);
expect(orderbookData.compactRows).toHaveBeenCalledWith(
mockedData.bids,
VolumeType.bid,
@@ -85,7 +92,88 @@ describe('Orderbook', () => {
VolumeType.ask,
10
);
await fireEvent.click(await screen.getByTestId('price-12294'));
expect(onClickSpy).toBeCalledWith('122.94');
await userEvent.click(await screen.getByTestId('price-12294'));
expect(onClickSpy).toBeCalledWith({ price: '122.94' });
});
it('plus - minus buttons should change resolution', async () => {
const onClickSpy = jest.fn();
jest.spyOn(orderbookData, 'compactRows');
const mockedData = generateMockData(params);
render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
onClick={onClickSpy}
{...mockedData}
assetSymbol="USD"
/>
);
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
1
);
expect(screen.getByTestId('minus-button')).toBeDisabled();
userEvent.click(screen.getByTestId('plus-button'));
await waitFor(() => {
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
10
);
});
expect(screen.getByTestId('minus-button')).not.toBeDisabled();
userEvent.click(screen.getByTestId('minus-button'));
await waitFor(() => {
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
1
);
});
expect(screen.getByTestId('minus-button')).toBeDisabled();
await userEvent.click(screen.getByTestId('resolution'));
await waitFor(() => {
expect(screen.getByRole('menu')).toBeInTheDocument();
});
await userEvent.click(screen.getAllByRole('menuitem')[5]);
await waitFor(() => {
expect((orderbookData.compactRows as jest.Mock).mock.lastCall[2]).toEqual(
100000
);
});
expect(screen.getByTestId('plus-button')).toBeDisabled();
});
it('two columns', () => {
mockOffsetSize(200, 768);
const onClickSpy = jest.fn();
const mockedData = generateMockData(params);
render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
onClick={onClickSpy}
{...mockedData}
assetSymbol="USD"
/>
);
screen.getAllByTestId('bid-rows-container').forEach((item) => {
expect(item).toHaveClass('grid-cols-2');
});
});
it('one column', () => {
mockOffsetSize(140, 768);
const onClickSpy = jest.fn();
const mockedData = generateMockData(params);
render(
<Orderbook
decimalPlaces={decimalPlaces}
positionDecimalPlaces={0}
onClick={onClickSpy}
{...mockedData}
assetSymbol="USD"
/>
);
screen.getAllByTestId('ask-rows-container').forEach((item) => {
expect(item).toHaveClass('grid-cols-1');
});
});
});
+123 -24
View File
@@ -5,10 +5,20 @@ import {
formatNumberFixed,
} from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { usePrevious } from '@vegaprotocol/react-helpers';
import { OrderbookRow } from './orderbook-row';
import type { OrderbookRowData } from './orderbook-data';
import { compactRows, VolumeType } from './orderbook-data';
import { Splash } from '@vegaprotocol/ui-toolkit';
import {
Splash,
VegaIcon,
VegaIconNames,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
Button,
} from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import { useState } from 'react';
import type { PriceLevelFieldsFragment } from './__generated__/MarketDepth';
@@ -26,13 +36,15 @@ const OrderbookTable = ({
decimalPlaces,
positionDecimalPlaces,
onClick,
width,
}: {
rows: OrderbookRowData[];
resolution: number;
decimalPlaces: number;
positionDecimalPlaces: number;
type: VolumeType;
onClick?: (price: string) => void;
onClick?: (args: { price?: string; size?: string }) => void;
width: number;
}) => {
return (
<div
@@ -59,6 +71,7 @@ const OrderbookTable = ({
cumulativeValue={data.cumulativeVol.value}
cumulativeRelativeValue={data.cumulativeVol.relativeValue}
type={type}
width={width}
/>
))}
</div>
@@ -69,7 +82,7 @@ const OrderbookTable = ({
interface OrderbookProps {
decimalPlaces: number;
positionDecimalPlaces: number;
onClick?: (price: string) => void;
onClick?: (args: { price?: string; size?: string }) => void;
midPrice?: string;
bids: PriceLevelFieldsFragment[];
asks: PriceLevelFieldsFragment[];
@@ -99,12 +112,59 @@ export const Orderbook = ({
const groupedBids = useMemo(() => {
return compactRows(bids, VolumeType.bid, resolution);
}, [bids, resolution]);
const [isOpen, setOpen] = useState(false);
const previousMidPrice = usePrevious(midPrice);
const icon =
midPrice && previousMidPrice !== midPrice ? (
<span
className={classNames(
(previousMidPrice || '') > midPrice
? 'text-market-red dark:text-market-red'
: 'text-market-green-600 dark:text-market-green'
)}
>
<VegaIcon
name={
(previousMidPrice || '') > midPrice
? VegaIconNames.ARROW_DOWN
: VegaIconNames.ARROW_UP
}
/>
</span>
) : (
<span className="text-vega-blue-500 dark:text-vega-blue-500">
<VegaIcon name={VegaIconNames.BULLET} />
</span>
);
const formatResolution = (r: number) => {
return formatNumberFixed(
Math.log10(r) - decimalPlaces > 0
? Math.pow(10, Math.log10(r) - decimalPlaces)
: 0,
decimalPlaces - Math.log10(r)
);
};
const increaseResolution = () => {
const index = resolutions.indexOf(resolution);
if (index < resolutions.length - 1) {
setResolution(resolutions[index + 1]);
}
};
const decreaseResolution = () => {
const index = resolutions.indexOf(resolution);
if (index > 0) {
setResolution(resolutions[index - 1]);
}
};
return (
<div className="h-full pl-1 text-xs grid grid-rows-[1fr_min-content]">
<div>
<ReactVirtualizedAutoSizer disableWidth>
{({ height }) => {
<ReactVirtualizedAutoSizer>
{({ width, height }) => {
const limit = Math.max(
1,
Math.floor((height - midHeight) / 2 / (rowHeight + rowGap))
@@ -116,6 +176,7 @@ export const Orderbook = ({
className="overflow-hidden grid"
data-testid="orderbook-grid-element"
style={{
width: width + 'px',
height: height + 'px',
gridTemplateRows: `1fr ${midHeight}px 1fr`, // cannot use tailwind here as tailwind will not parse a class string with interpolation
}}
@@ -129,6 +190,7 @@ export const Orderbook = ({
decimalPlaces={decimalPlaces}
positionDecimalPlaces={positionDecimalPlaces}
onClick={onClick}
width={width}
/>
<div className="flex items-center justify-center gap-2">
{midPrice && (
@@ -140,6 +202,7 @@ export const Orderbook = ({
{addDecimalsFormatNumber(midPrice, decimalPlaces)}
</span>
<span className="text-base">{assetSymbol}</span>
{icon}
</>
)}
</div>
@@ -150,6 +213,7 @@ export const Orderbook = ({
decimalPlaces={decimalPlaces}
positionDecimalPlaces={positionDecimalPlaces}
onClick={onClick}
width={width}
/>
</>
) : (
@@ -162,26 +226,61 @@ export const Orderbook = ({
}}
</ReactVirtualizedAutoSizer>
</div>
<div className="border-t border-default">
<select
onChange={(e) => {
setResolution(Number(e.currentTarget.value));
}}
value={resolution}
className="block bg-neutral-100 dark:bg-neutral-700 font-mono text-right"
data-testid="resolution"
<div className="border-t border-default flex">
<Button
onClick={increaseResolution}
size="xs"
disabled={resolutions.indexOf(resolution) >= resolutions.length - 1}
className="text-black dark:text-white rounded-none border-y-0 border-l-0 flex items-center border-r-1"
data-testid="plus-button"
>
{resolutions.map((r) => (
<option key={r} value={r}>
{formatNumberFixed(
Math.log10(r) - decimalPlaces > 0
? Math.pow(10, Math.log10(r) - decimalPlaces)
: 0,
decimalPlaces - Math.log10(r)
)}
</option>
))}
</select>
<VegaIcon size={12} name={VegaIconNames.PLUS} />
</Button>
<DropdownMenu
open={isOpen}
onOpenChange={(open) => setOpen(open)}
trigger={
<DropdownMenuTrigger
data-testid="resolution"
className="flex justify-between px-1 items-center"
style={{
width: `${
Math.max.apply(
null,
resolutions.map((item) => formatResolution(item).length)
) + 3
}ch`,
}}
>
<VegaIcon
size={12}
name={
isOpen ? VegaIconNames.CHEVRON_UP : VegaIconNames.CHEVRON_DOWN
}
/>
<div className="text-xs text-left">
{formatResolution(resolution)}
</div>
</DropdownMenuTrigger>
}
>
<DropdownMenuContent align="start">
{resolutions.map((r) => (
<DropdownMenuItem key={r} onClick={() => setResolution(r)}>
{formatResolution(r)}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
<Button
onClick={decreaseResolution}
size="xs"
disabled={resolutions.indexOf(resolution) <= 0}
className="text-black dark:text-white rounded-none border-y-0 border-l-1 flex items-center"
data-testid="minus-button"
>
<VegaIcon size={12} name={VegaIconNames.MINUS} />
</Button>
</div>
</div>
);
@@ -0,0 +1,18 @@
export const IconArrowUp = ({ size = 16 }: { size: number }) => {
return (
<svg width={size} height={size} viewBox="0 0 16 16">
<path
d="M 7.47,3.63
C 7.47,3.63 2.37,8.72 2.37,8.72
2.37,8.72 1.63,7.98 1.63,7.98
1.63,7.98 8.00,1.60 8.00,1.60
8.00,1.60 14.37,7.98 14.37,7.98
14.37,7.98 13.63,8.72 13.63,8.72
13.63,8.72 8.53,3.63 8.53,3.63
8.53,3.63 8.53,14.35 8.53,14.35
8.53,14.35 7.47,14.35 7.47,14.35
7.47,14.35 7.47,3.63 7.47,3.63 Z"
/>
</svg>
);
};
@@ -0,0 +1,7 @@
export const IconBullet = ({ size = 16 }: { size: number }) => {
return (
<svg width={size} height={size} viewBox="0 0 16 16">
<circle cx="8" cy="8" r="6" />
</svg>
);
};
@@ -0,0 +1,13 @@
export const IconMinus = ({ size = 16 }: { size: number }) => {
return (
<svg width={size} height={size} viewBox="0 0 16 16">
<path
d="M 0.92,8.58
C 0.92,8.58 0.92,7.48 0.92,7.48
0.92,7.48 15.01,7.48 15.01,7.48
15.01,7.48 15.01,8.58 15.01,8.58
15.01,8.58 0.92,8.58 0.92,8.58 Z"
/>
</svg>
);
};
@@ -0,0 +1,21 @@
export const IconPlus = ({ size = 16 }: { size: number }) => {
return (
<svg width={size} height={size} viewBox="0 0 16 16">
<path
d="M 7.43,15.24
C 7.43,15.24 7.43,8.58 7.43,8.58
7.43,8.58 0.92,8.58 0.92,8.58
0.92,8.58 0.92,7.48 0.92,7.48
0.92,7.48 7.43,7.48 7.43,7.48
7.43,7.48 7.43,0.85 7.43,0.85
7.43,0.85 8.48,0.85 8.48,0.85
8.48,0.85 8.48,7.48 8.48,7.48
8.48,7.48 15.01,7.48 15.01,7.48
15.01,7.48 15.01,8.58 15.01,8.58
15.01,8.58 8.48,8.58 8.48,8.58
8.48,8.58 8.48,15.24 8.48,15.24
8.48,15.24 7.43,15.24 7.43,15.24 Z"
/>
</svg>
);
};
@@ -1,6 +1,8 @@
import { IconArrowDown } from './svg-icons/icon-arrow-down';
import { IconArrowUp } from './svg-icons/icon-arrow-up';
import { IconArrowRight } from './svg-icons/icon-arrow-right';
import { IconBreakdown } from './svg-icons/icon-breakdown';
import { IconBullet } from './svg-icons/icon-bullet';
import { IconChevronDown } from './svg-icons/icon-chevron-down';
import { IconChevronLeft } from './svg-icons/icon-chevron-left';
import { IconChevronUp } from './svg-icons/icon-chevron-up';
@@ -13,9 +15,11 @@ import { IconGlobe } from './svg-icons/icon-globe';
import { IconInfo } from './svg-icons/icon-info';
import { IconKebab } from './svg-icons/icon-kebab';
import { IconLinkedIn } from './svg-icons/icon-linkedin';
import { IconMinus } from './svg-icons/icon-minus';
import { IconMoon } from './svg-icons/icon-moon';
import { IconOpenExternal } from './svg-icons/icon-open-external';
import { IconQuestionMark } from './svg-icons/icon-question-mark';
import { IconPlus } from './svg-icons/icon-plus';
import { IconTick } from './svg-icons/icon-tick';
import { IconTransfer } from './svg-icons/icon-transfer';
import { IconTrendUp } from './svg-icons/icon-trend-up';
@@ -24,8 +28,10 @@ import { IconWithdraw } from './svg-icons/icon-withdraw';
export enum VegaIconNames {
ARROW_DOWN = 'arrow-down',
ARROW_UP = 'arrow-up',
ARROW_RIGHT = 'arrow-right',
BREAKDOWN = 'breakdown',
BULLET = 'bullet',
CHEVRON_DOWN = 'chevron-down',
CHEVRON_LEFT = 'chevron-left',
CHEVRON_UP = 'chevron-up',
@@ -38,9 +44,11 @@ export enum VegaIconNames {
INFO = 'info',
KEBAB = 'kebab',
LINKEDIN = 'linkedin',
MINUS = 'minus',
MOON = 'moon',
OPEN_EXTERNAL = 'open-external',
QUESTION_MARK = 'question-mark',
PLUS = 'plus',
TICK = 'tick',
TRANSFER = 'transfer',
TREND_UP = 'trend-up',
@@ -53,6 +61,7 @@ export const VegaIconNameMap: Record<
({ size }: { size: number }) => JSX.Element
> = {
'arrow-down': IconArrowDown,
'arrow-up': IconArrowUp,
'arrow-right': IconArrowRight,
'chevron-down': IconChevronDown,
'chevron-left': IconChevronLeft,
@@ -61,6 +70,7 @@ export const VegaIconNameMap: Record<
'question-mark': IconQuestionMark,
'trend-up': IconTrendUp,
breakdown: IconBreakdown,
bullet: IconBullet,
copy: IconCopy,
cross: IconCross,
deposit: IconDeposit,
@@ -70,7 +80,9 @@ export const VegaIconNameMap: Record<
info: IconInfo,
kebab: IconKebab,
linkedin: IconLinkedIn,
minus: IconMinus,
moon: IconMoon,
plus: IconPlus,
tick: IconTick,
transfer: IconTransfer,
twitter: IconTwitter,
+2 -1
View File
@@ -23,6 +23,7 @@ export const Tabs = ({
}
return children[0].props.id;
});
return (
<TabsPrimitive.Root
{...props}
@@ -30,7 +31,7 @@ export const Tabs = ({
onValueChange={onValueChange || setActiveTab}
className="h-full grid grid-rows-[min-content_1fr]"
>
<div className="border-b border-default">
<div className="border-b border-default min-w-0">
<TabsPrimitive.List
className="flex flex-nowrap overflow-visible"
role="tablist"