mirror of https://github.com/buster-so/buster.git
legend item
This commit is contained in:
parent
7f8cfe4b4f
commit
9cbb33c569
|
@ -1,10 +1,10 @@
|
||||||
import React, { useMemo, useEffect, useLayoutEffect } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { BusterChartLegendItem, BusterChartLegendProps } from './interfaces';
|
import { type BusterChartLegendItem, type BusterChartLegendProps } from './interfaces';
|
||||||
import { Text, Title } from '@/components/ui';
|
|
||||||
import { createStyles } from 'antd-style';
|
import { createStyles } from 'antd-style';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { LegendItemDot } from './LegendDot';
|
import { LegendItemDot } from './LegendDot';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
export const LegendItem: React.FC<{
|
export const LegendItem: React.FC<{
|
||||||
item: BusterChartLegendItem;
|
item: BusterChartLegendItem;
|
||||||
|
@ -112,12 +112,13 @@ const LegendItemStandard = React.memo(
|
||||||
<AnimatePresence initial={false}>
|
<AnimatePresence initial={false}>
|
||||||
{hasHeadline && (
|
{hasHeadline && (
|
||||||
<motion.div {...headlineAnimation} className="flex items-center space-x-1.5">
|
<motion.div {...headlineAnimation} className="flex items-center space-x-1.5">
|
||||||
<Title
|
<span
|
||||||
level={4}
|
className={cn(
|
||||||
className="leading-none font-semibold!"
|
'text-md leading-none font-semibold!',
|
||||||
type={!inactive ? 'default' : 'tertiary'}>
|
!inactive ? 'text-foreground' : 'text-text-secondary'
|
||||||
|
)}>
|
||||||
{headline?.titleAmount}
|
{headline?.titleAmount}
|
||||||
</Title>
|
</span>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
@ -134,10 +135,11 @@ const LegendItemStandard = React.memo(
|
||||||
inactive={item.inactive}
|
inactive={item.inactive}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Text
|
<span
|
||||||
size="sm"
|
className={cn(
|
||||||
className="flex! items-center truncate transition-all duration-100 select-none"
|
'flex! items-center truncate text-base transition-all duration-100 select-none',
|
||||||
type={!inactive ? 'default' : 'tertiary'}>
|
!inactive ? 'text-foreground' : 'text-text-secondary'
|
||||||
|
)}>
|
||||||
<AnimatePresence mode="wait" initial={false}>
|
<AnimatePresence mode="wait" initial={false}>
|
||||||
{headlinePreText && (
|
{headlinePreText && (
|
||||||
<motion.div
|
<motion.div
|
||||||
|
@ -149,7 +151,7 @@ const LegendItemStandard = React.memo(
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
{formattedName}
|
{formattedName}
|
||||||
</Text>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { LegendItem } from '../LegendItem';
|
||||||
|
import { ChartType } from '../../interfaces';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Base/Charts/LegendItem',
|
||||||
|
component: LegendItem,
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered'
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#1677ff',
|
||||||
|
inactive: false,
|
||||||
|
type: ChartType.Line,
|
||||||
|
formattedName: 'Sample Legend',
|
||||||
|
id: '1',
|
||||||
|
serieName: 'series1'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
item: {
|
||||||
|
control: 'object',
|
||||||
|
description: 'The legend item configuration'
|
||||||
|
},
|
||||||
|
onClickItem: {
|
||||||
|
action: 'clicked',
|
||||||
|
description: 'Function called when the legend item is clicked'
|
||||||
|
},
|
||||||
|
onFocusItem: {
|
||||||
|
action: 'focused',
|
||||||
|
description: 'Function called when the legend item is focused'
|
||||||
|
},
|
||||||
|
onHoverItem: {
|
||||||
|
action: 'hovered',
|
||||||
|
description: 'Function called when the legend item is hovered'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} satisfies Meta<typeof LegendItem>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof LegendItem>;
|
||||||
|
|
||||||
|
// Basic legend item
|
||||||
|
export const Basic: Story = {
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#1677ff',
|
||||||
|
inactive: false,
|
||||||
|
type: ChartType.Line,
|
||||||
|
formattedName: 'Basic Legend',
|
||||||
|
id: '1',
|
||||||
|
serieName: 'series1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Inactive legend item
|
||||||
|
export const Inactive: Story = {
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#1677ff',
|
||||||
|
inactive: true,
|
||||||
|
type: ChartType.Line,
|
||||||
|
formattedName: 'Inactive Legend',
|
||||||
|
id: '2',
|
||||||
|
serieName: 'series2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bar type legend item
|
||||||
|
export const BarType: Story = {
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#52c41a',
|
||||||
|
inactive: false,
|
||||||
|
type: ChartType.Bar,
|
||||||
|
formattedName: 'Bar Legend',
|
||||||
|
id: '3',
|
||||||
|
serieName: 'series3'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scatter type legend item
|
||||||
|
export const ScatterType: Story = {
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#722ed1',
|
||||||
|
inactive: false,
|
||||||
|
type: ChartType.Scatter,
|
||||||
|
formattedName: 'Scatter Legend',
|
||||||
|
id: '4',
|
||||||
|
serieName: 'series4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// With headline
|
||||||
|
export const WithHeadline: Story = {
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#f5222d',
|
||||||
|
inactive: false,
|
||||||
|
type: ChartType.Line,
|
||||||
|
formattedName: 'Revenue',
|
||||||
|
id: '5',
|
||||||
|
serieName: 'series5',
|
||||||
|
headline: {
|
||||||
|
type: 'current',
|
||||||
|
titleAmount: '$50,000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// With average headline
|
||||||
|
export const WithAverageHeadline: Story = {
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#fa8c16',
|
||||||
|
inactive: false,
|
||||||
|
type: ChartType.Line,
|
||||||
|
formattedName: 'Monthly Sales',
|
||||||
|
id: '6',
|
||||||
|
serieName: 'series6',
|
||||||
|
headline: {
|
||||||
|
type: 'average',
|
||||||
|
titleAmount: '$25,000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Interactive example with all handlers
|
||||||
|
export const WithFocusEvent: Story = {
|
||||||
|
args: {
|
||||||
|
item: {
|
||||||
|
color: '#eb2f96',
|
||||||
|
inactive: false,
|
||||||
|
type: ChartType.Line,
|
||||||
|
formattedName: 'Interactive Legend',
|
||||||
|
id: '7',
|
||||||
|
serieName: 'series7'
|
||||||
|
},
|
||||||
|
onClickItem: (item) => alert(`Clicked: ${item.formattedName}`),
|
||||||
|
onFocusItem: (item) => alert(`Focused: ${item.formattedName}`)
|
||||||
|
// onHoverItem: (item, isHover) => alert(`Hover: ${item.formattedName} ${isHover}`)
|
||||||
|
}
|
||||||
|
};
|
|
@ -91,6 +91,12 @@
|
||||||
--color-ring: var(--color-item-hover);
|
--color-ring: var(--color-item-hover);
|
||||||
--color-popover: var(--color-background);
|
--color-popover: var(--color-background);
|
||||||
--color-popover-foreground: var(--color-foreground);
|
--color-popover-foreground: var(--color-foreground);
|
||||||
|
|
||||||
|
/* text color */
|
||||||
|
--color-text-default: var(--color-foreground);
|
||||||
|
--color-text-disabled: var(--color-gray-light);
|
||||||
|
--color-text-secondary: var(--color-gray-dark);
|
||||||
|
--color-text-tertiary: var(--color-gray-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
@import './tailwindAnimations.css';
|
@import './tailwindAnimations.css';
|
||||||
|
|
Loading…
Reference in New Issue