mirror of https://github.com/buster-so/buster.git
tooltip item move to taliwind
This commit is contained in:
parent
5144c1246d
commit
e460fa86f6
|
@ -16,7 +16,6 @@ export const BusterChartJSTooltip: React.FC<{
|
||||||
hasCategoryAxis: boolean;
|
hasCategoryAxis: boolean;
|
||||||
hasMultipleMeasures: boolean;
|
hasMultipleMeasures: boolean;
|
||||||
keyToUsePercentage: string[];
|
keyToUsePercentage: string[];
|
||||||
columnSettings: NonNullable<BusterChartProps['columnSettings']>;
|
|
||||||
}> = ({
|
}> = ({
|
||||||
chart,
|
chart,
|
||||||
dataPoints: dataPointsProp,
|
dataPoints: dataPointsProp,
|
||||||
|
@ -24,8 +23,7 @@ export const BusterChartJSTooltip: React.FC<{
|
||||||
selectedChartType,
|
selectedChartType,
|
||||||
hasCategoryAxis,
|
hasCategoryAxis,
|
||||||
keyToUsePercentage,
|
keyToUsePercentage,
|
||||||
hasMultipleMeasures,
|
hasMultipleMeasures
|
||||||
columnSettings
|
|
||||||
}) => {
|
}) => {
|
||||||
const isPieChart = selectedChartType === ChartType.Pie;
|
const isPieChart = selectedChartType === ChartType.Pie;
|
||||||
const isScatter = selectedChartType === ChartType.Scatter;
|
const isScatter = selectedChartType === ChartType.Scatter;
|
||||||
|
|
|
@ -194,7 +194,7 @@ const getOrCreateInitialTooltipContainer = (chart: ChartJSOrUndefined) => {
|
||||||
|
|
||||||
tooltipEl.innerHTML = `
|
tooltipEl.innerHTML = `
|
||||||
<div class="tooltip-caret" ></div>
|
<div class="tooltip-caret" ></div>
|
||||||
<div class="tooltip-content bg-white" style="position: relative; z-index: 2; border: 0.5px solid ${token.colorBorder}; border-radius: 4px"></div>
|
<div class="tooltip-content bg-background" style="position: relative; z-index: 2; border: 0.5px solid ${token.colorBorder}; border-radius: 4px"></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const caretEl = tooltipEl.querySelector('.tooltip-caret')! as HTMLDivElement;
|
const caretEl = tooltipEl.querySelector('.tooltip-caret')! as HTMLDivElement;
|
||||||
|
@ -245,7 +245,6 @@ const externalTooltip = (
|
||||||
columnLabelFormats={columnLabelFormats}
|
columnLabelFormats={columnLabelFormats}
|
||||||
selectedChartType={selectedChartType}
|
selectedChartType={selectedChartType}
|
||||||
keyToUsePercentage={keyToUsePercentage}
|
keyToUsePercentage={keyToUsePercentage}
|
||||||
columnSettings={columnSettings}
|
|
||||||
chart={chart}
|
chart={chart}
|
||||||
hasCategoryAxis={hasCategoryAxis}
|
hasCategoryAxis={hasCategoryAxis}
|
||||||
hasMultipleMeasures={hasMultipleMeasures}
|
hasMultipleMeasures={hasMultipleMeasures}
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { BusterChartTooltip } from './BusterChartTooltip';
|
||||||
|
|
||||||
|
const meta: Meta<typeof BusterChartTooltip> = {
|
||||||
|
title: 'Base/Charts/BusterChartTooltip',
|
||||||
|
component: BusterChartTooltip,
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered'
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<div className="rounded-sm border shadow-lg">
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof BusterChartTooltip>;
|
||||||
|
|
||||||
|
const baseTooltipItems = [
|
||||||
|
{
|
||||||
|
color: '#1677ff',
|
||||||
|
seriesType: 'line',
|
||||||
|
formattedLabel: 'Series 1',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
formattedValue: 100,
|
||||||
|
formattedLabel: 'Value',
|
||||||
|
formattedPercentage: '50%'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
usePercentage: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
color: '#52c41a',
|
||||||
|
seriesType: 'line',
|
||||||
|
formattedLabel: 'Series 2',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
formattedValue: 200,
|
||||||
|
formattedLabel: 'Value',
|
||||||
|
formattedPercentage: '100%'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
usePercentage: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const scatterTooltipItems = [
|
||||||
|
{
|
||||||
|
color: '#1677ff',
|
||||||
|
seriesType: 'scatter',
|
||||||
|
formattedLabel: 'Point A',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
formattedValue: '10 dollars',
|
||||||
|
formattedLabel: 'X',
|
||||||
|
formattedPercentage: undefined
|
||||||
|
},
|
||||||
|
{
|
||||||
|
formattedValue: '20 years',
|
||||||
|
formattedLabel: 'Y',
|
||||||
|
formattedPercentage: undefined
|
||||||
|
}
|
||||||
|
],
|
||||||
|
usePercentage: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const manyTooltipItems = Array.from({ length: 15 }, (_, i) => ({
|
||||||
|
color: `hsl(${i * 20}, 70%, 50%)`,
|
||||||
|
seriesType: 'line',
|
||||||
|
formattedLabel: `Series ${i + 1}`,
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
formattedValue: (i + 1) * 100,
|
||||||
|
formattedLabel: 'Value',
|
||||||
|
formattedPercentage: `${(i + 1) * 10}%`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
usePercentage: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
tooltipItems: baseTooltipItems,
|
||||||
|
title: 'Chart Data'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithScatterPlot: Story = {
|
||||||
|
args: {
|
||||||
|
tooltipItems: scatterTooltipItems,
|
||||||
|
title: '' //scatter typically does not have a title
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithManyItems: Story = {
|
||||||
|
args: {
|
||||||
|
tooltipItems: manyTooltipItems,
|
||||||
|
title: 'Many Series'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NoTitle: Story = {
|
||||||
|
args: {
|
||||||
|
tooltipItems: baseTooltipItems,
|
||||||
|
title: undefined
|
||||||
|
}
|
||||||
|
};
|
|
@ -24,7 +24,9 @@ export const BusterChartTooltip: React.FC<{
|
||||||
<div className="flex flex-col py-1.5">
|
<div className="flex flex-col py-1.5">
|
||||||
<div
|
<div
|
||||||
className={`grid ${
|
className={`grid ${
|
||||||
isScatter ? 'grid-cols-1 gap-y-1.5' : 'grid-cols-[auto_auto] items-center gap-x-5'
|
isScatter
|
||||||
|
? 'grid-cols-1 gap-y-1.5'
|
||||||
|
: 'grid-cols-[auto_auto] items-center gap-x-5 gap-y-[3px]'
|
||||||
}`}>
|
}`}>
|
||||||
{shownItems.map((param, index) => (
|
{shownItems.map((param, index) => (
|
||||||
<TooltipItem key={index} {...param} />
|
<TooltipItem key={index} {...param} />
|
||||||
|
@ -32,7 +34,7 @@ export const BusterChartTooltip: React.FC<{
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{hasHiddenItems && (
|
{hasHiddenItems && (
|
||||||
<div className="text-text-secondary pl-3 text-sm">{`${hiddenItems.length} more...`}</div>
|
<div className="text-text-secondary mt-1 pl-3 text-sm">{`${hiddenItems.length} more...`}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useStyles } from './useStyles';
|
|
||||||
import type { ITooltipItem, TooltipItemValueProps } from './interfaces';
|
import type { ITooltipItem, TooltipItemValueProps } from './interfaces';
|
||||||
import { LegendItemDot } from '../BusterChartLegend';
|
import { LegendItemDot } from '../BusterChartLegend/LegendDot';
|
||||||
import { ChartType } from '../interfaces';
|
import { ChartType } from '../interfaces';
|
||||||
|
import { cn } from '@/lib/classMerge';
|
||||||
|
|
||||||
export const TooltipItem: React.FC<ITooltipItem> = ({
|
export const TooltipItem: React.FC<ITooltipItem> = ({
|
||||||
values,
|
values,
|
||||||
|
@ -11,24 +11,23 @@ export const TooltipItem: React.FC<ITooltipItem> = ({
|
||||||
formattedLabel,
|
formattedLabel,
|
||||||
usePercentage
|
usePercentage
|
||||||
}) => {
|
}) => {
|
||||||
const { styles, cx } = useStyles();
|
|
||||||
const isScatter = seriesType === 'scatter';
|
const isScatter = seriesType === 'scatter';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{formattedLabel && (
|
{formattedLabel && (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center space-x-1.5 overflow-hidden pl-3 pr-3">
|
<div className="flex items-center space-x-1.5 overflow-hidden pr-3 pl-3">
|
||||||
<LegendItemDot color={color} type={seriesType as ChartType} inactive={false} />
|
<LegendItemDot color={color} type={seriesType as ChartType} inactive={false} />
|
||||||
<span
|
<span
|
||||||
className={cx(styles.tooltipItemLabel, 'truncate', {
|
className={cn('truncate text-base', {
|
||||||
title: isScatter
|
'text-foreground font-medium': isScatter
|
||||||
})}>
|
})}>
|
||||||
{formattedLabel}
|
{formattedLabel}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isScatter && <div className={cx(styles.tooltipItemSeparator)} />}
|
{isScatter && <div className="bg-border h-[0.5px] w-full" />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -42,8 +41,6 @@ const TooltipItemValue: React.FC<{
|
||||||
usePercentage: boolean;
|
usePercentage: boolean;
|
||||||
isScatter: boolean;
|
isScatter: boolean;
|
||||||
}> = ({ values, usePercentage, isScatter }) => {
|
}> = ({ values, usePercentage, isScatter }) => {
|
||||||
const { styles, cx } = useStyles();
|
|
||||||
|
|
||||||
const chooseValue = (
|
const chooseValue = (
|
||||||
value: string | number | undefined,
|
value: string | number | undefined,
|
||||||
percentage: string | number | undefined
|
percentage: string | number | undefined
|
||||||
|
@ -67,7 +64,10 @@ const TooltipItemValue: React.FC<{
|
||||||
|
|
||||||
const formattedValue = values[0]?.formattedValue;
|
const formattedValue = values[0]?.formattedValue;
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.tooltipItemValue, 'tooltip-values px-3')}>
|
<div
|
||||||
|
className={cn(
|
||||||
|
'text-text-default tooltip-values overflow-hidden px-3 text-right text-xs font-medium text-ellipsis whitespace-nowrap'
|
||||||
|
)}>
|
||||||
{chooseValue(formattedValue, values[0]?.formattedPercentage)}
|
{chooseValue(formattedValue, values[0]?.formattedPercentage)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -77,12 +77,15 @@ const GroupTooltipValue: React.FC<{
|
||||||
label: string;
|
label: string;
|
||||||
value: string | number | undefined;
|
value: string | number | undefined;
|
||||||
}> = ({ label, value }) => {
|
}> = ({ label, value }) => {
|
||||||
const { styles, cx } = useStyles();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={cx(styles.tooltipItemLabel, 'truncate')}>{label}</div>
|
<div className={cn('text-md text-text-secondary max-w-fit truncate')}>{label}</div>
|
||||||
<div className={cx(styles.tooltipItemValue)}>{value}</div>
|
<div
|
||||||
|
className={cn(
|
||||||
|
'text-text-default overflow-hidden text-right text-sm font-medium text-ellipsis whitespace-nowrap'
|
||||||
|
)}>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { useStyles } from './useStyles';
|
import { cn } from '@/lib/classMerge';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const TooltipTitle: React.FC<{ title: string }> = ({ title }) => {
|
export const TooltipTitle: React.FC<{ title: string }> = ({ title }) => {
|
||||||
const { styles, cx } = useStyles();
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.tooltipTitleContainer, 'px-3 py-1.5')}>
|
<div className={cn('border-b', 'px-3 py-1.5')}>
|
||||||
<span className="title">{title}</span>
|
<span className="text-foreground text-base font-medium">{title}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
import { createStyles } from 'antd-style';
|
|
||||||
|
|
||||||
export const useStyles = createStyles(({ token, css }) => ({
|
|
||||||
tooltipTitleContainer: css`
|
|
||||||
border-bottom: 0.5px solid ${token.colorBorder};
|
|
||||||
.title {
|
|
||||||
color: ${token.colorText};
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
|
|
||||||
tooltipItemLabel: css`
|
|
||||||
font-size: 12px;
|
|
||||||
color: ${token.colorTextSecondary};
|
|
||||||
max-width: fit-content;
|
|
||||||
&.title {
|
|
||||||
color: ${token.colorText};
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
tooltipItemValue: css`
|
|
||||||
color: ${token.colorText};
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-align: right;
|
|
||||||
`,
|
|
||||||
tooltipItemSeparator: css`
|
|
||||||
background: ${token.colorBorder};
|
|
||||||
height: 0.5px;
|
|
||||||
width: 100%;
|
|
||||||
`
|
|
||||||
}));
|
|
Loading…
Reference in New Issue