@spteck/fluentui-react-charts 1.0.5 → 1.0.6

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 (36) hide show
  1. package/dist/fluentui-react-charts.cjs.development.js +2478 -2198
  2. package/dist/fluentui-react-charts.cjs.development.js.map +1 -1
  3. package/dist/fluentui-react-charts.cjs.production.min.js +1 -1
  4. package/dist/fluentui-react-charts.cjs.production.min.js.map +1 -1
  5. package/dist/fluentui-react-charts.esm.js +2479 -2200
  6. package/dist/fluentui-react-charts.esm.js.map +1 -1
  7. package/dist/hooks/index.d.ts +1 -1
  8. package/dist/hooks/useChartFactory.d.ts +6 -0
  9. package/dist/hooks/{useGraphUtils.d.ts → useChartUtils.d.ts} +2 -5
  10. package/dist/hooks/useIndexedDBCache.d.ts +33 -0
  11. package/dist/index.d.ts +1 -0
  12. package/package.json +2 -1
  13. package/src/charts/BarChart/BarChart.tsx +2 -2
  14. package/src/charts/ComboChart/ComboChart.tsx +2 -2
  15. package/src/charts/Doughnut/DoughnutChart.tsx +2 -2
  16. package/src/charts/PieChart/PieChart.tsx +3 -3
  17. package/src/charts/areaChart/AreaChart.tsx +2 -2
  18. package/src/charts/barHorizontalChart/BarHotizontalChart.tsx +2 -2
  19. package/src/charts/bubbleChart/BubbleChart.tsx +2 -2
  20. package/src/charts/floatBarChart/FloatBarChart.tsx +2 -2
  21. package/src/charts/lineChart/LineChart.tsx +2 -2
  22. package/src/charts/polarChart/PolarChart.tsx +2 -2
  23. package/src/charts/radarChart/RadarChart.tsx +2 -2
  24. package/src/charts/scatterChart/ScatterChart.tsx +2 -2
  25. package/src/charts/stackedLineChart/StackedLineChart.tsx +2 -2
  26. package/src/charts/steamChart/SteamChart.tsx +2 -2
  27. package/src/components/dashboard/DashBoard.tsx +117 -21
  28. package/src/components/dashboard/ExampleDashboardUsage.tsx +1 -1
  29. package/src/components/dashboard/IDashboardProps.tsx +0 -2
  30. package/src/hooks/index.ts +1 -1
  31. package/src/hooks/useChartFactory.tsx +136 -0
  32. package/src/hooks/{useGraphUtils.tsx → useChartUtils.tsx} +3 -130
  33. package/src/hooks/useIndexedDBCache.ts +122 -0
  34. package/src/hooks/useResponsiveLegend.ts +2 -2
  35. package/src/index.tsx +1 -0
  36. package/src/models/ICardChartContainer.tsx +0 -2
