@takaro/lib-components 0.3.3 → 0.4.0

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.
@@ -0,0 +1,124 @@
1
+ import React from 'react';
2
+ import { Meta, StoryFn } from '@storybook/react';
3
+ import { EChartsRadialBar, EChartsRadialBarProps } from './EChartsRadialBar';
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/RadialBar',
10
+ component: EChartsRadialBar,
11
+ args: {
12
+ showLegend: true,
13
+ title: 'Radial Bar Chart',
14
+ angleAxis: true,
15
+ },
16
+ } as Meta<EChartsRadialBarProps>;
17
+
18
+ const Wrapper = styled.div`
19
+ height: 500px;
20
+ width: 100%;
21
+ `;
22
+
23
+ interface CategoryData {
24
+ category: string;
25
+ value: number;
26
+ }
27
+
28
+ // Generate sample category data
29
+ function generateCategoryData(): CategoryData[] {
30
+ return [
31
+ { category: 'Weapons', value: faker.number.int({ min: 50, max: 150 }) },
32
+ { category: 'Armor', value: faker.number.int({ min: 40, max: 120 }) },
33
+ { category: 'Consumables', value: faker.number.int({ min: 60, max: 180 }) },
34
+ { category: 'Materials', value: faker.number.int({ min: 30, max: 100 }) },
35
+ { category: 'Special', value: faker.number.int({ min: 20, max: 80 }) },
36
+ ];
37
+ }
38
+
39
+ export const Default: StoryFn<EChartsRadialBarProps<CategoryData>> = (args) => {
40
+ const data = generateCategoryData();
41
+
42
+ return (
43
+ <Wrapper>
44
+ <EChartsRadialBar<CategoryData>
45
+ {...args}
46
+ data={data}
47
+ nameAccessor={(d) => d.category}
48
+ valueAccessor={(d) => d.value}
49
+ seriesName="Sales"
50
+ />
51
+ </Wrapper>
52
+ );
53
+ };
54
+
55
+ export const CategoryPerformance: StoryFn = () => {
56
+ const categories = [
57
+ { category: 'Building', value: 85 },
58
+ { category: 'Combat', value: 120 },
59
+ { category: 'Exploration', value: 95 },
60
+ { category: 'Crafting', value: 110 },
61
+ { category: 'Trading', value: 75 },
62
+ { category: 'Farming', value: 60 },
63
+ ];
64
+
65
+ return (
66
+ <Wrapper>
67
+ <Card variant="outline">
68
+ <Card.Title label="Category Performance" />
69
+ <Card.Body>
70
+ <div style={{ height: '400px' }}>
71
+ <EChartsRadialBar
72
+ data={categories}
73
+ nameAccessor={(d) => d.category}
74
+ valueAccessor={(d) => d.value}
75
+ seriesName="Performance Score"
76
+ showLegend={false}
77
+ radius={['25%', '75%']}
78
+ tooltipFormatter={(params: any) => {
79
+ return `${params.name}<br/>Score: ${params.value}`;
80
+ }}
81
+ />
82
+ </div>
83
+ </Card.Body>
84
+ </Card>
85
+ </Wrapper>
86
+ );
87
+ };
88
+
89
+ export const SmallRadius: StoryFn<EChartsRadialBarProps<CategoryData>> = (args) => {
90
+ const data = generateCategoryData().slice(0, 4);
91
+
92
+ return (
93
+ <Wrapper>
94
+ <EChartsRadialBar<CategoryData>
95
+ {...args}
96
+ data={data}
97
+ nameAccessor={(d) => d.category}
98
+ valueAccessor={(d) => d.value}
99
+ seriesName="Inventory"
100
+ title="Stock Levels"
101
+ subtitle="Current inventory status"
102
+ radius={['40%', '60%']}
103
+ />
104
+ </Wrapper>
105
+ );
106
+ };
107
+
108
+ export const AlternateAxis: StoryFn<EChartsRadialBarProps<CategoryData>> = (args) => {
109
+ const data = generateCategoryData();
110
+
111
+ return (
112
+ <Wrapper>
113
+ <EChartsRadialBar<CategoryData>
114
+ {...args}
115
+ data={data}
116
+ nameAccessor={(d) => d.category}
117
+ valueAccessor={(d) => d.value}
118
+ seriesName="Distribution"
119
+ angleAxis={false}
120
+ title="Resource Distribution"
121
+ />
122
+ </Wrapper>
123
+ );
124
+ };
@@ -0,0 +1,118 @@
1
+ import { FC, useMemo } from 'react';
2
+ import { EChartsOption } from 'echarts';
3
+ import { ResponsiveECharts, EChartsBaseProps } from './EChartsBase';
4
+
5
+ export interface EChartsRadialBarProps<T = any> extends Omit<EChartsBaseProps, 'option'> {
6
+ data: T[];
7
+ nameAccessor: (d: T) => string;
8
+ valueAccessor: (d: T) => number;
9
+ seriesName?: string;
10
+ showLegend?: boolean;
11
+ showLabel?: boolean;
12
+ title?: string;
13
+ subtitle?: string;
14
+ tooltipFormatter?: (params: any) => string;
15
+ radius?: [string, string];
16
+ angleAxis?: boolean;
17
+ }
18
+
19
+ export const EChartsRadialBar: FC<EChartsRadialBarProps> = ({
20
+ data,
21
+ nameAccessor,
22
+ valueAccessor,
23
+ seriesName = 'Value',
24
+ showLegend = true,
25
+ showLabel = false,
26
+ title,
27
+ subtitle,
28
+ tooltipFormatter,
29
+ radius = ['30%', '80%'],
30
+ angleAxis = true,
31
+ ...chartProps
32
+ }) => {
33
+ const option: EChartsOption = useMemo(() => {
34
+ const categories = data.map(nameAccessor);
35
+ const values = data.map(valueAccessor);
36
+ const maxValue = Math.max(...values);
37
+
38
+ return {
39
+ title: title
40
+ ? {
41
+ text: title,
42
+ subtext: subtitle,
43
+ left: 'center',
44
+ }
45
+ : undefined,
46
+ legend: showLegend
47
+ ? {
48
+ show: true,
49
+ top: 'bottom',
50
+ }
51
+ : undefined,
52
+ tooltip: {
53
+ trigger: 'item',
54
+ formatter: tooltipFormatter,
55
+ },
56
+ polar: {
57
+ radius: radius,
58
+ },
59
+ radiusAxis: angleAxis
60
+ ? {
61
+ type: 'category',
62
+ data: categories,
63
+ z: 10,
64
+ }
65
+ : {
66
+ max: maxValue * 1.1,
67
+ },
68
+ angleAxis: angleAxis
69
+ ? {
70
+ max: maxValue * 1.1,
71
+ }
72
+ : {
73
+ type: 'category',
74
+ data: categories,
75
+ },
76
+ series: [
77
+ {
78
+ name: seriesName,
79
+ type: 'bar',
80
+ data: values.map((value, index) => ({
81
+ value,
82
+ name: categories[index],
83
+ itemStyle: {
84
+ opacity: 0.9,
85
+ },
86
+ })),
87
+ coordinateSystem: 'polar',
88
+ label: showLabel
89
+ ? {
90
+ show: true,
91
+ position: 'middle',
92
+ formatter: '{b}: {c}',
93
+ }
94
+ : {
95
+ show: false,
96
+ },
97
+ emphasis: {
98
+ focus: 'series',
99
+ },
100
+ },
101
+ ],
102
+ };
103
+ }, [
104
+ data,
105
+ nameAccessor,
106
+ valueAccessor,
107
+ seriesName,
108
+ showLegend,
109
+ showLabel,
110
+ title,
111
+ subtitle,
112
+ tooltipFormatter,
113
+ radius,
114
+ angleAxis,
115
+ ]);
116
+
117
+ return <ResponsiveECharts option={option} {...chartProps} />;
118
+ };
@@ -0,0 +1,166 @@
1
+ import React from 'react';
2
+ import { Meta, StoryFn } from '@storybook/react';
3
+ import { EChartsScatter, EChartsScatterProps } from './EChartsScatter';
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/Scatter',
10
+ component: EChartsScatter,
11
+ args: {
12
+ showGrid: true,
13
+ showLegend: false,
14
+ xAxisLabel: 'X Axis',
15
+ yAxisLabel: 'Y Axis',
16
+ title: 'Scatter Plot',
17
+ symbolSize: 10,
18
+ },
19
+ } as Meta<EChartsScatterProps>;
20
+
21
+ const Wrapper = styled.div`
22
+ height: 500px;
23
+ width: 100%;
24
+ `;
25
+
26
+ interface ScatterData {
27
+ x: number;
28
+ y: number;
29
+ size?: number;
30
+ name?: string;
31
+ }
32
+
33
+ // Generate sample scatter data
34
+ function generateScatterData(count: number = 50): ScatterData[] {
35
+ const data: ScatterData[] = [];
36
+
37
+ for (let i = 0; i < count; i++) {
38
+ data.push({
39
+ x: faker.number.int({ min: 0, max: 100 }),
40
+ y: faker.number.int({ min: 0, max: 100 }),
41
+ size: faker.number.int({ min: 5, max: 50 }),
42
+ name: `Point ${i + 1}`,
43
+ });
44
+ }
45
+
46
+ return data;
47
+ }
48
+
49
+ export const Default: StoryFn<EChartsScatterProps<ScatterData>> = (args) => {
50
+ const data = generateScatterData();
51
+
52
+ return (
53
+ <Wrapper>
54
+ <EChartsScatter<ScatterData>
55
+ {...args}
56
+ data={data}
57
+ xAccessor={(d) => d.x}
58
+ yAccessor={(d) => d.y}
59
+ seriesName="Data Points"
60
+ />
61
+ </Wrapper>
62
+ );
63
+ };
64
+
65
+ export const BubbleChart: StoryFn<EChartsScatterProps<ScatterData>> = (args) => {
66
+ const data = generateScatterData(30);
67
+
68
+ return (
69
+ <Wrapper>
70
+ <EChartsScatter<ScatterData>
71
+ {...args}
72
+ data={data}
73
+ xAccessor={(d) => d.x}
74
+ yAccessor={(d) => d.y}
75
+ sizeAccessor={(d) => d.size || 10}
76
+ nameAccessor={(d) => d.name}
77
+ seriesName="Bubble Data"
78
+ title="Bubble Chart"
79
+ subtitle="Size represents third dimension"
80
+ />
81
+ </Wrapper>
82
+ );
83
+ };
84
+
85
+ export const PlayerAnalysis: StoryFn = () => {
86
+ // Generate player data with correlation
87
+ const players = Array.from({ length: 40 }, (_, i) => {
88
+ const playtime = faker.number.int({ min: 10, max: 200 });
89
+ const purchases = Math.floor(playtime * 0.3 + faker.number.int({ min: -10, max: 20 }));
90
+ const level = Math.floor(playtime * 0.5 + faker.number.int({ min: 0, max: 10 }));
91
+
92
+ return {
93
+ playtime,
94
+ purchases,
95
+ level,
96
+ name: `Player${i + 1}`,
97
+ };
98
+ });
99
+
100
+ return (
101
+ <Wrapper>
102
+ <Card variant="outline">
103
+ <Card.Title label="Player Behavior Analysis" />
104
+ <Card.Body>
105
+ <div style={{ height: '400px' }}>
106
+ <EChartsScatter
107
+ data={players}
108
+ xAccessor={(d) => d.playtime}
109
+ yAccessor={(d) => d.purchases}
110
+ sizeAccessor={(d) => d.level}
111
+ nameAccessor={(d) => d.name}
112
+ seriesName="Players"
113
+ xAxisLabel="Playtime (hours)"
114
+ yAxisLabel="Total Purchases"
115
+ showGrid={true}
116
+ tooltipFormatter={(params: any) => {
117
+ const value = params.value || params.data.value;
118
+ return `${params.data.name}<br/>
119
+ Playtime: ${value[0]} hours<br/>
120
+ Purchases: ${value[1]}<br/>
121
+ Level: ${value[2]}`;
122
+ }}
123
+ />
124
+ </div>
125
+ </Card.Body>
126
+ </Card>
127
+ </Wrapper>
128
+ );
129
+ };
130
+
131
+ export const Clustering: StoryFn<EChartsScatterProps<ScatterData>> = (args) => {
132
+ // Generate clustered data
133
+ const clusters = [
134
+ { cx: 25, cy: 25, spread: 10 },
135
+ { cx: 75, cy: 75, spread: 10 },
136
+ { cx: 25, cy: 75, spread: 8 },
137
+ { cx: 75, cy: 25, spread: 12 },
138
+ ];
139
+
140
+ const data: ScatterData[] = [];
141
+ clusters.forEach((cluster, clusterIndex) => {
142
+ for (let i = 0; i < 15; i++) {
143
+ data.push({
144
+ x: cluster.cx + faker.number.int({ min: -cluster.spread, max: cluster.spread }),
145
+ y: cluster.cy + faker.number.int({ min: -cluster.spread, max: cluster.spread }),
146
+ name: `Cluster ${clusterIndex + 1}`,
147
+ });
148
+ }
149
+ });
150
+
151
+ return (
152
+ <Wrapper>
153
+ <EChartsScatter<ScatterData>
154
+ {...args}
155
+ data={data}
156
+ xAccessor={(d) => d.x}
157
+ yAccessor={(d) => d.y}
158
+ nameAccessor={(d) => d.name}
159
+ seriesName="Clusters"
160
+ title="Data Clustering"
161
+ subtitle="Four distinct groups"
162
+ symbolSize={8}
163
+ />
164
+ </Wrapper>
165
+ );
166
+ };
@@ -0,0 +1,135 @@
1
+ import { FC, useMemo } from 'react';
2
+ import { EChartsOption } from 'echarts';
3
+ import { ResponsiveECharts, EChartsBaseProps } from './EChartsBase';
4
+
5
+ export interface EChartsScatterProps<T = any> extends Omit<EChartsBaseProps, 'option'> {
6
+ data: T[];
7
+ xAccessor: (d: T) => number;
8
+ yAccessor: (d: T) => number;
9
+ sizeAccessor?: (d: T) => number;
10
+ nameAccessor?: (d: T) => string;
11
+ seriesName?: string;
12
+ showGrid?: boolean;
13
+ showLegend?: boolean;
14
+ xAxisLabel?: string;
15
+ yAxisLabel?: string;
16
+ title?: string;
17
+ subtitle?: string;
18
+ symbolSize?: number | ((value: number[]) => number);
19
+ tooltipFormatter?: (params: any) => string;
20
+ }
21
+
22
+ export const EChartsScatter: FC<EChartsScatterProps> = ({
23
+ data,
24
+ xAccessor,
25
+ yAccessor,
26
+ sizeAccessor,
27
+ nameAccessor,
28
+ seriesName = 'Value',
29
+ showGrid = true,
30
+ showLegend = false,
31
+ xAxisLabel,
32
+ yAxisLabel,
33
+ title,
34
+ subtitle,
35
+ symbolSize = 10,
36
+ tooltipFormatter,
37
+ ...chartProps
38
+ }) => {
39
+ const option: EChartsOption = useMemo(() => {
40
+ const scatterData = data.map((d) => {
41
+ const point: any = [xAccessor(d), yAccessor(d)];
42
+ if (sizeAccessor) {
43
+ point.push(sizeAccessor(d));
44
+ }
45
+ if (nameAccessor) {
46
+ return {
47
+ value: point,
48
+ name: nameAccessor(d),
49
+ };
50
+ }
51
+ return point;
52
+ });
53
+
54
+ const actualSymbolSize = sizeAccessor ? (value: number[]) => Math.sqrt(value[2]) * 5 : symbolSize;
55
+
56
+ return {
57
+ title: title
58
+ ? {
59
+ text: title,
60
+ subtext: subtitle,
61
+ left: 'center',
62
+ }
63
+ : undefined,
64
+ legend: showLegend
65
+ ? {
66
+ data: [seriesName],
67
+ top: 30,
68
+ }
69
+ : undefined,
70
+ grid: showGrid
71
+ ? {
72
+ left: '3%',
73
+ right: '4%',
74
+ bottom: '3%',
75
+ containLabel: true,
76
+ }
77
+ : undefined,
78
+ tooltip: {
79
+ trigger: 'item',
80
+ formatter:
81
+ tooltipFormatter ||
82
+ ((params: any) => {
83
+ const value = params.value || params.data.value;
84
+ const name = params.data?.name || params.name || '';
85
+ return `${name}<br/>X: ${value[0]}<br/>Y: ${value[1]}${value[2] !== undefined ? `<br/>Size: ${value[2]}` : ''}`;
86
+ }),
87
+ },
88
+ xAxis: {
89
+ type: 'value',
90
+ name: xAxisLabel,
91
+ nameLocation: 'middle',
92
+ nameGap: 30,
93
+ },
94
+ yAxis: {
95
+ type: 'value',
96
+ name: yAxisLabel,
97
+ nameLocation: 'middle',
98
+ nameGap: 50,
99
+ },
100
+ series: [
101
+ {
102
+ name: seriesName,
103
+ type: 'scatter',
104
+ data: scatterData,
105
+ symbolSize: actualSymbolSize,
106
+ emphasis: {
107
+ focus: 'series',
108
+ itemStyle: {
109
+ shadowBlur: 10,
110
+ shadowOffsetX: 0,
111
+ shadowColor: 'rgba(0, 0, 0, 0.5)',
112
+ },
113
+ },
114
+ },
115
+ ],
116
+ };
117
+ }, [
118
+ data,
119
+ xAccessor,
120
+ yAccessor,
121
+ sizeAccessor,
122
+ nameAccessor,
123
+ seriesName,
124
+ showGrid,
125
+ showLegend,
126
+ xAxisLabel,
127
+ yAxisLabel,
128
+ title,
129
+ subtitle,
130
+ symbolSize,
131
+ tooltipFormatter,
132
+ ]);
133
+
134
+ return <ResponsiveECharts option={option} {...chartProps} />;
135
+ };
@@ -0,0 +1,26 @@
1
+ export { EChartsBase, ResponsiveECharts } from './EChartsBase';
2
+ export type { EChartsBaseProps } from './EChartsBase';
3
+
4
+ export { EChartsLine } from './EChartsLine';
5
+ export type { EChartsLineProps } from './EChartsLine';
6
+
7
+ export { EChartsBar } from './EChartsBar';
8
+ export type { EChartsBarProps } from './EChartsBar';
9
+
10
+ export { EChartsPie } from './EChartsPie';
11
+ export type { EChartsPieProps } from './EChartsPie';
12
+
13
+ export { EChartsArea } from './EChartsArea';
14
+ export type { EChartsAreaProps } from './EChartsArea';
15
+
16
+ export { EChartsHeatmap } from './EChartsHeatmap';
17
+ export type { EChartsHeatmapProps } from './EChartsHeatmap';
18
+
19
+ export { EChartsRadialBar } from './EChartsRadialBar';
20
+ export type { EChartsRadialBarProps } from './EChartsRadialBar';
21
+
22
+ export { EChartsScatter } from './EChartsScatter';
23
+ export type { EChartsScatterProps } from './EChartsScatter';
24
+
25
+ export { EChartsFunnel } from './EChartsFunnel';
26
+ export type { EChartsFunnelProps } from './EChartsFunnel';
@@ -24,3 +24,29 @@ export type { RadialBarChartProps } from './RadialBarChart';
24
24
 
