@takaro/lib-components 0.4.9 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -6
- package/src/components/actions/Button/__snapshots__/Button.test.tsx.snap +1 -1
- package/src/components/actions/IconButton/__snapshots__/IconButton.test.tsx.snap +1 -1
- package/src/components/charts/AreaChart/AreaChart.stories.tsx +11 -7
- package/src/components/charts/AreaChart/index.tsx +114 -63
- package/src/components/charts/BarChart/BarChart.stories.tsx +33 -10
- package/src/components/charts/BarChart/index.tsx +280 -147
- package/src/components/charts/EmptyChart.tsx +45 -0
- package/src/components/charts/GeoMercator/GeoMercator.stories.tsx +15 -9
- package/src/components/charts/GeoMercator/index.tsx +15 -172
- package/src/components/charts/Heatmap/Heatmap.stories.tsx +167 -33
- package/src/components/charts/Heatmap/index.tsx +427 -193
- package/src/components/charts/LineChart/LineChart.stories.tsx +77 -3
- package/src/components/charts/LineChart/index.tsx +200 -79
- package/src/components/charts/PieChart/PieChart.stories.tsx +128 -20
- package/src/components/charts/PieChart/index.tsx +353 -59
- package/src/components/charts/PointHighlight.tsx +2 -2
- package/src/components/charts/RadarChart/RadarChart.stories.tsx +14 -5
- package/src/components/charts/RadarChart/index.tsx +94 -45
- package/src/components/charts/RadialBarChart/RadialBarChart.stories.tsx +26 -1
- package/src/components/charts/RadialBarChart/index.tsx +100 -34
- package/src/components/charts/RadialLineChart/RadialLineChart.stories.tsx +19 -2
- package/src/components/charts/RadialLineChart/index.tsx +116 -26
- package/src/components/charts/index.tsx +0 -26
- package/src/components/charts/util.ts +50 -12
- package/src/components/data/CountryList/index.tsx +146 -0
- package/src/components/data/Stats/Sparkline.tsx +48 -0
- package/src/components/data/Stats/Stat.tsx +15 -4
- package/src/components/data/Stats/context.tsx +1 -1
- package/src/components/data/Stats/index.tsx +8 -3
- package/src/components/data/index.ts +3 -0
- package/src/components/feedback/IconTooltip/index.tsx +9 -6
- package/src/components/feedback/ProgressBar/ProgressBar.stories.tsx +13 -14
- package/src/components/feedback/ProgressBar/index.tsx +1 -1
- package/src/components/inputs/DurationField/__tests__/Generic.test.tsx +12 -0
- package/src/components/visual/Card/CardTitle.tsx +7 -1
- package/src/components/visual/Card/index.tsx +0 -4
- package/src/helpers/formatNumber.ts +6 -0
- package/src/helpers/index.ts +1 -0
- package/vite.config.mts +4 -0
- package/src/components/charts/echarts/EChartsArea.stories.tsx +0 -139
- package/src/components/charts/echarts/EChartsArea.tsx +0 -139
- package/src/components/charts/echarts/EChartsBar.stories.tsx +0 -141
- package/src/components/charts/echarts/EChartsBar.tsx +0 -133
- package/src/components/charts/echarts/EChartsBase.tsx +0 -264
- package/src/components/charts/echarts/EChartsFunnel.stories.tsx +0 -164
- package/src/components/charts/echarts/EChartsFunnel.tsx +0 -114
- package/src/components/charts/echarts/EChartsHeatmap.stories.tsx +0 -168
- package/src/components/charts/echarts/EChartsHeatmap.tsx +0 -141
- package/src/components/charts/echarts/EChartsLine.stories.tsx +0 -132
- package/src/components/charts/echarts/EChartsLine.tsx +0 -111
- package/src/components/charts/echarts/EChartsPie.stories.tsx +0 -131
- package/src/components/charts/echarts/EChartsPie.tsx +0 -124
- package/src/components/charts/echarts/EChartsRadialBar.stories.tsx +0 -124
- package/src/components/charts/echarts/EChartsRadialBar.tsx +0 -118
- package/src/components/charts/echarts/EChartsScatter.stories.tsx +0 -166
- package/src/components/charts/echarts/EChartsScatter.tsx +0 -135
- package/src/components/charts/echarts/index.ts +0 -26
|
@@ -6,11 +6,7 @@ import { styled } from '../../../styled';
|
|
|
6
6
|
|
|
7
7
|
const ButtonContainer = styled.div`
|
|
8
8
|
display: flex;
|
|
9
|
-
|
|
10
|
-
&:first-child {
|
|
11
|
-
margin: 0 1rem;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
9
|
+
gap: ${({ theme }) => theme.spacing[1]};
|
|
14
10
|
`;
|
|
15
11
|
|
|
16
12
|
export default {
|
|
@@ -18,22 +14,25 @@ export default {
|
|
|
18
14
|
component: ProgressBar,
|
|
19
15
|
args: {
|
|
20
16
|
mode: 'indeterminate',
|
|
21
|
-
|
|
17
|
+
showPercentage: false,
|
|
22
18
|
},
|
|
23
19
|
} as Meta<ProgressBarProps>;
|
|
24
20
|
|
|
25
|
-
export const Default: StoryFn<ProgressBarProps> = (args) =>
|
|
26
|
-
|
|
27
|
-
export const Determinate: StoryFn<ProgressBarProps> = () => {
|
|
21
|
+
export const Default: StoryFn<ProgressBarProps> = (args) => {
|
|
28
22
|
const [value, setValue] = useState<number>(0);
|
|
29
23
|
|
|
30
24
|
return (
|
|
31
25
|
<>
|
|
32
|
-
<ProgressBar
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
26
|
+
<ProgressBar {...args} value={value} />
|
|
27
|
+
|
|
28
|
+
{args.mode === 'determinate' && (
|
|
29
|
+
<ButtonContainer>
|
|
30
|
+
<button onClick={() => setValue(value - 10)}>-10</button>
|
|
31
|
+
<button onClick={() => setValue(value - 5)}>-5</button>
|
|
32
|
+
<button onClick={() => setValue(value + 5)}>+5</button>
|
|
33
|
+
<button onClick={() => setValue(value + 10)}>+10</button>
|
|
34
|
+
</ButtonContainer>
|
|
35
|
+
)}
|
|
37
36
|
</>
|
|
38
37
|
);
|
|
39
38
|
};
|
|
@@ -124,7 +124,7 @@ export const ProgressBar: FC<ProgressBarProps> = ({
|
|
|
124
124
|
return (
|
|
125
125
|
<Container>
|
|
126
126
|
<Progress color={color} progress={value > minFill ? value : value == 0 ? 0 : minFill} size={size} />
|
|
127
|
-
{showPercentage && <Label>{Math.min(value, 100)}%</Label>}
|
|
127
|
+
{showPercentage && <Label>{Math.max(0, Math.min(value, 100))}%</Label>}
|
|
128
128
|
</Container>
|
|
129
129
|
);
|
|
130
130
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Duration } from 'luxon';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
|
|
4
|
+
describe('DurationField - Luxon year conversion bug', () => {
|
|
5
|
+
it('should correctly round-trip 20 years through milliseconds without rescale drift', () => {
|
|
6
|
+
const originalYears = 20;
|
|
7
|
+
const millis = Duration.fromObject({ years: originalYears }).toMillis();
|
|
8
|
+
const rescaled = Duration.fromMillis(millis).rescale().toObject();
|
|
9
|
+
|
|
10
|
+
expect(rescaled).toEqual({ years: originalYears });
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -9,6 +9,12 @@ const Container = styled.div`
|
|
|
9
9
|
padding: ${({ theme }) => theme.spacing[1]};
|
|
10
10
|
`;
|
|
11
11
|
|
|
12
|
+
const Inner = styled.div`
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
gap: ${({ theme }) => theme.spacing['0_5']};
|
|
16
|
+
`;
|
|
17
|
+
|
|
12
18
|
interface CardTitleProps {
|
|
13
19
|
label: string;
|
|
14
20
|
}
|
|
@@ -17,7 +23,7 @@ export const CardTitle: FC<PropsWithChildren<CardTitleProps>> = (props) => {
|
|
|
17
23
|
return (
|
|
18
24
|
<Container>
|
|
19
25
|
<h2>{props.label}</h2>
|
|
20
|
-
<
|
|
26
|
+
<Inner>{props.children}</Inner>
|
|
21
27
|
</Container>
|
|
22
28
|
);
|
|
23
29
|
};
|
|
@@ -13,10 +13,6 @@ const Container = styled.div<{ canClick: boolean; variant: Variant }>`
|
|
|
13
13
|
cursor: ${({ canClick }) => (canClick ? 'pointer' : 'default')};
|
|
14
14
|
height: fit-content;
|
|
15
15
|
|
|
16
|
-
&:focus-within {
|
|
17
|
-
border-color: none;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
16
|
&:focus {
|
|
21
17
|
border-color: ${({ theme, canClick }) => (canClick ? theme.colors.primary : theme.colors.backgroundAccent)};
|
|
22
18
|
}
|
package/src/helpers/index.ts
CHANGED
package/vite.config.mts
CHANGED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Meta, StoryFn } from '@storybook/react';
|
|
3
|
-
import { EChartsArea, EChartsAreaProps } from './EChartsArea';
|
|
4
|
-
import { styled } from '../../../styled';
|
|
5
|
-
import { Card } from '../../../components';
|
|
6
|
-
import { faker } from '@faker-js/faker';
|
|
7
|
-
|
|
8
|
-
export default {
|
|
9
|
-
title: 'Charts/ECharts/Area',
|
|
10
|
-
component: EChartsArea,
|
|
11
|
-
args: {
|
|
12
|
-
smooth: true,
|
|
13
|
-
gradient: true,
|
|
14
|
-
showGrid: true,
|
|
15
|
-
showLegend: true,
|
|
16
|
-
xAxisLabel: 'Date',
|
|
17
|
-
yAxisLabel: 'Revenue ($)',
|
|
18
|
-
title: 'Area Chart Example',
|
|
19
|
-
},
|
|
20
|
-
} as Meta<EChartsAreaProps>;
|
|
21
|
-
|
|
22
|
-
const Wrapper = styled.div`
|
|
23
|
-
height: 500px;
|
|
24
|
-
width: 100%;
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
interface RevenueData {
|
|
28
|
-
date: string;
|
|
29
|
-
revenue: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Generate sample revenue data
|
|
33
|
-
function generateRevenueData(days: number = 30): RevenueData[] {
|
|
34
|
-
const data: RevenueData[] = [];
|
|
35
|
-
const now = new Date();
|
|
36
|
-
const baseValue = 1000;
|
|
37
|
-
|
|
38
|
-
for (let i = days - 1; i >= 0; i--) {
|
|
39
|
-
const date = new Date(now);
|
|
40
|
-
date.setDate(date.getDate() - i);
|
|
41
|
-
|
|
42
|
-
// Add some realistic variation
|
|
43
|
-
const dayOfWeek = date.getDay();
|
|
44
|
-
const weekendBonus = dayOfWeek === 0 || dayOfWeek === 6 ? 300 : 0;
|
|
45
|
-
const randomVariation = faker.number.int({ min: -200, max: 400 });
|
|
46
|
-
const trendGrowth = i * 5; // Slight upward trend
|
|
47
|
-
|
|
48
|
-
data.push({
|
|
49
|
-
date: date.toLocaleDateString(),
|
|
50
|
-
revenue: baseValue + weekendBonus + randomVariation + trendGrowth,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return data;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export const Default: StoryFn<EChartsAreaProps<RevenueData>> = (args) => {
|
|
58
|
-
const data = generateRevenueData();
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<Wrapper>
|
|
62
|
-
<EChartsArea<RevenueData>
|
|
63
|
-
{...args}
|
|
64
|
-
data={data}
|
|
65
|
-
xAccessor={(d) => d.date}
|
|
66
|
-
yAccessor={(d) => d.revenue}
|
|
67
|
-
seriesName="Daily Revenue"
|
|
68
|
-
/>
|
|
69
|
-
</Wrapper>
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export const NoGradient: StoryFn<EChartsAreaProps<RevenueData>> = (args) => {
|
|
74
|
-
const data = generateRevenueData();
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<Wrapper>
|
|
78
|
-
<EChartsArea<RevenueData>
|
|
79
|
-
{...args}
|
|
80
|
-
data={data}
|
|
81
|
-
xAccessor={(d) => d.date}
|
|
82
|
-
yAccessor={(d) => d.revenue}
|
|
83
|
-
seriesName="Revenue"
|
|
84
|
-
gradient={false}
|
|
85
|
-
title="Revenue Trend"
|
|
86
|
-
subtitle="Solid fill area chart"
|
|
87
|
-
/>
|
|
88
|
-
</Wrapper>
|
|
89
|
-
);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export const ShopAnalytics: StoryFn = () => {
|
|
93
|
-
const data = generateRevenueData(90);
|
|
94
|
-
|
|
95
|
-
return (
|
|
96
|
-
<Wrapper>
|
|
97
|
-
<Card variant="outline">
|
|
98
|
-
<Card.Title label="Revenue Over Time" />
|
|
99
|
-
<Card.Body>
|
|
100
|
-
<div style={{ height: '400px' }}>
|
|
101
|
-
<EChartsArea
|
|
102
|
-
data={data}
|
|
103
|
-
xAccessor={(d) => d.date}
|
|
104
|
-
yAccessor={(d) => d.revenue}
|
|
105
|
-
seriesName="Revenue"
|
|
106
|
-
smooth={true}
|
|
107
|
-
gradient={true}
|
|
108
|
-
showGrid={true}
|
|
109
|
-
yAxisLabel="Revenue ($)"
|
|
110
|
-
tooltipFormatter={(params: any) => {
|
|
111
|
-
const value = params[0].value;
|
|
112
|
-
return `${params[0].name}<br/>Revenue: $${value.toLocaleString()}`;
|
|
113
|
-
}}
|
|
114
|
-
/>
|
|
115
|
-
</div>
|
|
116
|
-
</Card.Body>
|
|
117
|
-
</Card>
|
|
118
|
-
</Wrapper>
|
|
119
|
-
);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
export const StackedArea: StoryFn<EChartsAreaProps<RevenueData>> = (args) => {
|
|
123
|
-
const data = generateRevenueData(20);
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<Wrapper>
|
|
127
|
-
<EChartsArea<RevenueData>
|
|
128
|
-
{...args}
|
|
129
|
-
data={data}
|
|
130
|
-
xAccessor={(d) => d.date}
|
|
131
|
-
yAccessor={(d) => d.revenue}
|
|
132
|
-
seriesName="Product Sales"
|
|
133
|
-
stack={true}
|
|
134
|
-
title="Stacked Revenue"
|
|
135
|
-
subtitle="Multiple product categories"
|
|
136
|
-
/>
|
|
137
|
-
</Wrapper>
|
|
138
|
-
);
|
|
139
|
-
};
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { FC, useMemo } from 'react';
|
|
2
|
-
import { EChartsOption } from 'echarts';
|
|
3
|
-
import { ResponsiveECharts, EChartsBaseProps } from './EChartsBase';
|
|
4
|
-
import { useTheme } from '../../../hooks';
|
|
5
|
-
|
|
6
|
-
export interface EChartsAreaProps<T = any> extends Omit<EChartsBaseProps, 'option'> {
|
|
7
|
-
data: T[];
|
|
8
|
-
xAccessor: (d: T) => string | number | Date;
|
|
9
|
-
yAccessor: (d: T) => number;
|
|
10
|
-
seriesName?: string;
|
|
11
|
-
smooth?: boolean;
|
|
12
|
-
showGrid?: boolean;
|
|
13
|
-
showLegend?: boolean;
|
|
14
|
-
xAxisLabel?: string;
|
|
15
|
-
yAxisLabel?: string;
|
|
16
|
-
title?: string;
|
|
17
|
-
subtitle?: string;
|
|
18
|
-
gradient?: boolean;
|
|
19
|
-
tooltipFormatter?: (params: any) => string;
|
|
20
|
-
stack?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const EChartsArea: FC<EChartsAreaProps> = ({
|
|
24
|
-
data,
|
|
25
|
-
xAccessor,
|
|
26
|
-
yAccessor,
|
|
27
|
-
seriesName = 'Value',
|
|
28
|
-
smooth = true,
|
|
29
|
-
showGrid = true,
|
|
30
|
-
showLegend = false,
|
|
31
|
-
xAxisLabel,
|
|
32
|
-
yAxisLabel,
|
|
33
|
-
title,
|
|
34
|
-
subtitle,
|
|
35
|
-
gradient = true,
|
|
36
|
-
tooltipFormatter,
|
|
37
|
-
stack = false,
|
|
38
|
-
...chartProps
|
|
39
|
-
}) => {
|
|
40
|
-
const theme = useTheme();
|
|
41
|
-
|
|
42
|
-
const option: EChartsOption = useMemo(() => {
|
|
43
|
-
const xData = data.map(xAccessor);
|
|
44
|
-
const yData = data.map(yAccessor);
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
title: title
|
|
48
|
-
? {
|
|
49
|
-
text: title,
|
|
50
|
-
subtext: subtitle,
|
|
51
|
-
left: 'center',
|
|
52
|
-
}
|
|
53
|
-
: undefined,
|
|
54
|
-
legend: showLegend
|
|
55
|
-
? {
|
|
56
|
-
data: [seriesName],
|
|
57
|
-
top: 30,
|
|
58
|
-
}
|
|
59
|
-
: undefined,
|
|
60
|
-
grid: showGrid
|
|
61
|
-
? {
|
|
62
|
-
left: '3%',
|
|
63
|
-
right: '4%',
|
|
64
|
-
bottom: '3%',
|
|
65
|
-
containLabel: true,
|
|
66
|
-
}
|
|
67
|
-
: undefined,
|
|
68
|
-
tooltip: {
|
|
69
|
-
trigger: 'axis',
|
|
70
|
-
formatter: tooltipFormatter,
|
|
71
|
-
},
|
|
72
|
-
xAxis: {
|
|
73
|
-
type: 'category',
|
|
74
|
-
data: xData,
|
|
75
|
-
name: xAxisLabel,
|
|
76
|
-
nameLocation: 'middle',
|
|
77
|
-
nameGap: 30,
|
|
78
|
-
boundaryGap: false,
|
|
79
|
-
},
|
|
80
|
-
yAxis: {
|
|
81
|
-
type: 'value',
|
|
82
|
-
name: yAxisLabel,
|
|
83
|
-
nameLocation: 'middle',
|
|
84
|
-
nameGap: 50,
|
|
85
|
-
},
|
|
86
|
-
series: [
|
|
87
|
-
{
|
|
88
|
-
name: seriesName,
|
|
89
|
-
type: 'line',
|
|
90
|
-
data: yData,
|
|
91
|
-
smooth: smooth,
|
|
92
|
-
stack: stack ? 'total' : undefined,
|
|
93
|
-
areaStyle: gradient
|
|
94
|
-
? {
|
|
95
|
-
color: {
|
|
96
|
-
type: 'linear',
|
|
97
|
-
x: 0,
|
|
98
|
-
y: 0,
|
|
99
|
-
x2: 0,
|
|
100
|
-
y2: 1,
|
|
101
|
-
colorStops: [
|
|
102
|
-
{
|
|
103
|
-
offset: 0,
|
|
104
|
-
color: theme.colors.primary + '80', // 50% opacity
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
offset: 1,
|
|
108
|
-
color: theme.colors.primary + '10', // 6% opacity
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
},
|
|
112
|
-
}
|
|
113
|
-
: {},
|
|
114
|
-
emphasis: {
|
|
115
|
-
focus: 'series',
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
};
|
|
120
|
-
}, [
|
|
121
|
-
data,
|
|
122
|
-
xAccessor,
|
|
123
|
-
yAccessor,
|
|
124
|
-
seriesName,
|
|
125
|
-
smooth,
|
|
126
|
-
showGrid,
|
|
127
|
-
showLegend,
|
|
128
|
-
xAxisLabel,
|
|
129
|
-
yAxisLabel,
|
|
130
|
-
title,
|
|
131
|
-
subtitle,
|
|
132
|
-
gradient,
|
|
133
|
-
tooltipFormatter,
|
|
134
|
-
stack,
|
|
135
|
-
theme,
|
|
136
|
-
]);
|
|
137
|
-
|
|
138
|
-
return <ResponsiveECharts option={option} {...chartProps} />;
|
|
139
|
-
};
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Meta, StoryFn } from '@storybook/react';
|
|
3
|
-
import { EChartsBar, EChartsBarProps } from './EChartsBar';
|
|
4
|
-
import { styled } from '../../../styled';
|
|
5
|
-
import { Card } from '../../../components';
|
|
6
|
-
import { faker } from '@faker-js/faker';
|
|
7
|
-
|
|
8
|
-
export default {
|
|
9
|
-
title: 'Charts/ECharts/Bar',
|
|
10
|
-
component: EChartsBar,
|
|
11
|
-
args: {
|
|
12
|
-
horizontal: false,
|
|
13
|
-
showGrid: true,
|
|
14
|
-
showLegend: true,
|
|
15
|
-
xAxisLabel: 'Category',
|
|
16
|
-
yAxisLabel: 'Value',
|
|
17
|
-
title: 'Bar Chart Example',
|
|
18
|
-
colorBy: 'data',
|
|
19
|
-
},
|
|
20
|
-
} as Meta<EChartsBarProps>;
|
|
21
|
-
|
|
22
|
-
const Wrapper = styled.div`
|
|
23
|
-
height: 500px;
|
|
24
|
-
width: 100%;
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
interface CategoryData {
|
|
28
|
-
name: string;
|
|
29
|
-
value: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Generate sample category data
|
|
33
|
-
function generateCategoryData(count: number = 10): CategoryData[] {
|
|
34
|
-
const categories = [
|
|
35
|
-
'Weapons',
|
|
36
|
-
'Armor',
|
|
37
|
-
'Tools',
|
|
38
|
-
'Food',
|
|
39
|
-
'Materials',
|
|
40
|
-
'Potions',
|
|
41
|
-
'Books',
|
|
42
|
-
'Gems',
|
|
43
|
-
'Artifacts',
|
|
44
|
-
'Misc',
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
return categories.slice(0, count).map((name) => ({
|
|
48
|
-
name,
|
|
49
|
-
value: faker.number.int({ min: 10, max: 200 }),
|
|
50
|
-
}));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const Default: StoryFn<EChartsBarProps<CategoryData>> = (args) => {
|
|
54
|
-
const data = generateCategoryData(8);
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<Wrapper>
|
|
58
|
-
<EChartsBar<CategoryData>
|
|
59
|
-
{...args}
|
|
60
|
-
data={data}
|
|
61
|
-
xAccessor={(d) => d.name}
|
|
62
|
-
yAccessor={(d) => d.value}
|
|
63
|
-
seriesName="Sales"
|
|
64
|
-
/>
|
|
65
|
-
</Wrapper>
|
|
66
|
-
);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export const HorizontalBar: StoryFn<EChartsBarProps<CategoryData>> = (args) => {
|
|
70
|
-
const data = generateCategoryData(6);
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<Wrapper>
|
|
74
|
-
<EChartsBar<CategoryData>
|
|
75
|
-
{...args}
|
|
76
|
-
data={data}
|
|
77
|
-
xAccessor={(d) => d.name}
|
|
78
|
-
yAccessor={(d) => d.value}
|
|
79
|
-
seriesName="Inventory"
|
|
80
|
-
horizontal={true}
|
|
81
|
-
title="Item Inventory"
|
|
82
|
-
subtitle="Current stock levels"
|
|
83
|
-
xAxisLabel="Quantity"
|
|
84
|
-
yAxisLabel=""
|
|
85
|
-
/>
|
|
86
|
-
</Wrapper>
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const TopSellingItems: StoryFn = () => {
|
|
91
|
-
const products = [
|
|
92
|
-
{ name: 'Diamond Sword', revenue: 15000 },
|
|
93
|
-
{ name: 'Iron Pickaxe', revenue: 12000 },
|
|
94
|
-
{ name: 'Golden Apple', revenue: 9500 },
|
|
95
|
-
{ name: 'Enchanted Book', revenue: 8000 },
|
|
96
|
-
{ name: 'Ender Pearl', revenue: 6500 },
|
|
97
|
-
];
|
|
98
|
-
|
|
99
|
-
return (
|
|
100
|
-
<Wrapper>
|
|
101
|
-
<Card variant="outline">
|
|
102
|
-
<Card.Title label="Top Selling Items" />
|
|
103
|
-
<Card.Body>
|
|
104
|
-
<div style={{ height: '400px' }}>
|
|
105
|
-
<EChartsBar
|
|
106
|
-
data={products}
|
|
107
|
-
xAccessor={(d) => d.name}
|
|
108
|
-
yAccessor={(d) => d.revenue}
|
|
109
|
-
seriesName="Revenue"
|
|
110
|
-
colorBy="data"
|
|
111
|
-
showGrid={true}
|
|
112
|
-
yAxisLabel="Revenue ($)"
|
|
113
|
-
tooltipFormatter={(params: any) => {
|
|
114
|
-
return `${params[0].name}<br/>Revenue: $${params[0].value.toLocaleString()}`;
|
|
115
|
-
}}
|
|
116
|
-
/>
|
|
117
|
-
</div>
|
|
118
|
-
</Card.Body>
|
|
119
|
-
</Card>
|
|
120
|
-
</Wrapper>
|
|
121
|
-
);
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
export const MonochromeBar: StoryFn<EChartsBarProps<CategoryData>> = (args) => {
|
|
125
|
-
const data = generateCategoryData(12);
|
|
126
|
-
|
|
127
|
-
return (
|
|
128
|
-
<Wrapper>
|
|
129
|
-
<EChartsBar<CategoryData>
|
|
130
|
-
{...args}
|
|
131
|
-
data={data}
|
|
132
|
-
xAccessor={(d) => d.name}
|
|
133
|
-
yAccessor={(d) => d.value}
|
|
134
|
-
seriesName="Activity"
|
|
135
|
-
colorBy="series"
|
|
136
|
-
title="Player Activity by Hour"
|
|
137
|
-
barWidth="60%"
|
|
138
|
-
/>
|
|
139
|
-
</Wrapper>
|
|
140
|
-
);
|
|
141
|
-
};
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { FC, useMemo } from 'react';
|
|
2
|
-
import { EChartsOption } from 'echarts';
|
|
3
|
-
import { ResponsiveECharts, EChartsBaseProps } from './EChartsBase';
|
|
4
|
-
|
|
5
|
-
export interface EChartsBarProps<T = any> extends Omit<EChartsBaseProps, 'option'> {
|
|
6
|
-
data: T[];
|
|
7
|
-
xAccessor: (d: T) => string | number;
|
|
8
|
-
yAccessor: (d: T) => number;
|
|
9
|
-
seriesName?: string;
|
|
10
|
-
horizontal?: boolean;
|
|
11
|
-
showGrid?: boolean;
|
|
12
|
-
showLegend?: boolean;
|
|
13
|
-
xAxisLabel?: string;
|
|
14
|
-
yAxisLabel?: string;
|
|
15
|
-
title?: string;
|
|
16
|
-
subtitle?: string;
|
|
17
|
-
barWidth?: string | number;
|
|
18
|
-
barGap?: string;
|
|
19
|
-
tooltipFormatter?: (params: any) => string;
|
|
20
|
-
colorBy?: 'series' | 'data';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const EChartsBar: FC<EChartsBarProps> = ({
|
|
24
|
-
data,
|
|
25
|
-
xAccessor,
|
|
26
|
-
yAccessor,
|
|
27
|
-
seriesName = 'Value',
|
|
28
|
-
horizontal = false,
|
|
29
|
-
showGrid = true,
|
|
30
|
-
showLegend = false,
|
|
31
|
-
xAxisLabel,
|
|
32
|
-
yAxisLabel,
|
|
33
|
-
title,
|
|
34
|
-
subtitle,
|
|
35
|
-
barWidth,
|
|
36
|
-
barGap = '30%',
|
|
37
|
-
tooltipFormatter,
|
|
38
|
-
colorBy = 'series',
|
|
39
|
-
...chartProps
|
|
40
|
-
}) => {
|
|
41
|
-
const option: EChartsOption = useMemo(() => {
|
|
42
|
-
const categories = data.map(xAccessor);
|
|
43
|
-
const values = data.map(yAccessor);
|
|
44
|
-
|
|
45
|
-
const xAxisConfig = {
|
|
46
|
-
type: horizontal ? 'value' : 'category',
|
|
47
|
-
data: horizontal ? undefined : categories,
|
|
48
|
-
name: xAxisLabel,
|
|
49
|
-
nameLocation: 'middle',
|
|
50
|
-
nameGap: 30,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const yAxisConfig = {
|
|
54
|
-
type: horizontal ? 'category' : 'value',
|
|
55
|
-
data: horizontal ? categories : undefined,
|
|
56
|
-
name: yAxisLabel,
|
|
57
|
-
nameLocation: 'middle',
|
|
58
|
-
nameGap: 50,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
title: title
|
|
63
|
-
? {
|
|
64
|
-
text: title,
|
|
65
|
-
subtext: subtitle,
|
|
66
|
-
left: 'center',
|
|
67
|
-
}
|
|
68
|
-
: undefined,
|
|
69
|
-
legend: showLegend
|
|
70
|
-
? {
|
|
71
|
-
data: [seriesName],
|
|
72
|
-
top: 30,
|
|
73
|
-
}
|
|
74
|
-
: undefined,
|
|
75
|
-
grid: showGrid
|
|
76
|
-
? {
|
|
77
|
-
left: '3%',
|
|
78
|
-
right: '4%',
|
|
79
|
-
bottom: '3%',
|
|
80
|
-
containLabel: true,
|
|
81
|
-
}
|
|
82
|
-
: undefined,
|
|
83
|
-
tooltip: {
|
|
84
|
-
trigger: 'axis',
|
|
85
|
-
axisPointer: {
|
|
86
|
-
type: 'shadow',
|
|
87
|
-
},
|
|
88
|
-
formatter: tooltipFormatter,
|
|
89
|
-
},
|
|
90
|
-
xAxis: xAxisConfig as any,
|
|
91
|
-
yAxis: yAxisConfig as any,
|
|
92
|
-
series: [
|
|
93
|
-
{
|
|
94
|
-
name: seriesName,
|
|
95
|
-
type: 'bar',
|
|
96
|
-
data: values,
|
|
97
|
-
barWidth: barWidth,
|
|
98
|
-
barGap: barGap,
|
|
99
|
-
itemStyle:
|
|
100
|
-
colorBy === 'data'
|
|
101
|
-
? {
|
|
102
|
-
color: (params: any) => {
|
|
103
|
-
const colors = ['#664de5', '#3ccd6A', '#f57c00', '#ff4252', '#06b6d4'];
|
|
104
|
-
return colors[params.dataIndex % colors.length];
|
|
105
|
-
},
|
|
106
|
-
}
|
|
107
|
-
: undefined,
|
|
108
|
-
emphasis: {
|
|
109
|
-
focus: 'series',
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
};
|
|
114
|
-
}, [
|
|
115
|
-
data,
|
|
116
|
-
xAccessor,
|
|
117
|
-
yAccessor,
|
|
118
|
-
seriesName,
|
|
119
|
-
horizontal,
|
|
120
|
-
showGrid,
|
|
121
|
-
showLegend,
|
|
122
|
-
xAxisLabel,
|
|
123
|
-
yAxisLabel,
|
|
124
|
-
title,
|
|
125
|
-
subtitle,
|
|
126
|
-
barWidth,
|
|
127
|
-
barGap,
|
|
128
|
-
tooltipFormatter,
|
|
129
|
-
colorBy,
|
|
130
|
-
]);
|
|
131
|
-
|
|
132
|
-
return <ResponsiveECharts option={option} {...chartProps} />;
|
|
133
|
-
};
|