@@ -0,0 +1,136 @@
1
+ import { Theme, webLightTheme } from "@fluentui/react-components";
2
+
3
+ import AreaChart from '../charts/areaChart/AreaChart';
4
+ import BarChart from '../charts/BarChart/BarChart';
5
+ import BarHorizontalChart from '../charts/barHorizontalChart/BarHotizontalChart';
6
+ import BubbleChart from '../charts/bubbleChart/BubbleChart';
7
+ import ComboChart from '../charts/ComboChart/ComboChart';
8
+ import DoughnutChart from '../charts/Doughnut/DoughnutChart';
9
+ import FloatingBarChart from '../charts/floatBarChart/FloatBarChart';
10
+ import { IChart } from "../models";
11
+ import LineChart from '../charts/lineChart/LineChart';
12
+ import PieChart from '../charts/PieChart/PieChart';
13
+ import PolarChart from '../charts/polarChart/PolarChart';
14
+ import RadarChart from '../charts/radarChart/RadarChart';
15
+ import React from 'react';
16
+ import ScatterChart from '../charts/scatterChart/ScatterChart';
17
+ import StackedLineChart from '../charts/stackedLineChart/StackedLineChart';
18
+ import SteamChart from '../charts/steamChart/SteamChart';
19
+
20
+ const chartProps = (chart: IChart) => ({
21
+ data: chart.data,
22
+ title: chart.title,
23
+ getPrimary: (d: any) => d.name,
24
+ getSecondary: (d: any) => d.value,
25
+ });
26
+
27
+ const getChartComponent = (chart: IChart, theme: Theme) => {
28
+ const { type } = chart;
29
+ const fuiTheme = theme ?? webLightTheme;
30
+ switch (type) {
31
+ case 'bar':
32
+ return <BarChart {...chartProps(chart)} stacked={false} theme={fuiTheme} />;
33
+ case 'line':
34
+ return <LineChart {...chartProps(chart)} theme={fuiTheme} />;
35
+ case 'area':
36
+ return <AreaChart {...chartProps(chart)} stacked={false} theme={fuiTheme} />;
37
+
38
+ case 'bar-horizontal':
39
+ return <BarHorizontalChart {...chartProps(chart)} stacked={true} theme={fuiTheme} />;
40
+ case 'bubble':
41
+ return (
42
+ <BubbleChart {...chartProps(chart)} getRadius={d => d.radius ?? 1} theme={fuiTheme} />
43
+ );
44
+ case 'multiple-axes':
45
+ return (
46
+ <ComboChart
47
+ {...chartProps(chart)}
48
+ theme={fuiTheme}
49
+
50
+ data={chart.data.map((series: any) => ({
51
+ label: series.label,
52
+ type: series.type ?? 'bar',
53
+ data: series.data,
54
+ yAxisID: series.secondaryAxisId,
55
+
56
+ }))}
57
+ />
58
+ );
59
+ case 'steam':
60
+ return <SteamChart {...chartProps(chart)} theme={fuiTheme} />;
61
+ case 'floating-bar':
62
+ return (
63
+ <FloatingBarChart
64
+ getRange={d => [d.min ?? 0, d.max ?? 0]}
65
+ {...chartProps(chart)}
66
+ theme={fuiTheme}
67
+ />
68
+ );
69
+ case 'stacked-line':
70
+ return <StackedLineChart {...chartProps(chart)} theme={fuiTheme} />;
71
+ case 'doughnut':
72
+ return (
73
+ <DoughnutChart
74
+ getLabel={datum => datum.name}
75
+ getValue={datum => datum.value ?? 0}
76
+ {...chartProps(chart)}
77
+ theme={fuiTheme}
78
+ />
79
+ );
80
+ case 'pie':
81
+ return (
82
+ <PieChart
83
+ getLabel={datum => datum.name}
84
+ getValue={datum => datum.value ?? 0}
85
+ showDataLabels={true}
86
+ {...chartProps(chart)}
87
+ theme={fuiTheme}
88
+ />
89
+ );
90
+ case 'scatter':
91
+ return (
92
+ <ScatterChart
93
+ getX={d => {
94
+ if (typeof d.x === 'number') return d.x;
95
+ if (typeof d.x === 'string') return Number(d.x) || 0;
96
+ if (d.x instanceof Date) return d.x.getTime();
97
+ return 0;
98
+ }}
99
+ getY={d => (typeof d.y === 'number' ? d.y : 0)}
100
+ {...chartProps(chart)}
101
+ theme={fuiTheme}
102
+ showDataLabels={false}
103
+ />
104
+ );
105
+ case 'polar':
106
+ return (
107
+ <PolarChart
108
+ data={chart.data}
109
+ getLabel={d => d.name}
110
+ getValue={d => d.value ?? 0}
111
+ title={chart.title}
112
+ showDataLabels={true}
113
+ theme={fuiTheme}
114
+ />
115
+ );
116
+ case 'radar':
117
+ return (
118
+ <RadarChart
119
+ data={chart.data}
120
+ getLabel={d => d.name}
121
+ getValue={d => d.value ?? 0}
122
+ title={chart.title}
123
+ theme={fuiTheme}
124
+ />
125
+ );
126
+
127
+ default:
128
+ throw new Error(`Unsupported chart type: ${type}`);
129
+ }
130
+ };
131
+
132
+ export const useChartFactory = () => {
133
+ return React.useMemo(() => ({
134
+ getChartComponent
135
+ }), []);
136
+ };
@@ -5,24 +5,8 @@ import {
5
5
  TooltipModel,
6
6
  TooltipOptions,
7
7
  } from 'chart.js';
