overflow story

This commit is contained in:
Nate Kelley 2025-02-26 15:30:46 -07:00
parent e460fa86f6
commit 4b4ba2e21e
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
4 changed files with 87 additions and 74 deletions

View File

@ -1,2 +1 @@
export * from './ItemContainer';
export * from './CodeCard';

View File

@ -0,0 +1,69 @@
import type { Meta, StoryObj } from '@storybook/react';
import { OverflowButton } from './OverflowContainer';
import { ChartType } from '../interfaces';
const meta = {
title: 'Base/Charts/OverflowButton',
component: OverflowButton,
parameters: {
layout: 'centered'
},
tags: ['autodocs']
} satisfies Meta<typeof OverflowButton>;
export default meta;
type Story = StoryObj<typeof meta>;
const mockLegendItems = [
{
id: '1',
color: '#FF5733',
inactive: false,
type: ChartType.Line,
formattedName: 'Series A',
serieName: 'series-a'
},
{
id: '2',
color: '#33FF57',
inactive: false,
type: ChartType.Line,
formattedName: 'Series B',
serieName: 'series-b'
},
{
id: '3',
color: '#3357FF',
inactive: true,
type: ChartType.Line,
formattedName: 'Inactive Series C',
serieName: 'series-c'
}
];
export const Default: Story = {
args: {
legendItems: mockLegendItems,
onClickItem: (item) => console.log('Clicked:', item),
onFocusClick: (item) => console.log('Focused:', item)
}
};
export const WithInactiveItems: Story = {
args: {
legendItems: mockLegendItems.map((item) => ({ ...item, inactive: true }))
}
};
export const WithManyItems: Story = {
args: {
legendItems: Array.from({ length: 10 }, (_, i) => ({
id: `${i + 1}`,
color: `hsl(${(i * 36) % 360}, 70%, 50%)`,
inactive: false,
type: ChartType.Line,
formattedName: `Series ${String.fromCharCode(65 + i)}`,
serieName: `series-${String.fromCharCode(97 + i)}`
}))
}
};

View File

@ -1,9 +1,10 @@
import { AppPopover } from '@/components/ui/tooltip';
import { createStyles } from 'antd-style';
import { Popover } from '@/components/ui/tooltip/Popover';
import React from 'react';
import { BusterChartLegendItem, BusterChartLegendProps } from './interfaces';
import { LegendItem } from './LegendItem';
import { Text } from '@/components/ui';
import { cn } from '@/lib/classMerge';
import { LegendItemDot } from './LegendDot';
import { ChartType } from '../interfaces';
export const OverflowButton: React.FC<{
legendItems: BusterChartLegendItem[];
@ -11,15 +12,11 @@ export const OverflowButton: React.FC<{
onClickItem?: BusterChartLegendProps['onClickItem'];
onHoverItem?: BusterChartLegendProps['onHoverItem'];
}> = React.memo(({ legendItems, onFocusClick, onClickItem, onHoverItem }) => {
const { styles, cx } = useStyles();
return (
<AppPopover
placement="bottomRight"
mouseEnterDelay={0.75}
trigger={'click'}
destroyTooltipOnHide
className="max-h-[420px] max-w-[265px]! min-w-[200px] overflow-x-hidden overflow-y-auto px-0"
<Popover
align="end"
side="right"
className="max-h-[420px] max-w-[265px]! min-w-[200px] overflow-x-hidden overflow-y-auto px-0 py-1"
content={
<div className="flex flex-col space-y-1 p-0.5">
{legendItems.map((item) => {
@ -35,66 +32,15 @@ export const OverflowButton: React.FC<{
})}
</div>
}>
<div className={cx('flex items-center space-x-1.5', styles.overflowItemContainer)}>
<div className={cx(styles.dot, styles.overflowDot, 'flex')} />
<Text size="sm" className="text-nowrap select-none">
Next {legendItems.length}
</Text>
<div
className={cn(
'flex h-[24px] cursor-pointer items-center space-x-1.5 rounded-sm px-2 py-1',
'hover:bg-item-hover'
)}>
<LegendItemDot type={ChartType.Bar} color={undefined} inactive={true} />
<span className="text-sm text-nowrap select-none">Next {legendItems.length}</span>
</div>
</AppPopover>
</Popover>
);
});
OverflowButton.displayName = 'OverflowButton';
const useStyles = createStyles(({ token, css }) => {
return {
dot: css`
background: ${token.colorBgContainerDisabled};
width: 18px;
min-width: 18px;
height: 12px;
border-radius: 4px;
&.group {
&:hover {
&.focus-item {
background-color: ${token.colorBgElevated} !important;
}
}
}
`,
overflowItemContainer: css`
cursor: pointer;
padding: 1px 8px;
border-radius: 4px;
border: 0px solid ${token.colorBorder};
// background: ${token.colorBgBase};
&:hover {
background: ${token.controlItemBgHover};
}
`,
overflowDot: css`
background: ${token.colorBorder};
`,
overflowItem: css`
display: flex;
align-items: center;
cursor: pointer;
white-space: nowrap;
padding: 3px 5px;
border-radius: 4px;
&:hover {
background: ${token.controlItemBgHover};
}
&.inactive {
border-color: ${token.colorBgContainerDisabled};
.dot {
background: ${token.colorBgContainerDisabled};
}
}
`
};
});

View File

@ -23,12 +23,11 @@ const PopoverContent = React.forwardRef<
className={cn(
'bg-popover text-popover-foreground',
'w-fit rounded border shadow outline-none',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50',
className
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50'
)}
{...props}>
{headerContent && <>{headerContent}</>}
<div className="p-2.5"> {children}</div>
<div className={cn('p-2.5', className)}>{children}</div>
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
));