lupine.components 1.1.31 → 1.1.33
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 +1 -1
- package/src/component-pool/cascader/cascader.tsx +3 -0
- package/src/component-pool/charts/area-chart-demo.tsx +110 -0
- package/src/component-pool/charts/area-chart.tsx +251 -0
- package/src/component-pool/charts/bar-chart-demo.tsx +110 -0
- package/src/component-pool/charts/bar-chart.tsx +220 -0
- package/src/component-pool/charts/chart-utils.ts +181 -0
- package/src/component-pool/charts/column-chart-demo.tsx +114 -0
- package/src/component-pool/charts/column-chart.tsx +227 -0
- package/src/component-pool/charts/donut-chart-demo.tsx +115 -0
- package/src/component-pool/charts/donut-chart.tsx +28 -0
- package/src/component-pool/charts/gauge-chart-demo.tsx +105 -0
- package/src/component-pool/charts/gauge-chart.tsx +113 -0
- package/src/component-pool/charts/index.ts +19 -0
- package/src/component-pool/charts/line-chart-demo.tsx +113 -0
- package/src/component-pool/charts/line-chart.tsx +230 -0
- package/src/component-pool/charts/pie-chart-demo.tsx +139 -0
- package/src/component-pool/charts/pie-chart.tsx +125 -0
- package/src/component-pool/charts/radar-chart-demo.tsx +91 -0
- package/src/component-pool/charts/radar-chart.tsx +196 -0
- package/src/component-pool/charts/scatter-chart-demo.tsx +91 -0
- package/src/component-pool/charts/scatter-chart.tsx +234 -0
- package/src/component-pool/picker-helper.tsx +50 -19
- package/src/component-pool/radial-progress/radial-progress-demo.tsx +0 -1
- package/src/component-pool/svg-icons.ts +3 -1
- package/src/component-pool/tooltip/tooltip.tsx +1 -3
- package/src/components/action-sheet.tsx +14 -2
- package/src/components/button-demo.tsx +101 -98
- package/src/components/button-push-animation-demo.tsx +71 -83
- package/src/components/editable-label-demo.tsx +39 -36
- package/src/components/index.ts +1 -0
- package/src/components/input-number-demo.tsx +131 -163
- package/src/components/loading-spin-demo.tsx +37 -0
- package/src/components/loading-spin.tsx +59 -0
- package/src/components/menu-item-props.tsx +3 -0
- package/src/components/mobile-components/mobile-side-menu.tsx +26 -9
- package/src/components/notice-message-demo.tsx +21 -24
- package/src/components/notice-message.tsx +66 -17
- package/src/components/paging-link-demo.tsx +74 -90
- package/src/components/popup-menu-demo.tsx +128 -24
- package/src/components/popup-menu.tsx +454 -207
- package/src/components/toggle-switch-demo.tsx +227 -224
- package/src/demo/demo-frame-helper.tsx +242 -148
- package/src/demo/demo-registry.ts +22 -0
- package/src/demo/demo-render-page.tsx +2 -1
- package/src/demo/mock/demo-icons.ts +4 -0
- package/src/frames/responsive-frame.tsx +11 -4
package/package.json
CHANGED
|
@@ -12,6 +12,8 @@ export type CascaderProps = {
|
|
|
12
12
|
defaultOpen?: boolean;
|
|
13
13
|
showCircle?: boolean; // New prop for circular button styling
|
|
14
14
|
children?: any;
|
|
15
|
+
key?: string;
|
|
16
|
+
onClick?: () => void;
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
const cascaderCss: CssProps = {
|
|
@@ -137,6 +139,7 @@ export const Cascader = (props: CascaderProps) => {
|
|
|
137
139
|
if (!el) return;
|
|
138
140
|
|
|
139
141
|
const nextState = !el.classList.contains('open');
|
|
142
|
+
if (props.onClick) props.onClick();
|
|
140
143
|
|
|
141
144
|
if (nextState && props.group) {
|
|
142
145
|
const others = document.querySelectorAll(`[data-cascader-group="${props.group}"]`);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { AreaChart } from './area-chart';
|
|
2
|
+
import { DemoStory } from '../../demo/demo-types';
|
|
3
|
+
import { ChartData } from './chart-utils';
|
|
4
|
+
|
|
5
|
+
const multiSeriesData: ChartData = {
|
|
6
|
+
labels: ['2019', '2020', '2021', '2022', '2023', '2024'],
|
|
7
|
+
series: [
|
|
8
|
+
{ name: 'Cloud Revenue', data: [15, 22, 35, 48, 65, 80] },
|
|
9
|
+
{ name: 'Hardware Sales', data: [50, 48, 45, 40, 35, 30] },
|
|
10
|
+
],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const areaChartDemo: DemoStory<any> = {
|
|
14
|
+
id: 'areaChartDemo',
|
|
15
|
+
text: 'Area Chart',
|
|
16
|
+
args: {
|
|
17
|
+
title: 'Company Revenues',
|
|
18
|
+
width: '100%',
|
|
19
|
+
height: '350px',
|
|
20
|
+
showLegend: true,
|
|
21
|
+
curved: true,
|
|
22
|
+
},
|
|
23
|
+
argTypes: {
|
|
24
|
+
title: { control: 'text' },
|
|
25
|
+
width: { control: 'text' },
|
|
26
|
+
height: { control: 'text' },
|
|
27
|
+
showLegend: { control: 'boolean' },
|
|
28
|
+
curved: { control: 'boolean' },
|
|
29
|
+
},
|
|
30
|
+
render: (args: any) => {
|
|
31
|
+
const css = {
|
|
32
|
+
display: 'flex',
|
|
33
|
+
flexDirection: 'column',
|
|
34
|
+
gap: '48px',
|
|
35
|
+
padding: '24px',
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
|
|
38
|
+
'.demo-section': {
|
|
39
|
+
display: 'flex',
|
|
40
|
+
flexDirection: 'column',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
gap: '24px',
|
|
43
|
+
width: '100%',
|
|
44
|
+
maxWidth: '800px',
|
|
45
|
+
},
|
|
46
|
+
'.section-title': {
|
|
47
|
+
fontSize: '20px',
|
|
48
|
+
fontWeight: 'bold',
|
|
49
|
+
color: 'var(--primary-color)',
|
|
50
|
+
marginBottom: '16px',
|
|
51
|
+
borderBottom: '2px solid var(--secondary-border-color)',
|
|
52
|
+
width: '100%',
|
|
53
|
+
paddingBottom: '8px',
|
|
54
|
+
},
|
|
55
|
+
'.chart-box': {
|
|
56
|
+
padding: '20px',
|
|
57
|
+
border: '1px solid var(--secondary-border-color)',
|
|
58
|
+
borderRadius: '8px',
|
|
59
|
+
backgroundColor: 'var(--primary-bg-color)',
|
|
60
|
+
width: '100%',
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div css={css}>
|
|
66
|
+
<section class='demo-section'>
|
|
67
|
+
<div class='section-title'>Interactive Control</div>
|
|
68
|
+
<div class='chart-box'>
|
|
69
|
+
<AreaChart
|
|
70
|
+
data={multiSeriesData}
|
|
71
|
+
title={args.title}
|
|
72
|
+
width={args.width}
|
|
73
|
+
height={args.height}
|
|
74
|
+
showLegend={args.showLegend}
|
|
75
|
+
curved={args.curved}
|
|
76
|
+
yAxisFormatter={(val) => '$' + val + 'M'}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
</section>
|
|
80
|
+
|
|
81
|
+
<section class='demo-section'>
|
|
82
|
+
<div class='section-title'>Straight Area Chart</div>
|
|
83
|
+
<div class='chart-box'>
|
|
84
|
+
<AreaChart
|
|
85
|
+
data={multiSeriesData}
|
|
86
|
+
title='Straight Area Comparison'
|
|
87
|
+
height='300px'
|
|
88
|
+
showLegend={true}
|
|
89
|
+
curved={false}
|
|
90
|
+
yAxisFormatter={(val) => '$' + val + 'M'}
|
|
91
|
+
/>
|
|
92
|
+
</div>
|
|
93
|
+
</section>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
code: `import { AreaChart } from 'lupine.components/component-pool/charts';
|
|
98
|
+
|
|
99
|
+
const data = {
|
|
100
|
+
labels: ['Q1', 'Q2', 'Q3'],
|
|
101
|
+
series: [{ name: 'Growth', data: [10, 25, 45] }]
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
<AreaChart
|
|
105
|
+
data={data}
|
|
106
|
+
title="Growth Area"
|
|
107
|
+
curved={true}
|
|
108
|
+
/>
|
|
109
|
+
`,
|
|
110
|
+
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { bindGlobalStyle, getGlobalStylesId, HtmlVar } from 'lupine.components';
|
|
2
|
+
import { chartCommonCss, getChartColor, BasicChartProps } from './chart-utils';
|
|
3
|
+
import { Tooltip } from '../tooltip';
|
|
4
|
+
|
|
5
|
+
export type AreaChartProps = BasicChartProps & {
|
|
6
|
+
yAxisFormatter?: (value: number) => string;
|
|
7
|
+
curved?: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const AreaChart = (props: AreaChartProps) => {
|
|
11
|
+
const globalCssId = getGlobalStylesId(chartCommonCss);
|
|
12
|
+
bindGlobalStyle(globalCssId, chartCommonCss);
|
|
13
|
+
|
|
14
|
+
const showLegend = props.showLegend !== false;
|
|
15
|
+
const series = props.data.series;
|
|
16
|
+
const labels = props.data.labels;
|
|
17
|
+
|
|
18
|
+
if (!series || series.length === 0 || labels.length === 0) {
|
|
19
|
+
return <div class='&-container'>No data</div>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Find max value for Y axis scale
|
|
23
|
+
let maxVal = 0;
|
|
24
|
+
series.forEach((s) => {
|
|
25
|
+
s.data.forEach((val) => {
|
|
26
|
+
if (val > maxVal) maxVal = val;
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const tickCount = 5;
|
|
31
|
+
const order = Math.floor(Math.log10(maxVal || 1));
|
|
32
|
+
const magnitude = Math.pow(10, order);
|
|
33
|
+
const niceStep = Math.ceil(maxVal / magnitude / tickCount) * magnitude;
|
|
34
|
+
const niceMax = niceStep * tickCount;
|
|
35
|
+
|
|
36
|
+
const yTicks = Array.from({ length: tickCount + 1 }, (_, i) => parseFloat((i * niceStep).toPrecision(12)));
|
|
37
|
+
|
|
38
|
+
const renderChart = (viewBoxWidth: number, viewBoxHeight: number) => {
|
|
39
|
+
// Layout parameters
|
|
40
|
+
const padding = { top: 20, right: 80, bottom: 40, left: 60 };
|
|
41
|
+
|
|
42
|
+
const chartWidth = viewBoxWidth - padding.left - padding.right;
|
|
43
|
+
const chartHeight = viewBoxHeight - padding.top - padding.bottom;
|
|
44
|
+
|
|
45
|
+
// Calculate points considering a half step padding on left and right for area/line
|
|
46
|
+
const pointStep = chartWidth / Math.max(1, labels.length);
|
|
47
|
+
const dataLeftPadding = pointStep / 2;
|
|
48
|
+
|
|
49
|
+
const formatY = props.yAxisFormatter || ((val) => val.toString());
|
|
50
|
+
|
|
51
|
+
// Render Y Axis
|
|
52
|
+
const renderYAxis = () => {
|
|
53
|
+
return yTicks.map((val) => {
|
|
54
|
+
const y = padding.top + chartHeight - (val / niceMax) * chartHeight;
|
|
55
|
+
return (
|
|
56
|
+
<g>
|
|
57
|
+
<line
|
|
58
|
+
x1={padding.left}
|
|
59
|
+
y1={y}
|
|
60
|
+
x2={viewBoxWidth - padding.right}
|
|
61
|
+
y2={y}
|
|
62
|
+
stroke='var(--secondary-border-color)'
|
|
63
|
+
stroke-width='1'
|
|
64
|
+
stroke-dasharray='4 4'
|
|
65
|
+
/>
|
|
66
|
+
<text x={padding.left - 15} y={y + 4} fill='var(--primary-color)' fontSize='12' text-anchor='end'>
|
|
67
|
+
{formatY(val)}
|
|
68
|
+
</text>
|
|
69
|
+
</g>
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Render X Axis
|
|
75
|
+
const renderXAxis = () => {
|
|
76
|
+
return labels.map((label, index) => {
|
|
77
|
+
const x = padding.left + dataLeftPadding + index * pointStep;
|
|
78
|
+
const y = viewBoxHeight - padding.bottom + 25;
|
|
79
|
+
return (
|
|
80
|
+
<text x={x} y={y} fill='var(--primary-color)' fontSize='12' text-anchor='middle'>
|
|
81
|
+
{label}
|
|
82
|
+
</text>
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Render Areas, Lines & Points
|
|
88
|
+
const renderAreasLinesAndPoints = () => {
|
|
89
|
+
const areas: any[] = [];
|
|
90
|
+
const lines: any[] = [];
|
|
91
|
+
const points: any[] = [];
|
|
92
|
+
|
|
93
|
+
// Render area in reverse order so first series is drawn last (on top) if they overlap
|
|
94
|
+
// Note: Better visualization is sometimes stacking, but basic is overlapping
|
|
95
|
+
series
|
|
96
|
+
.slice()
|
|
97
|
+
.reverse()
|
|
98
|
+
.forEach((s, revIndex) => {
|
|
99
|
+
const sIndex = series.length - 1 - revIndex;
|
|
100
|
+
const color = s.color || getChartColor(sIndex);
|
|
101
|
+
|
|
102
|
+
const coordinates = s.data.map((val, lIndex) => {
|
|
103
|
+
const x = padding.left + dataLeftPadding + lIndex * pointStep;
|
|
104
|
+
const y = padding.top + chartHeight - (val / niceMax) * chartHeight;
|
|
105
|
+
return { x, y, val, label: labels[lIndex] };
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Draw Path Base
|
|
109
|
+
let linePath = '';
|
|
110
|
+
if (props.curved && coordinates.length > 2) {
|
|
111
|
+
linePath = `M ${coordinates[0].x} ${coordinates[0].y} `;
|
|
112
|
+
for (let i = 0; i < coordinates.length - 1; i++) {
|
|
113
|
+
const current = coordinates[i];
|
|
114
|
+
const next = coordinates[i + 1];
|
|
115
|
+
const mx = (current.x + next.x) / 2;
|
|
116
|
+
linePath += `C ${mx} ${current.y}, ${mx} ${next.y}, ${next.x} ${next.y} `;
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
linePath = 'M ' + coordinates.map((c) => `${c.x} ${c.y}`).join(' L ');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const endX = coordinates[coordinates.length - 1].x;
|
|
123
|
+
const startX = coordinates[0].x;
|
|
124
|
+
const baseY = padding.top + chartHeight;
|
|
125
|
+
|
|
126
|
+
const areaPath = `${linePath} L ${endX} ${baseY} L ${startX} ${baseY} Z`;
|
|
127
|
+
|
|
128
|
+
areas.push(
|
|
129
|
+
<path
|
|
130
|
+
d={areaPath}
|
|
131
|
+
fill={color}
|
|
132
|
+
opacity='0.3' // Transparency for area
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
lines.push(<path d={linePath} fill='none' stroke={color} stroke-width='3' />);
|
|
137
|
+
|
|
138
|
+
// Draw interactive points overlay
|
|
139
|
+
coordinates.forEach((c) => {
|
|
140
|
+
const handleMouseEnter = (e: any) => {
|
|
141
|
+
Tooltip.show(
|
|
142
|
+
e,
|
|
143
|
+
<div>
|
|
144
|
+
<div style={{ fontWeight: 'bold' }}>{c.label}</div>
|
|
145
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
|
|
146
|
+
<div style={{ width: '10px', height: '10px', backgroundColor: color, borderRadius: '2px' }} />
|
|
147
|
+
<span>
|
|
148
|
+
{s.name}: {formatY(c.val)}
|
|
149
|
+
</span>
|
|
150
|
+
</div>
|
|
151
|
+
</div>,
|
|
152
|
+
{ position: 'auto' }
|
|
153
|
+
);
|
|
154
|
+
e.target.setAttribute('r', '6');
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const handleMouseLeave = (e: any) => {
|
|
158
|
+
Tooltip.hide();
|
|
159
|
+
e.target.setAttribute('r', '4');
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
points.push(
|
|
163
|
+
<circle
|
|
164
|
+
class='chart-element'
|
|
165
|
+
cx={c.x}
|
|
166
|
+
cy={c.y}
|
|
167
|
+
r='4'
|
|
168
|
+
fill='var(--primary-bg-color)'
|
|
169
|
+
stroke={color}
|
|
170
|
+
stroke-width='2'
|
|
171
|
+
onMouseEnter={handleMouseEnter}
|
|
172
|
+
onMouseLeave={handleMouseLeave}
|
|
173
|
+
style={{ transition: 'r 0.2s ease' }}
|
|
174
|
+
/>
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return { areas, lines, points };
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const { areas, lines, points } = renderAreasLinesAndPoints();
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<svg
|
|
186
|
+
class='chart-svg'
|
|
187
|
+
style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', overflow: 'visible' }}
|
|
188
|
+
viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}
|
|
189
|
+
preserveAspectRatio='none'
|
|
190
|
+
>
|
|
191
|
+
{/* Base Axis line */}
|
|
192
|
+
<line
|
|
193
|
+
x1={padding.left}
|
|
194
|
+
y1={padding.top + chartHeight}
|
|
195
|
+
x2={viewBoxWidth - padding.right}
|
|
196
|
+
y2={padding.top + chartHeight}
|
|
197
|
+
stroke='var(--secondary-color)'
|
|
198
|
+
stroke-width='2'
|
|
199
|
+
/>
|
|
200
|
+
|
|
201
|
+
<g class='y-axis'>{renderYAxis()}</g>
|
|
202
|
+
<g class='x-axis'>{renderXAxis()}</g>
|
|
203
|
+
<g class='areas'>{areas}</g>
|
|
204
|
+
<g class='lines'>{lines}</g>
|
|
205
|
+
<g class='points'>{points}</g>
|
|
206
|
+
</svg>
|
|
207
|
+
);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const chartVar = new HtmlVar(renderChart(1000, 300));
|
|
211
|
+
|
|
212
|
+
const ref = {
|
|
213
|
+
globalCssId,
|
|
214
|
+
onLoad: async (el: Element) => {
|
|
215
|
+
const ro = new ResizeObserver((entries) => {
|
|
216
|
+
const { width, height } = entries[0].contentRect;
|
|
217
|
+
if (width > 50 && height > 50) {
|
|
218
|
+
chartVar.value = renderChart(width, height);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
ro.observe(el);
|
|
222
|
+
(el as any)._ro = ro;
|
|
223
|
+
},
|
|
224
|
+
onUnload: async (el: Element) => {
|
|
225
|
+
if ((el as any)._ro) {
|
|
226
|
+
(el as any)._ro.disconnect();
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const styleStr = `width: ${props.width || '100%'}; height: ${props.height || '100%'};`;
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<div ref={ref} class='&-container' style={styleStr}>
|
|
235
|
+
{props.title && <div class='chart-title'>{props.title}</div>}
|
|
236
|
+
|
|
237
|
+
<div style={{ flex: 1, position: 'relative', minHeight: 0 }}>{chartVar.node}</div>
|
|
238
|
+
|
|
239
|
+
{showLegend && (
|
|
240
|
+
<div class='chart-legend'>
|
|
241
|
+
{series.map((s, i) => (
|
|
242
|
+
<div class='legend-item'>
|
|
243
|
+
<div class='legend-color' style={{ backgroundColor: s.color || getChartColor(i) }} />
|
|
244
|
+
<div>{s.name}</div>
|
|
245
|
+
</div>
|
|
246
|
+
))}
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</div>
|
|
250
|
+
);
|
|
251
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { BarChart } from './bar-chart';
|
|
2
|
+
import { DemoStory } from '../../demo/demo-types';
|
|
3
|
+
import { ChartData } from './chart-utils';
|
|
4
|
+
|
|
5
|
+
const singleSeriesData: ChartData = {
|
|
6
|
+
labels: ['United States', 'China', 'Japan', 'Germany', 'United Kingdom'],
|
|
7
|
+
series: [
|
|
8
|
+
{
|
|
9
|
+
name: 'GDP (Trillions)',
|
|
10
|
+
data: [25.4, 17.9, 4.2, 4.0, 3.0],
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const multiSeriesData: ChartData = {
|
|
16
|
+
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
17
|
+
series: [
|
|
18
|
+
{ name: 'Product A', data: [40, 30, 50, 70] },
|
|
19
|
+
{ name: 'Product B', data: [20, 40, 30, 60] },
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const barChartDemo: DemoStory<any> = {
|
|
24
|
+
id: 'barChartDemo',
|
|
25
|
+
text: 'Bar Chart',
|
|
26
|
+
args: {
|
|
27
|
+
title: 'Top Economies',
|
|
28
|
+
width: '100%',
|
|
29
|
+
height: '350px',
|
|
30
|
+
showLegend: true,
|
|
31
|
+
},
|
|
32
|
+
argTypes: {
|
|
33
|
+
title: { control: 'text' },
|
|
34
|
+
width: { control: 'text' },
|
|
35
|
+
height: { control: 'text' },
|
|
36
|
+
showLegend: { control: 'boolean' },
|
|
37
|
+
},
|
|
38
|
+
render: (args: any) => {
|
|
39
|
+
const css = {
|
|
40
|
+
display: 'flex',
|
|
41
|
+
flexDirection: 'column',
|
|
42
|
+
gap: '48px',
|
|
43
|
+
padding: '24px',
|
|
44
|
+
alignItems: 'center',
|
|
45
|
+
|
|
46
|
+
'.demo-section': {
|
|
47
|
+
display: 'flex',
|
|
48
|
+
flexDirection: 'column',
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
gap: '24px',
|
|
51
|
+
width: '100%',
|
|
52
|
+
maxWidth: '800px',
|
|
53
|
+
},
|
|
54
|
+
'.section-title': {
|
|
55
|
+
fontSize: '20px',
|
|
56
|
+
fontWeight: 'bold',
|
|
57
|
+
color: 'var(--primary-color)',
|
|
58
|
+
marginBottom: '16px',
|
|
59
|
+
borderBottom: '2px solid var(--secondary-border-color)',
|
|
60
|
+
width: '100%',
|
|
61
|
+
paddingBottom: '8px',
|
|
62
|
+
},
|
|
63
|
+
'.chart-box': {
|
|
64
|
+
padding: '20px',
|
|
65
|
+
border: '1px solid var(--secondary-border-color)',
|
|
66
|
+
borderRadius: '8px',
|
|
67
|
+
backgroundColor: 'var(--primary-bg-color)',
|
|
68
|
+
width: '100%',
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div css={css}>
|
|
74
|
+
<section class='demo-section'>
|
|
75
|
+
<div class='section-title'>Interactive Control</div>
|
|
76
|
+
<div class='chart-box'>
|
|
77
|
+
<BarChart
|
|
78
|
+
data={singleSeriesData}
|
|
79
|
+
title={args.title}
|
|
80
|
+
width={args.width}
|
|
81
|
+
height={args.height}
|
|
82
|
+
showLegend={args.showLegend}
|
|
83
|
+
xAxisFormatter={(val) => '$' + val + 'T'}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
</section>
|
|
87
|
+
|
|
88
|
+
<section class='demo-section'>
|
|
89
|
+
<div class='section-title'>Multi-Series (Grouped Horizontal)</div>
|
|
90
|
+
<div class='chart-box'>
|
|
91
|
+
<BarChart data={multiSeriesData} title='Quarterly Comparison' height='300px' showLegend={true} />
|
|
92
|
+
</div>
|
|
93
|
+
</section>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
code: `import { BarChart } from 'lupine.components/component-pool/charts';
|
|
98
|
+
|
|
99
|
+
const data = {
|
|
100
|
+
labels: ['US', 'CN', 'JP'],
|
|
101
|
+
series: [{ name: 'GDP', data: [25, 18, 4] }]
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
<BarChart
|
|
105
|
+
data={data}
|
|
106
|
+
title="Top Economies"
|
|
107
|
+
xAxisFormatter={val => '$' + val + 'T'}
|
|
108
|
+
/>
|
|
109
|
+
`,
|
|
110
|
+
};
|