8
- import { Theme, webLightTheme } from '@fluentui/react-components';
9
8
 
10
- import AreaChart from '../charts/areaChart/AreaChart';
11
- import BarChart from '../charts/BarChart/BarChart';
12
- import BarHorizontalChart from '../charts/barHorizontalChart/BarHotizontalChart';
13
- import BubbleChart from '../charts/bubbleChart/BubbleChart';
14
- import ComboChart from '../charts/ComboChart/ComboChart';
15
- import DoughnutChart from '../charts/Doughnut/DoughnutChart';
16
- import FloatingBarChart from '../charts/floatBarChart/FloatBarChart';
17
- import { IChart } from '../models/IChart';
18
- import LineChart from '../charts/lineChart/LineChart';
19
- import PieChart from '../charts/PieChart/PieChart';
20
- import PolarChart from '../charts/polarChart/PolarChart';
21
- import RadarChart from '../charts/radarChart/RadarChart';
22
- import React from 'react';
23
- import ScatterChart from '../charts/scatterChart/ScatterChart';
24
- import StackedLineChart from '../charts/stackedLineChart/StackedLineChart';
25
- import SteamChart from '../charts/steamChart/SteamChart';
9
+ import { Theme } from '@fluentui/react-components';
26
10
  import { useMemo } from 'react';
27
11
 
28
12
  /**
@@ -62,117 +46,7 @@ export const getFluentPalette = (_theme: Theme): string[] => [
62
46
  '#79706e',
63
47
  ];
64
48
 
65
- const chartProps = (chart: IChart) => ({
66
- data: chart.data,
67
- title: chart.title,
68
- getPrimary: (d: any) => d.name,
69
- getSecondary: (d: any) => d.value,
70
- });
71
49
 
72
- const getChartComponent = (chart: IChart, theme: Theme) => {
73
- const { type } = chart;
74
- const fuiTheme = theme ?? webLightTheme;
75
- switch (type) {
76
- case 'bar':
77
- return <BarChart {...chartProps(chart)} stacked={false} theme={fuiTheme} />;
78
- case 'line':
79
- return <LineChart {...chartProps(chart)} theme={fuiTheme} />;
80
- case 'area':
81
- return <AreaChart {...chartProps(chart)} stacked={false} theme={fuiTheme} />;
82
-
83
- case 'bar-horizontal':
84
- return <BarHorizontalChart {...chartProps(chart)} stacked={true} theme={fuiTheme} />;
85
- case 'bubble':
86
- return (
87
- <BubbleChart {...chartProps(chart)} getRadius={d => d.radius ?? 1} theme={fuiTheme} />
88
- );
89
- case 'multiple-axes':
90
- return (
91
- <ComboChart
92
- {...chartProps(chart)}
93
- theme={fuiTheme}
94
-
95
- data={chart.data.map((series: any) => ({
96
- label: series.label,
97
- type: series.type ?? 'bar',
98
- data: series.data,
99
- yAxisID: series.secondaryAxisId,
100
-
101
- }))}
102
- />
103
- );
104
- case 'steam':
105
- return <SteamChart {...chartProps(chart)} theme={fuiTheme} />;
106
- case 'floating-bar':
107
- return (
108
- <FloatingBarChart
109
- getRange={d => [d.min ?? 0, d.max ?? 0]}
110
- {...chartProps(chart)}
111
- theme={fuiTheme}
112
- />
113
- );
114
- case 'stacked-line':
115
- return <StackedLineChart {...chartProps(chart)} theme={fuiTheme} />;
116
- case 'doughnut':
117
- return (
118
- <DoughnutChart
119
- getLabel={datum => datum.name}
120
- getValue={datum => datum.value ?? 0}
121
- {...chartProps(chart)}
122
- theme={fuiTheme}
123
- />
124
- );
125
- case 'pie':
126
- return (
127
- <PieChart
128
- getLabel={datum => datum.name}
129
- getValue={datum => datum.value ?? 0}
130
- showDataLabels={true}
131
- {...chartProps(chart)}
132
- theme={fuiTheme}
133
- />
134
- );
135
- case 'scatter':
136
- return (
137
- <ScatterChart
138
- getX={d => {
139
- if (typeof d.x === 'number') return d.x;
140
- if (typeof d.x === 'string') return Number(d.x) || 0;
141
- if (d.x instanceof Date) return d.x.getTime();
142
- return 0;
143
- }}
144
- getY={d => (typeof d.y === 'number' ? d.y : 0)}
145
- {...chartProps(chart)}
146
- theme={fuiTheme}
147
- showDataLabels={false}
148
- />
149
- );
150
- case 'polar':
151
- return (
152
- <PolarChart
153
- data={chart.data}
154
- getLabel={d => d.name}
155
- getValue={d => d.value ?? 0}
156
- title={chart.title}
157
- showDataLabels={true}
158
- theme={fuiTheme}
159
- />
160
- );
161
- case 'radar':
162
- return (
163
- <RadarChart
164
- data={chart.data}
165
- getLabel={d => d.name}
166
- getValue={d => d.value ?? 0}
167
- title={chart.title}
168
- theme={fuiTheme}
169
- />
170
- );
171
-
172
- default:
173
- throw new Error(`Unsupported chart type: ${type}`);
174
- }
175
- };
176
50
 
177
51
  /**
178
52
  * Smart Fluent tooltip generator with chart-type awareness.
@@ -297,14 +171,13 @@ function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): T {
297
171
  }
298
172
 
299
173
  /**
300
- * useGraphUtils — shared theming and chart helpers.
174
+ * useChartUtils — shared theming and chart helpers.
301
175
  */
