@spteck/fluentui-react-charts 0.1.8 → 1.0.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.
Files changed (39) hide show
  1. package/dist/components/RenderLabel/RenderLabel.d.ts +8 -0
  2. package/dist/components/RenderLabel/index.d.ts +2 -0
  3. package/dist/components/RenderLabel/useRenderLabelStylesStyles.d.ts +1 -0
  4. package/dist/components/dashboard/DashBoard.d.ts +4 -0
  5. package/dist/components/dashboard/ExampleDashboardUsage.d.ts +6 -0
  6. package/dist/components/dashboard/ICardChartContainer.d.ts +16 -0
  7. package/dist/components/dashboard/IDashboardProps.d.ts +9 -0
  8. package/dist/components/dashboard/NoDashboards.d.ts +5 -0
  9. package/dist/components/dashboard/index.d.ts +3 -0
  10. package/dist/components/dashboard/selectZoom/SelectZoom.d.ts +15 -0
  11. package/dist/components/dashboard/useDashboardStyles.d.ts +7 -0
  12. package/dist/components/index.d.ts +1 -1
  13. package/dist/components/svgImages/BusinessReportIcon.d.ts +9 -0
  14. package/dist/fluentui-react-charts.cjs.development.js +2 -0
  15. package/dist/fluentui-react-charts.cjs.development.js.map +1 -1
  16. package/dist/fluentui-react-charts.cjs.production.min.js +1 -1
  17. package/dist/fluentui-react-charts.cjs.production.min.js.map +1 -1
  18. package/dist/fluentui-react-charts.esm.js +2 -0
  19. package/dist/fluentui-react-charts.esm.js.map +1 -1
  20. package/dist/models/ChartDatum.d.ts +4 -0
  21. package/dist/models/index.d.ts +1 -0
  22. package/package.json +2 -3
  23. package/src/components/RenderLabel/RenderLabel.tsx +39 -0
  24. package/src/components/RenderLabel/index.ts +2 -0
  25. package/src/components/RenderLabel/useRenderLabelStylesStyles.ts +25 -0
  26. package/src/components/dashboard/DashBoard.tsx +220 -0
  27. package/src/components/dashboard/ExampleDashboardUsage.tsx +114 -0
  28. package/src/components/dashboard/ICardChartContainer.tsx +13 -0
  29. package/src/components/dashboard/IDashboardProps.tsx +13 -0
  30. package/src/components/dashboard/NoDashboards.tsx +26 -0
  31. package/src/components/dashboard/index.ts +4 -0
  32. package/src/components/dashboard/selectZoom/SelectZoom.tsx +189 -0
  33. package/src/components/dashboard/useDashboardStyles.ts +76 -0
  34. package/src/components/index.ts +3 -1
  35. package/src/components/svgImages/BusinessReportIcon.tsx +218 -0
  36. package/src/models/ChartDatum.ts +4 -0
  37. package/src/models/index.ts +1 -0
  38. package/dist/components/DashBoard.d.ts +0 -3
  39. package/src/components/DashBoard.tsx +0 -409