25
25
  export { GeoMercator } from './GeoMercator';
26
26
  export type { GeoMercatorProps } from './GeoMercator';
27
+
28
+ // ECharts components
29
+ export {
30
+ EChartsBase,
31
+ ResponsiveECharts,
32
+ EChartsLine,
33
+ EChartsBar,
34
+ EChartsPie,
35
+ EChartsArea,
36
+ EChartsHeatmap,
37
+ EChartsRadialBar,
38
+ EChartsScatter,
39
+ EChartsFunnel,
40
+ } from './echarts';
41
+
42
+ export type {
43
+ EChartsBaseProps,
44
+ EChartsLineProps,
45
+ EChartsBarProps,
46
+ EChartsPieProps,
47
+ EChartsAreaProps,
48
+ EChartsHeatmapProps,
49
+ EChartsRadialBarProps,
50
+ EChartsScatterProps,
51
+ EChartsFunnelProps,
52
+ } from './echarts';
@@ -31,9 +31,7 @@ exports[`Should render <Alert/> 1`] = `
31
31
  Alert title
32
32
  </h2>
33
33
  <p>
34
- <p>
35
- Alert text
36
- </p>
34
+ Alert text
37
35
  </p>
38
36
  <div
39
37
  class="sc-fqkvVR JhYnd action"
@@ -87,7 +87,7 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(
87
87
  <Grid>
88
88
  <IconContainer variant={variant}>{getIcon()}</IconContainer>
89
89
  {title && <h2>{title}</h2>}
90
- <p>{renderText()}</p>
90
+ {renderText()}
91
91
  <ButtonContainer
92
92
  hasTitle={hasTitle}
93
93
  show={dismiss || action ? true : false}