302
- export function useGraphUtils(theme?: Theme) {
176
+ export function useChartUtils(theme?: Theme) {
303
177
  return useMemo(
304
178
  () => ({
305
179
  lightenColor,
306
180
  getFluentPalette,
307
- getChartComponent,
308
181
  createFluentTooltip,
309
182
  createAxisLabelFormatter,
310
183
  debounce
@@ -0,0 +1,122 @@
1
+ /* eslint-disable @typescript-eslint/no-floating-promises */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ /* eslint-disable @typescript-eslint/explicit-function-return-type */
4
+ import {
5
+ DBSchema,
6
+ openDB,
7
+ } from 'idb';
8
+
9
+ import { useEffect } from 'react';
10
+
11
+ export interface CacheData<T> {
12
+ data: T;
13
+ timestamp: number;
14
+ }
15
+
16
+ interface CacheDB<T> extends DBSchema {
17
+ cache: {
18
+ key: string;
19
+ value: CacheData<T>;
20
+ };
21
+ }
22
+
23
+ interface UseIndexedDBCacheReturn<T> {
24
+ getData: (key: string) => Promise<T | undefined>;
25
+ setData: (key: string, data: T) => Promise<void>;
26
+ deleteData: (key: string) => Promise<void>;
27
+ clearAllCache: () => Promise<void>;
28
+ }
29
+
30
+ const CACHE: string = "application-cache";
31
+
32
+ const openDatabase = async <T>() => {
33
+ return openDB<CacheDB<T>>('app-cache-db', 1, {
34
+ upgrade(db) {
35
+ db.createObjectStore(CACHE as never);
36
+ },
37
+ });
38
+ };
39
+
40
+ const getCachedData = async <T>(key: string): Promise<T | undefined> => {
41
+ const db = await openDatabase<T>();
42
+ const cached = await db.get((CACHE as never), key);
43
+ return cached ? cached.data : undefined;
44
+ };
45
+
46
+ const setCachedData = async <T>(key: string, data: T): Promise<void> => {
47
+ const db = await openDatabase<T>();
48
+ await db.put(CACHE as never, { data, timestamp: Date.now() }, key);
49
+ };
50
+
51
+ const deleteCachedData = async (key: string): Promise<void> => {
52
+ const db = await openDatabase<any>();
53
+ await db.delete(CACHE as never, key);
54
+ };
55
+
56
+ const clearCache = async (): Promise<void> => {
57
+ const db = await openDatabase<any>();
58
+ await db.clear(CACHE as never);
59
+ };
60
+
61
+ const clearExpiredCache = async (maxAge: number): Promise<void> => {
62
+ const db = await openDatabase<any>();
63
+ const allKeys = await db.getAllKeys(CACHE as never);
64
+ const now = Date.now();
65
+
66
+ for (const key of allKeys) {
67
+ const cached = await db.get(CACHE as never, key as string);
68
+ if (cached && now - cached.timestamp > maxAge) {
69
+ await db.delete(CACHE as never, key);
70
+ }
71
+ }
72
+ };
73
+ const DEFAULT_MAX_AGE = 24 * 60 * 60 * 1000; // 1 day in milliseconds
74
+ /**
75
+ * Custom hook to manage IndexedDB cache with a specified maximum age.
76
+ *
77
+ * @template T - The type of data to be cached.
78
+ * @param {number} [maxAge=DEFAULT_MAX_AGE] - The maximum age (in milliseconds) for cached data before it is considered expired.
79
+ * @returns {UseIndexedDBCacheReturn<T>} An object containing methods to interact with the cache.
80
+ *
81
+ * @example
82
+ * const { getData, setData, deleteData, clearAllCache } = useIndexedDBCache<MyDataType>(3600000);
83
+ *
84
+ * @function
85
+ * @name useIndexedDBCache
86
+ * @memberof hooks
87
+ * @inner
88
+ *
89
+ * @typedef {Object} UseIndexedDBCacheReturn<T>
90
+ * @property {function(string): Promise<T | undefined>} getData - Retrieves cached data by key.
91
+ * @property {function(string, T): Promise<void>} setData - Caches data with a specified key.
92
+ * @property {function(string): Promise<void>} deleteData - Deletes cached data by key.
93
+ * @property {function(): Promise<void>} clearAllCache - Clears all cached data.
94
+ */
95
+ export const useIndexedDBCache = <T>(maxAge: number = DEFAULT_MAX_AGE): UseIndexedDBCacheReturn<T> => {
96
+ useEffect(() => {
97
+ // Clear expired cache on component mount
98
+ (async () => {
99
+ await clearExpiredCache(maxAge);
100
+ })();
101
+ }, [maxAge]);
102
+
103
+ const getData = async (key: string): Promise<T | undefined> => {
104
+ return await getCachedData<T>(key);
105
+ };
106
+
107
+ const setData = async (key: string, data: T): Promise<void> => {
108
+ await setCachedData<T>(key, data);
109
+ };
110
+
111
+ const deleteData = async (key: string): Promise<void> => {
112
+ await deleteCachedData(key);
113
+ };
114
+
115
+ const clearAllCache = async (): Promise<void> => {
116
+ await clearCache();
117
+ };
118
+
119
+ return { getData, setData, deleteData, clearAllCache };
120
+ };
121
+
122
+ export default useIndexedDBCache;
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useRef, useState } from 'react';
2
2
 
3
3
  import { ResizeObserver } from '@juggle/resize-observer';
4
- import { useGraphUtils } from './useGraphUtils';
4
+ import { useChartUtils } from './useChartUtils';
5
5
 
6
6
  const BUTTON_WIDTH = 100;
7
7
  const GAP = 10;
@@ -9,7 +9,7 @@ const GAP = 10;
9
9
  export function useResponsiveLegend<T extends { label: string }>(items: T[]) {
10
10
  const containerRef = useRef<HTMLDivElement>(null);
11
11
  const [maxVisible, setMaxVisible] = useState(items.length);
12
- const { debounce } = useGraphUtils();
12
+ const { debounce } = useChartUtils();
13
13
  useEffect(() => {
14
14
  const measure = () => {
15
15
  const containerWidth = containerRef.current?.offsetWidth ?? 0;
package/src/index.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
 
2
2
  export * from './components';
3
3
  export * from './hooks';
4
+ export {useChartUtils as useGraphUtils} from './hooks/useChartUtils';
4
5
  export * from './models';
@@ -1,5 +1,3 @@
1
- 'use client';
2
-
3
1
  import { ChartDatum } from './ChartDatum';
4
2
  import { IChart } from '.';
5
3