@@ -1,409 +0,0 @@
1
- import {
2
- Card,
3
- CardHeader,
4
- FluentProvider,
5
- IdPrefixProvider,
6
- Text,
7
- } from '@fluentui/react-components';
8
- import React, { useEffect, useRef, useState } from 'react';
9
-
10
- import { ButtonMenu } from './buttonMenu/ButtonMenu';
11
- import { ResizeObserver } from '@juggle/resize-observer';
12
- import { css } from '@emotion/css';
13
- import { tokens } from '@fluentui/react-components';
14
- import { useGraphUtils } from '../hooks/useGraphUtils';
15
- import { useThemeContext } from './themeProvider/ThemeProvider';
16
-
17
- // Fixed card width grid and centering
18
- const dashboardContainer = css`
19
- display: grid;
20
- padding: 20px;
21
- gap: 16px;
22
- background-color: ${tokens.colorNeutralBackground2};
23
- grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
24
- grid-auto-rows: minmax(350px, 450px);
25
- justify-content: center;
26
- grid-auto-flow: dense;
27
- overflow: auto;
28
- `;
29
- const cardBody = css`
30
- display: flex;
31
- flex-direction: column;
32
- height: 100%;
33
- `;
34
- const chartContainer = css`
35
- flex: 1;
36
- min-height: 0; /* enables flex child to shrink properly */
37
- overflow: hidden;
38
- `;
39
-
40
- const DashboardWithGridDnD: React.FC = () => {
41
- const { theme } = useThemeContext();
42
- const { getChartComponent } = useGraphUtils(theme);
43
-
44
- // sample charts array
45
- // Helper to generate random integer between min and max (inclusive)
46
- const randomInt = (min: number, max: number) =>
47
- Math.floor(Math.random() * (max - min + 1)) + min;
48
-
49
- // Helper to generate random chart data for a given type
50
- const generateRandomData = (type: string) => {
51
- switch (type) {
52
- case 'bar':
53
- case 'line':
54
- case 'area':
55
- case 'bar-horizontal':
56
- case 'stacked-line':
57
- return [
58
- {
59
- label: '2023',
60
- data: [
61
- { name: 'Jan', value: randomInt(10, 100) },
62
- { name: 'Feb', value: randomInt(10, 100) },
63
- { name: 'Mar', value: randomInt(10, 100) },
64
- ],
65
- },
66
- {
67
- label: '2024',
68
- data: [
69
- { name: 'Jan', value: randomInt(10, 100) },
70
- { name: 'Feb', value: randomInt(10, 100) },
71
- { name: 'Mar', value: randomInt(10, 100) },
72
- ],
73
- },
74
- {
75
- label: '2025',
76
- data: [
77
- { name: 'Jan', value: randomInt(10, 100) },
78
- { name: 'Feb', value: randomInt(10, 100) },
79
- { name: 'Mar', value: randomInt(10, 100) },
80
- ],
81
- },
82
- ];
83
- case 'bubble':
84
- return [
85
- {
86
- label: '2023',
87
- data: [
88
- { name: 'Jan', value: randomInt(10, 100), radius: randomInt(5, 20) },
89
- { name: 'Feb', value: randomInt(10, 100), radius: randomInt(5, 20) },
90
- { name: 'Mar', value: randomInt(10, 100), radius: randomInt(5, 20) },
91
- ],
92
- },
93
- {
94
- label: '2024',
95
- data: [
96
- { name: 'Jan', value: randomInt(10, 100), radius: randomInt(5, 20) },
97
- { name: 'Feb', value: randomInt(10, 100), radius: randomInt(5, 20) },
98
- { name: 'Mar', value: randomInt(10, 100), radius: randomInt(5, 20) },
99
- ],
100
- },
101
- {
102
- label: '2025',
103
- data: [
104
- { name: 'Jan', value: randomInt(10, 100), radius: randomInt(5, 20) },
105
- { name: 'Feb', value: randomInt(10, 100), radius: randomInt(5, 20) },
106
- { name: 'Mar', value: randomInt(10, 100), radius: randomInt(5, 20) },
107
- ],
108
- },
109
- ];
110
- case 'steam':
111
- return Array.from({ length: 5 }, (_, i) => ({
112
- label: `${2021 + i}`,
113
- data: [
114
- { name: 'Jan', value: randomInt(10, 200) },
115
- { name: 'Feb', value: randomInt(10, 200) },
116
- { name: 'Mar', value: randomInt(10, 200) },
117
- ],
118
- }));
119
- case 'multiple-axes':
120
- return [
121
- ...Array.from({ length: 3 }, (_, i) => ({
122
- label: `${2021 + i}`,
123
- type: 'bar',
124
- data: [
125
- { name: 'Jan', value: randomInt(10, 200) },
126
- { name: 'Feb', value: randomInt(10, 200) },
127
- { name: 'Mar', value: randomInt(10, 200) },
128
- ],
129
- })),
130
- ...Array.from({ length: 2 }, (_, i) => ({
131
- label: `${2024 + i}`,
132
- type: 'line',
133
- data: [
134
- { name: 'Jan', value: randomInt(10, 200) },
135
- { name: 'Feb', value: randomInt(10, 200) },
136
- { name: 'Mar', value: randomInt(10, 200) },
137
- ],
138
- })),
139
- ];
140
- case 'floating-bar':
141
- return [
142
- {
143
- label: 'City Porto',
144
- data: [
145
- { name: 'Jan', min: randomInt(-10, 10), max: randomInt(10, 30) },
146
- { name: 'Feb', min: randomInt(-10, 10), max: randomInt(10, 30) },
147
- { name: 'Mar', min: randomInt(-10, 10), max: randomInt(10, 30) },
148
- { name: 'Apr', min: randomInt(-10, 10), max: randomInt(10, 30) },
149
- { name: 'May', min: randomInt(-10, 10), max: randomInt(10, 30) },
150
- ],
151
- },
152
- {
153
- label: 'City Lisbon',
154
- data: [
155
- { name: 'Jan', min: randomInt(-10, 10), max: randomInt(10, 30) },
156
- { name: 'Feb', min: randomInt(-10, 10), max: randomInt(10, 30) },
157
- { name: 'Mar', min: randomInt(-10, 10), max: randomInt(10, 30) },
158
- { name: 'Apr', min: randomInt(-10, 10), max: randomInt(10, 30) },
159
- { name: 'May', min: randomInt(-10, 10), max: randomInt(10, 30) },
160
- ],
161
- },
162
- {
163
- label: 'City Faro',
164
- data: [
165
- { name: 'Jan', min: randomInt(-20, 20), max: randomInt(20, 150) },
166
- { name: 'Feb', min: randomInt(-20, 20), max: randomInt(20, 150) },
167
- { name: 'Mar', min: randomInt(-20, 20), max: randomInt(20, 150) },
168
- { name: 'Apr', min: randomInt(-20, 20), max: randomInt(20, 150) },
169
- { name: 'May', min: randomInt(-20, 20), max: randomInt(20, 150) },
170
- ],
171
- },
172
- ];
173
- case 'doughnut':
174
- case 'pie':
175
- return [
176
- {
177
- label: [2023],
178
- data: [
179
- { name: 'Jan', value: randomInt(10, 100) },
180
- { name: 'Feb', value: randomInt(10, 100) },
181
- { name: 'Mar', value: randomInt(10, 100) },
182
- { name: 'Apr', value: randomInt(10, 100) },
183
- ],
184
- },
185
- ];
186
- case 'scatter':
187
- return [
188
- {
189
- label: 'Group A',
190
- data: [
191
- { x: randomInt(1, 10), y: randomInt(1, 20) },
192
- { x: randomInt(1, 10), y: randomInt(1, 20) },
193
- { x: randomInt(1, 10), y: randomInt(1, 20) },
194
- ],
195
- },
196
- {
197
- label: 'Group B',
198
- data: [
199
- { x: randomInt(1, 10), y: randomInt(1, 20) },
200
- { x: randomInt(1, 10), y: randomInt(1, 20) },
201
- { x: randomInt(1, 10), y: randomInt(1, 20) },
202
- ],
203
- },
204
- {
205
- label: 'Group C',
206
- data: [
207
- { x: randomInt(1, 10), y: randomInt(1, 20) },
208
- { x: randomInt(1, 10), y: randomInt(1, 20) },
209
- { x: randomInt(1, 10), y: randomInt(1, 20) },
210
- ],
211
- },
212
- ];
213
- case 'polar':
214
- case 'radar':
215
- return [
216
- {
217
- label: [2025],
218
-
219
- data: [
220
- { name: 'Jan', value: randomInt(10, 50) },
221
- { name: 'Feb', value: randomInt(10, 50) },
222
- { name: 'Mar', value: randomInt(10, 50) },
223
- { name: 'Apr', value: randomInt(10, 50) },
224
- { name: 'May', value: randomInt(10, 50) },
225
- { name: 'Jun', value: randomInt(10, 50) },
226
- { name: 'Jul', value: randomInt(10, 50) },
227
- { name: 'Aug', value: randomInt(10, 50) },
228
- { name: 'Sep', value: randomInt(10, 50) },
229
- { name: 'Oct', value: randomInt(10, 50) },
230
- { name: 'Nov', value: randomInt(10, 50) },
231
- { name: 'Dec', value: randomInt(10, 50) },
232
- ],
233
- },
234
- ...(type === 'radar'
235
- ? [
236
- {
237
- label: [2024],
238
- data: [
239
- { name: 'Jan', value: randomInt(10, 50) },
240
- { name: 'Feb', value: randomInt(10, 50) },
241
- { name: 'Mar', value: randomInt(10, 50) },
242
- { name: 'Apr', value: randomInt(10, 50) },
243
- { name: 'May', value: randomInt(10, 50) },
244
- { name: 'Jun', value: randomInt(10, 50) },
245
- { name: 'Jul', value: randomInt(10, 50) },
246
- { name: 'Aug', value: randomInt(10, 50) },
247
- { name: 'Sep', value: randomInt(10, 50) },
248
- { name: 'Oct', value: randomInt(10, 50) },
249
- { name: 'Nov', value: randomInt(10, 50) },
250
- { name: 'Dec', value: randomInt(10, 50) },
251
- ],
252
- },
253
- ]
254
- : []),
255
- ];
256
- default:
257
- return [];
258
- }
259
- };
260
-
261
- // Chart definitions with random data
262
- const [charts, setCharts] = useState<any[]>([
263
- { id: '7', title: 'Multi-Series Multiple Axes Chart', type: 'bar', data: generateRandomData('bar') },
264
- { id: '1', title: 'Multi-Series Line Chart', type: 'line', data: generateRandomData('line') },
265
- { id: '2', title: 'Multi-Series Area Chart', type: 'area', data: generateRandomData('area') },
266
- { id: '9', title: 'Multi-Series Bar-Horizontal Chart', type: 'bar-horizontal', data: generateRandomData('bar-horizontal') },
267
- { id: '10', title: 'Multi-Series Bubble Chart', type: 'bubble', data: generateRandomData('bubble') },
268
- { id: '11', title: 'Multi-Series Steam Chart', type: 'steam', data: generateRandomData('steam') },
269
- { id: '12', title: 'Multi-Series Multiple Axes Chart', type: 'multiple-axes', data: generateRandomData('multiple-axes') },
270
- { id: '16', title: 'Floating Bar Chart', type: 'floating-bar', data: generateRandomData('floating-bar') },
271
- { id: '19', title: 'Stacked Line Chart', type: 'stacked-line', data: generateRandomData('stacked-line') },
272
- { id: '20', title: 'Doughnut Chart', type: 'doughnut', data: generateRandomData('doughnut') },
273
- { id: '23', title: 'Pie Chart', type: 'pie', data: generateRandomData('pie') },
274
- { id: '24', title: 'Scatter Chart', type: 'scatter', data: generateRandomData('scatter') },
275
- { id: '38', title: 'Polar Chart', type: 'polar', data: generateRandomData('polar') },
276
- { id: '39', title: 'Radar Chart', type: 'radar', data: generateRandomData('radar') },
277
- ]);
278
- const [sizes, setSizes] = useState<Record<string, number>>({});
279
- const dragItem = useRef<number | null>(null);
280
- const dragOverItem = useRef<number | null>(null);
281
-
282
- // measure container width to hide zoom on mobile
283
- const containerRef = useRef<HTMLDivElement>(null);
284
- const [containerWidth, setContainerWidth] = useState(0);
285
-
286
- useEffect(() => {
287
- if (!containerRef.current) return;
288
- const obs = new ResizeObserver(entries => {
289
- setContainerWidth(entries[0].contentRect.width);
290
- });
291
- obs.observe(containerRef.current);
292
- return () => obs.disconnect();
293
- }, []);
294
-
295
- useEffect(() => {
296
- if (containerWidth <= 600) {
297
- setSizes(() => {
298
- const reset: Record<string, number> = {};
299
- charts.forEach(c => {
300
- reset[c.id] = 1;
301
- });
302
- return reset;
303
- });
304
- }
305
- }, [containerWidth, charts]);
306
-
307
- const showZoom = React.useMemo(() => containerWidth > 600, [containerWidth]);
308
-
309
- const minCardWidth = 350;
310
- const gridGap = 16; // same value as CSS gap
311
- const containerPadding = 20; // same as dashboardContainer padding
312
- // calculate how many full columns fit
313
- const innerWidth = containerWidth - containerPadding * 2;
314
- const columns = Math.floor((innerWidth + gridGap) / (minCardWidth + gridGap));
315
- const maxZoom = Math.max(columns, 1);
316
-
317
- // if no charts, show placeholder
318
- if (charts.length === 0) {
319
- return (
320
- <FluentProvider theme={theme}>
321
- <div
322
- className={css`
323
- width: 100%;
324
- height: 100%;
325
- display: flex;
326
- align-items: center;
327
- justify-content: center;
328
- background-color: ${tokens.colorNeutralBackground2};
329
- `}
330
- >
331
- <Text size={500} weight="semibold">
332
- No charts to display.
333
- </Text>
334
- </div>
335
- </FluentProvider>
336
- );
337
- }
338
-
339
- const handleSort = () => {
340
- if (
341
- dragItem.current !== null &&
342
- dragOverItem.current !== null &&
343
- dragItem.current !== dragOverItem.current
344
- ) {
345
- const copy = [...charts];
346
- const [moved] = copy.splice(dragItem.current, 1);
347
- copy.splice(dragOverItem.current, 0, moved);
348
- setCharts(copy);
349
- }
350
- dragItem.current = null;
351
- dragOverItem.current = null;
352
- };
353
- const handleResize = (id: string, span: number) => {
354
- setSizes(prev => ({ ...prev, [id]: Math.min(Math.max(span, 1), maxZoom) }));
355
- };
356
-
357
- return (
358
- <IdPrefixProvider value="dashboard-grid-dnd">
359
- <FluentProvider theme={theme} style={{height: '100%', backgroundColor: tokens.colorNeutralBackground2 }} >
360
- <div ref={containerRef} className={dashboardContainer}>
361
- {charts.map((chart, idx) => {
362
- const zoomOptions = Array.from({ length: maxZoom }, (_, i) => ({
363
- key: String(i + 1),
364
- text: `Zoom: ${i + 1}x${i + 1}`,
365
- selected: sizes[chart.id] === i + 1,
366
- }));
367
- return (
368
- <div
369
- key={chart.id}
370
- draggable
371
- onDragStart={() => (dragItem.current = idx)}
372
- onDragEnter={() => (dragOverItem.current = idx)}
373
- onDragOver={e => e.preventDefault()}
374
- onDragEnd={handleSort}
375
- style={{
376
- gridColumnEnd: sizes[chart.id]
377
- ? `span ${sizes[chart.id]}`
378
- : undefined,
379
- }}
380
- >
381
- <Card className={cardBody}>
382
- <CardHeader
383
- header={chart.title}
384
- action={
385
- <>
386
- {showZoom && (
387
- <ButtonMenu
388
-
389
- options={zoomOptions}
390
- onSelected={opt =>
391
- handleResize(chart.id, Number(opt.key))
392
- }
393
- />
394
- )}
395
- </>
396
- }
397
- />
398
- <div className={chartContainer}>{getChartComponent(chart, theme)}</div>
399
- </Card>
400
- </div>
401
- );
402
- })}
403
- </div>
404
- </FluentProvider>
405
- </IdPrefixProvider>
406
- );
407
- };
408
-
409
- export default DashboardWithGridDnD;