@automattic/charts 0.26.0 → 0.28.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.
- package/CHANGELOG.md +11 -0
- package/dist/cjs/components/bar-chart/bar-chart.js +16 -6
- package/dist/cjs/components/leaderboard-chart/leaderboard-chart.js +23 -14
- package/dist/cjs/components/leaderboard-chart/leaderboard-chart.module.scss.js +1 -1
- package/dist/cjs/components/legend/base-legend.js +6 -2
- package/dist/cjs/components/legend/use-chart-legend-data.js +6 -2
- package/dist/cjs/components/line-chart/line-chart-annotation.js +7 -4
- package/dist/cjs/components/line-chart/line-chart.js +16 -6
- package/dist/cjs/components/pie-chart/index.js +1 -0
- package/dist/cjs/components/pie-chart/pie-chart.js +115 -31
- package/dist/cjs/components/pie-semi-circle-chart/pie-semi-circle-chart.js +111 -19
- package/dist/cjs/hooks/use-chart-mouse-handler.js +1 -3
- package/dist/cjs/hooks/use-deep-memo.js +21 -0
- package/dist/cjs/hooks/use-global-chart-theme.js +28 -0
- package/dist/cjs/hooks/use-xychart-theme.js +20 -0
- package/dist/cjs/index.js +9 -1
- package/dist/cjs/providers/chart-context/global-charts-provider.js +5 -2
- package/dist/cjs/providers/chart-context/utils.js +11 -5
- package/dist/cjs/providers/theme/index.js +0 -1
- package/dist/cjs/providers/theme/theme-provider.js +2 -18
- package/dist/cjs/style.css +1 -1
- package/dist/cjs/utils/merge-themes.js +21 -0
- package/dist/mjs/components/bar-chart/bar-chart.js +15 -5
- package/dist/mjs/components/leaderboard-chart/leaderboard-chart.js +24 -15
- package/dist/mjs/components/leaderboard-chart/leaderboard-chart.module.scss.js +1 -1
- package/dist/mjs/components/legend/base-legend.js +6 -2
- package/dist/mjs/components/legend/use-chart-legend-data.js +6 -2
- package/dist/mjs/components/line-chart/line-chart-annotation.js +7 -4
- package/dist/mjs/components/line-chart/line-chart.js +15 -5
- package/dist/mjs/components/pie-chart/index.js +1 -1
- package/dist/mjs/components/pie-chart/pie-chart.js +116 -33
- package/dist/mjs/components/pie-semi-circle-chart/pie-semi-circle-chart.js +114 -22
- package/dist/mjs/hooks/use-chart-mouse-handler.js +1 -1
- package/dist/mjs/hooks/use-deep-memo.js +19 -0
- package/dist/mjs/hooks/use-global-chart-theme.js +26 -0
- package/dist/mjs/hooks/use-xychart-theme.js +18 -0
- package/dist/mjs/index.js +5 -1
- package/dist/mjs/providers/chart-context/global-charts-provider.js +6 -3
- package/dist/mjs/providers/chart-context/utils.js +11 -5
- package/dist/mjs/providers/theme/index.js +1 -1
- package/dist/mjs/providers/theme/theme-provider.js +4 -19
- package/dist/mjs/style.css +1 -1
- package/dist/mjs/utils/merge-themes.js +19 -0
- package/dist/types/components/bar-list-chart/bar-list-chart.d.ts +1 -1
- package/dist/types/components/leaderboard-chart/leaderboard-chart.d.ts +22 -13
- package/dist/types/components/legend/base-legend.d.ts +9 -9
- package/dist/types/components/legend/use-chart-legend-data.d.ts +2 -3
- package/dist/types/components/pie-chart/index.d.ts +1 -1
- package/dist/types/components/pie-chart/pie-chart.d.ts +14 -5
- package/dist/types/components/pie-semi-circle-chart/pie-semi-circle-chart.d.ts +16 -4
- package/dist/types/hooks/use-chart-mouse-handler.d.ts +1 -1
- package/dist/types/hooks/use-deep-memo.d.ts +10 -0
- package/dist/types/hooks/use-global-chart-theme.d.ts +14 -0
- package/dist/types/hooks/use-xychart-theme.d.ts +6 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/providers/chart-context/global-charts-provider.d.ts +3 -0
- package/dist/types/providers/chart-context/types.d.ts +2 -1
- package/dist/types/providers/chart-context/utils.d.ts +7 -2
- package/dist/types/providers/theme/index.d.ts +1 -1
- package/dist/types/providers/theme/theme-provider.d.ts +3 -5
- package/dist/types/utils/merge-themes.d.ts +13 -0
- package/package.json +2 -1
|
@@ -10,12 +10,16 @@ var text = require('@visx/text');
|
|
|
10
10
|
var tooltip = require('@visx/tooltip');
|
|
11
11
|
var clsx = require('clsx');
|
|
12
12
|
var react = require('react');
|
|
13
|
+
require('fast-deep-equal');
|
|
14
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
15
|
+
require('@visx/xychart');
|
|
13
16
|
var globalChartsProvider = require('../../providers/chart-context/global-charts-provider.js');
|
|
14
17
|
var utils = require('../../providers/chart-context/utils.js');
|
|
15
|
-
var
|
|
18
|
+
var createComposition = require('../../utils/create-composition.js');
|
|
16
19
|
var legend = require('../legend/legend.js');
|
|
17
20
|
require('../legend/base-legend.js');
|
|
18
21
|
var useChartLegendData = require('../legend/use-chart-legend-data.js');
|
|
22
|
+
var singleChartContext = require('../shared/single-chart-context.js');
|
|
19
23
|
var useElementHeight = require('../shared/use-element-height.js');
|
|
20
24
|
var withResponsive = require('../shared/with-responsive.js');
|
|
21
25
|
var baseTooltip = require('../tooltip/base-tooltip.js');
|
|
@@ -43,8 +47,34 @@ const validateData = (data) => {
|
|
|
43
47
|
}
|
|
44
48
|
return { isValid: true, message: '' };
|
|
45
49
|
};
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Compound component for SVG children in the PieSemiCircleChart
|
|
52
|
+
* @param {PropsWithChildren} props - Component props
|
|
53
|
+
* @param {ReactNode} props.children - Child elements to render
|
|
54
|
+
* @return {JSX.Element} The children wrapped in a fragment
|
|
55
|
+
*/
|
|
56
|
+
const PieSemiCircleChartSVG = ({ children }) => {
|
|
57
|
+
// This component doesn't render directly - its children are extracted by PieSemiCircleChart
|
|
58
|
+
// We just return the children as-is
|
|
59
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
|
|
60
|
+
};
|
|
61
|
+
// Set displayName for better debugging and type checking
|
|
62
|
+
PieSemiCircleChartSVG.displayName = 'PieSemiCircleChart.SVG';
|
|
63
|
+
/**
|
|
64
|
+
* Compound component for HTML children in the PieSemiCircleChart
|
|
65
|
+
* @param {PropsWithChildren} props - Component props
|
|
66
|
+
* @param {ReactNode} props.children - Child elements to render
|
|
67
|
+
* @return {JSX.Element} The children wrapped in a fragment
|
|
68
|
+
*/
|
|
69
|
+
const PieSemiCircleChartHTML = ({ children }) => {
|
|
70
|
+
// This component doesn't render directly - its children are extracted by PieSemiCircleChart
|
|
71
|
+
// We just return the children as-is
|
|
72
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
|
|
73
|
+
};
|
|
74
|
+
// Set displayName for better debugging and type checking
|
|
75
|
+
PieSemiCircleChartHTML.displayName = 'PieSemiCircleChart.HTML';
|
|
76
|
+
const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width = 400, thickness = 0.4, clockwise = true, withTooltips = false, showLegend = false, legendOrientation = 'horizontal', legendPosition = 'bottom', legendAlignment = 'center', legendShape = 'circle', label, note, className, children, }) => {
|
|
77
|
+
const providerTheme = useGlobalChartTheme.useGlobalChartTheme();
|
|
48
78
|
const chartId = utils.useChartId(providedChartId);
|
|
49
79
|
const [legendRef, legendHeight] = useElementHeight.useElementHeight();
|
|
50
80
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = tooltip.useTooltip();
|
|
@@ -76,14 +106,53 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width = 40
|
|
|
76
106
|
// Memoize legend options to prevent unnecessary re-calculations
|
|
77
107
|
const legendOptions = react.useMemo(() => ({ showValues: true }), []);
|
|
78
108
|
// Create legend items using the reusable hook
|
|
79
|
-
const legendItems = useChartLegendData.useChartLegendData(data,
|
|
109
|
+
const legendItems = useChartLegendData.useChartLegendData(data, legendOptions);
|
|
110
|
+
// Process children to extract compound components
|
|
111
|
+
const { svgChildren, htmlChildren, otherChildren } = react.useMemo(() => {
|
|
112
|
+
const svg = [];
|
|
113
|
+
const html = [];
|
|
114
|
+
const other = [];
|
|
115
|
+
react.Children.forEach(children, child => {
|
|
116
|
+
if (react.isValidElement(child)) {
|
|
117
|
+
// Check displayName for compound components
|
|
118
|
+
const childType = child.type;
|
|
119
|
+
const displayName = childType?.displayName;
|
|
120
|
+
if (displayName === 'PieSemiCircleChart.SVG') {
|
|
121
|
+
// Extract children from PieSemiCircleChart.SVG
|
|
122
|
+
react.Children.forEach(child.props.children, svgChild => {
|
|
123
|
+
svg.push(svgChild);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else if (displayName === 'PieSemiCircleChart.HTML') {
|
|
127
|
+
// Extract children from PieSemiCircleChart.HTML
|
|
128
|
+
react.Children.forEach(child.props.children, htmlChild => {
|
|
129
|
+
html.push(htmlChild);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else if (child.type === group.Group) {
|
|
133
|
+
// Legacy support: still check for Group type for backward compatibility
|
|
134
|
+
svg.push(child);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
other.push(child);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return { svgChildren: svg, htmlChildren: html, otherChildren: other };
|
|
142
|
+
}, [children]);
|
|
80
143
|
// Memoize metadata to prevent unnecessary re-registration
|
|
81
144
|
const chartMetadata = react.useMemo(() => ({
|
|
82
145
|
thickness,
|
|
83
146
|
clockwise,
|
|
84
147
|
}), [thickness, clockwise]);
|
|
85
148
|
// Register chart with context only if data is valid
|
|
86
|
-
utils.useChartRegistration(
|
|
149
|
+
utils.useChartRegistration({
|
|
150
|
+
chartId,
|
|
151
|
+
legendItems,
|
|
152
|
+
chartType: 'pie-semi-circle',
|
|
153
|
+
isDataValid: isValid,
|
|
154
|
+
metadata: chartMetadata,
|
|
155
|
+
});
|
|
87
156
|
if (!isValid) {
|
|
88
157
|
return (jsxRuntime.jsx("div", { className: pieSemiCircleChart_module.default['pie-semi-circle-chart'], children: jsxRuntime.jsx("svg", { width: width, height: width / 2, "data-testid": "pie-chart-svg", children: jsxRuntime.jsx("text", { x: "50%", y: "50%", textAnchor: "middle", className: pieSemiCircleChart_module.default.error, children: message }) }) }));
|
|
89
158
|
}
|
|
@@ -102,19 +171,42 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width = 40
|
|
|
102
171
|
// Configure pie angles based on clockwise direction
|
|
103
172
|
const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2;
|
|
104
173
|
const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2;
|
|
105
|
-
return (jsxRuntime.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
174
|
+
return (jsxRuntime.jsx(singleChartContext.SingleChartContext.Provider, { value: {
|
|
175
|
+
chartId,
|
|
176
|
+
chartWidth: width,
|
|
177
|
+
chartHeight: radius,
|
|
178
|
+
}, children: jsxRuntime.jsxs("div", { className: clsx('pie-semi-circle-chart', pieSemiCircleChart_module.default['pie-semi-circle-chart'], className), "data-testid": "pie-chart-container", style: {
|
|
179
|
+
display: 'flex',
|
|
180
|
+
flexDirection: showLegend && legendPosition === 'top' ? 'column-reverse' : 'column',
|
|
181
|
+
}, children: [jsxRuntime.jsx("svg", { width: width, height: radius, viewBox: `0 0 ${width} ${chartHeight}`, "data-testid": "pie-chart-svg", children: jsxRuntime.jsxs(group.Group, { top: chartHeight, left: width / 2, children: [jsxRuntime.jsx(shape.Pie, { data: dataWithIndex, pieValue: accessors.value, outerRadius: radius, innerRadius: innerRadius, cornerRadius: 3, padAngle: PAD_ANGLE, startAngle: startAngle, endAngle: endAngle, pieSort: accessors.sort, children: pie => {
|
|
182
|
+
return pie.arcs.map(arc => (jsxRuntime.jsx("g", { onMouseMove: handleArcMouseMove(arc), onMouseLeave: handleMouseLeave, children: jsxRuntime.jsx("path", { d: pie.path(arc) || '', fill: accessors.fill(arc.data), "data-testid": "pie-segment" }) }, arc.data.label)));
|
|
183
|
+
} }), jsxRuntime.jsxs(group.Group, { children: [jsxRuntime.jsx(text.Text, { textAnchor: "middle", verticalAnchor: "start", y: -40, className: pieSemiCircleChart_module.default.label, children: label }), jsxRuntime.jsx(text.Text, { textAnchor: "middle", verticalAnchor: "start", y: -20, className: pieSemiCircleChart_module.default.note, children: note })] }), svgChildren] }) }), withTooltips && tooltipOpen && tooltipData && (jsxRuntime.jsx(baseTooltip.BaseTooltip, { data: {
|
|
184
|
+
label: tooltipData.label,
|
|
185
|
+
value: tooltipData.value,
|
|
186
|
+
valueDisplay: tooltipData.valueDisplay,
|
|
187
|
+
}, top: tooltipTop || 0, left: tooltipLeft || 0 })), showLegend && (jsxRuntime.jsx(legend.Legend, { items: legendItems, orientation: legendOrientation, position: legendPosition, alignment: legendAlignment, shape: legendShape, ref: legendRef, chartId: chartId })), htmlChildren, otherChildren] }) }));
|
|
188
|
+
};
|
|
189
|
+
const PieSemiCircleChartWithProvider = props => {
|
|
190
|
+
const existingContext = react.useContext(globalChartsProvider.GlobalChartsContext);
|
|
191
|
+
// If we're already in a GlobalChartsProvider context, don't create a new one
|
|
192
|
+
if (existingContext) {
|
|
193
|
+
return jsxRuntime.jsx(PieSemiCircleChartInternal, { ...props });
|
|
194
|
+
}
|
|
195
|
+
// Otherwise, create our own GlobalChartsProvider
|
|
196
|
+
return (jsxRuntime.jsx(globalChartsProvider.GlobalChartsProvider, { children: jsxRuntime.jsx(PieSemiCircleChartInternal, { ...props }) }));
|
|
115
197
|
};
|
|
116
|
-
|
|
117
|
-
PieSemiCircleChart
|
|
118
|
-
|
|
198
|
+
PieSemiCircleChartWithProvider.displayName = 'PieSemiCircleChart';
|
|
199
|
+
// Create PieSemiCircleChart with composition API
|
|
200
|
+
createComposition.attachSubComponents(PieSemiCircleChartWithProvider, {
|
|
201
|
+
Legend: legend.Legend,
|
|
202
|
+
SVG: PieSemiCircleChartSVG,
|
|
203
|
+
HTML: PieSemiCircleChartHTML,
|
|
204
|
+
});
|
|
205
|
+
// Create responsive PieSemiCircleChart with composition API
|
|
206
|
+
const PieSemiCircleChartResponsive = createComposition.attachSubComponents(withResponsive.withResponsive(PieSemiCircleChartWithProvider), {
|
|
207
|
+
Legend: legend.Legend,
|
|
208
|
+
SVG: PieSemiCircleChartSVG,
|
|
209
|
+
HTML: PieSemiCircleChartHTML,
|
|
210
|
+
});
|
|
119
211
|
|
|
120
|
-
exports.default =
|
|
212
|
+
exports.default = PieSemiCircleChartResponsive;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
var event = require('@visx/event');
|
|
6
4
|
var tooltip = require('@visx/tooltip');
|
|
7
5
|
var react = require('react');
|
|
@@ -45,4 +43,4 @@ const useChartMouseHandler = ({ withTooltips, }) => {
|
|
|
45
43
|
};
|
|
46
44
|
};
|
|
47
45
|
|
|
48
|
-
exports.
|
|
46
|
+
exports.useChartMouseHandler = useChartMouseHandler;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var isEqual = require('fast-deep-equal');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Custom hook to memoize a value using deep equality comparison.
|
|
8
|
+
* Prevents unnecessary re-renders when objects have the same content but different references.
|
|
9
|
+
*
|
|
10
|
+
* @param value - The value to memoize with deep equality comparison
|
|
11
|
+
* @return The memoized value that only changes when deeply different
|
|
12
|
+
*/
|
|
13
|
+
const useDeepMemo = (value) => {
|
|
14
|
+
const ref = react.useRef(value);
|
|
15
|
+
if (!isEqual(ref.current, value)) {
|
|
16
|
+
ref.current = value;
|
|
17
|
+
}
|
|
18
|
+
return ref.current;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
exports.useDeepMemo = useDeepMemo;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var globalChartsProvider = require('../providers/chart-context/global-charts-provider.js');
|
|
5
|
+
var themeProvider = require('../providers/theme/theme-provider.js');
|
|
6
|
+
var themes = require('../providers/theme/themes.js');
|
|
7
|
+
var mergeThemes = require('../utils/merge-themes.js');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook to get the effective chart theme, merging global and local themes.
|
|
11
|
+
*
|
|
12
|
+
* This hook combines the global theme from GlobalChartsProvider with the local theme
|
|
13
|
+
* from ThemeProvider. The global theme provides the base, while the local theme
|
|
14
|
+
* can override specific properties for fine-grained customization.
|
|
15
|
+
*
|
|
16
|
+
* @return The effective chart theme to use
|
|
17
|
+
*/
|
|
18
|
+
const useGlobalChartTheme = () => {
|
|
19
|
+
// Get context but don't throw if it doesn't exist (for testing or standalone usage)
|
|
20
|
+
const context = react.useContext(globalChartsProvider.GlobalChartsContext);
|
|
21
|
+
const globalTheme = context?.theme;
|
|
22
|
+
const localTheme = themeProvider.useChartTheme();
|
|
23
|
+
// Memoize the theme to prevent unnecessary re-renders
|
|
24
|
+
const effectiveTheme = react.useMemo(() => mergeThemes.mergeThemes(globalTheme ?? themes.defaultTheme, localTheme), [globalTheme, localTheme]);
|
|
25
|
+
return effectiveTheme;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.useGlobalChartTheme = useGlobalChartTheme;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var xychart = require('@visx/xychart');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var useGlobalChartTheme = require('./use-global-chart-theme.js');
|
|
6
|
+
|
|
7
|
+
const useXYChartTheme = (data) => {
|
|
8
|
+
const theme = useGlobalChartTheme.useGlobalChartTheme();
|
|
9
|
+
return react.useMemo(() => {
|
|
10
|
+
const seriesColors = (data ?? [])
|
|
11
|
+
.map(series => series.options?.stroke)
|
|
12
|
+
.filter((color) => Boolean(color));
|
|
13
|
+
return xychart.buildChartTheme({
|
|
14
|
+
...theme,
|
|
15
|
+
colors: [...seriesColors, ...(theme.colors ?? [])],
|
|
16
|
+
});
|
|
17
|
+
}, [theme, data]);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
exports.useXYChartTheme = useXYChartTheme;
|
package/dist/cjs/index.js
CHANGED
|
@@ -16,7 +16,11 @@ var group = require('@visx/group');
|
|
|
16
16
|
var legend$1 = require('@visx/legend');
|
|
17
17
|
var themeProvider = require('./providers/theme/theme-provider.js');
|
|
18
18
|
var themes = require('./providers/theme/themes.js');
|
|
19
|
+
var mergeThemes = require('./utils/merge-themes.js');
|
|
20
|
+
var useDeepMemo = require('./hooks/use-deep-memo.js');
|
|
21
|
+
var useGlobalChartTheme = require('./hooks/use-global-chart-theme.js');
|
|
19
22
|
var useChartMouseHandler = require('./hooks/use-chart-mouse-handler.js');
|
|
23
|
+
var useXychartTheme = require('./hooks/use-xychart-theme.js');
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
|
|
@@ -63,4 +67,8 @@ exports.ThemeProvider = themeProvider.ThemeProvider;
|
|
|
63
67
|
exports.defaultTheme = themes.defaultTheme;
|
|
64
68
|
exports.jetpackTheme = themes.jetpackTheme;
|
|
65
69
|
exports.wooTheme = themes.wooTheme;
|
|
66
|
-
exports.
|
|
70
|
+
exports.mergeThemes = mergeThemes.mergeThemes;
|
|
71
|
+
exports.useDeepMemo = useDeepMemo.useDeepMemo;
|
|
72
|
+
exports.useGlobalChartTheme = useGlobalChartTheme.useGlobalChartTheme;
|
|
73
|
+
exports.useChartMouseHandler = useChartMouseHandler.useChartMouseHandler;
|
|
74
|
+
exports.useXYChartTheme = useXychartTheme.useXYChartTheme;
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var themes = require('../theme/themes.js');
|
|
5
6
|
|
|
6
7
|
const GlobalChartsContext = react.createContext(null);
|
|
7
|
-
const GlobalChartsProvider = ({ children }) => {
|
|
8
|
+
const GlobalChartsProvider = ({ children, theme = {}, }) => {
|
|
8
9
|
const [charts, setCharts] = react.useState(() => new Map());
|
|
10
|
+
const providerTheme = react.useMemo(() => ({ ...themes.defaultTheme, ...theme }), [theme]);
|
|
9
11
|
const registerChart = react.useCallback((id, data) => {
|
|
10
12
|
setCharts(prev => new Map(prev).set(id, data));
|
|
11
13
|
}, []);
|
|
@@ -24,7 +26,8 @@ const GlobalChartsProvider = ({ children }) => {
|
|
|
24
26
|
registerChart,
|
|
25
27
|
unregisterChart,
|
|
26
28
|
getChartData,
|
|
27
|
-
|
|
29
|
+
theme: providerTheme,
|
|
30
|
+
}), [charts, registerChart, unregisterChart, getChartData, providerTheme]);
|
|
28
31
|
return jsxRuntime.jsx(GlobalChartsContext.Provider, { value: value, children: children });
|
|
29
32
|
};
|
|
30
33
|
const useGlobalChartsContext = () => {
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
|
+
var useDeepMemo = require('../../hooks/use-deep-memo.js');
|
|
4
5
|
var globalChartsProvider = require('./global-charts-provider.js');
|
|
6
|
+
require('../theme/theme-provider.js');
|
|
7
|
+
require('deepmerge');
|
|
8
|
+
require('@visx/event');
|
|
9
|
+
require('@visx/tooltip');
|
|
10
|
+
require('@visx/xychart');
|
|
5
11
|
|
|
6
12
|
const useChartId = (providedId) => {
|
|
7
13
|
const generatedId = react.useId();
|
|
8
14
|
return providedId || generatedId;
|
|
9
15
|
};
|
|
10
|
-
const useChartRegistration = (chartId, legendItems,
|
|
16
|
+
const useChartRegistration = ({ chartId, legendItems, chartType, isDataValid, metadata, }) => {
|
|
11
17
|
const { registerChart, unregisterChart } = globalChartsProvider.useGlobalChartsContext();
|
|
18
|
+
// Memoize legendItems with deep comparison to prevent infinite loops
|
|
19
|
+
const stableLegendItems = useDeepMemo.useDeepMemo(legendItems);
|
|
12
20
|
// Memoize metadata to prevent unnecessary re-renders
|
|
13
21
|
const memoizedMetadata = react.useMemo(() => metadata, [metadata]);
|
|
14
22
|
react.useEffect(() => {
|
|
15
23
|
// Only register if data is valid
|
|
16
24
|
if (isDataValid) {
|
|
17
25
|
registerChart(chartId, {
|
|
18
|
-
legendItems,
|
|
19
|
-
theme,
|
|
26
|
+
legendItems: stableLegendItems,
|
|
20
27
|
chartType,
|
|
21
28
|
metadata: memoizedMetadata,
|
|
22
29
|
});
|
|
@@ -27,8 +34,7 @@ const useChartRegistration = (chartId, legendItems, theme, chartType, isDataVali
|
|
|
27
34
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
35
|
}, [
|
|
29
36
|
chartId,
|
|
30
|
-
|
|
31
|
-
theme,
|
|
37
|
+
stableLegendItems,
|
|
32
38
|
chartType,
|
|
33
39
|
memoizedMetadata,
|
|
34
40
|
isDataValid,
|
|
@@ -7,7 +7,6 @@ var themes = require('./themes.js');
|
|
|
7
7
|
|
|
8
8
|
exports.ThemeProvider = themeProvider.ThemeProvider;
|
|
9
9
|
exports.useChartTheme = themeProvider.useChartTheme;
|
|
10
|
-
exports.useXYChartTheme = themeProvider.useXYChartTheme;
|
|
11
10
|
exports.defaultTheme = themes.defaultTheme;
|
|
12
11
|
exports.jetpackTheme = themes.jetpackTheme;
|
|
13
12
|
exports.wooTheme = themes.wooTheme;
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var xychart = require('@visx/xychart');
|
|
5
4
|
var react = require('react');
|
|
6
|
-
var themes = require('./themes.js');
|
|
7
5
|
|
|
8
6
|
/**
|
|
9
7
|
* Context for sharing theme configuration across components
|
|
10
8
|
*/
|
|
11
|
-
const ThemeContext = react.createContext(
|
|
9
|
+
const ThemeContext = react.createContext({});
|
|
12
10
|
/**
|
|
13
11
|
* Hook to access chart theme
|
|
14
12
|
* @return {object} A built theme configuration compatible with visx charts
|
|
@@ -17,25 +15,11 @@ const useChartTheme = () => {
|
|
|
17
15
|
const theme = react.useContext(ThemeContext);
|
|
18
16
|
return theme;
|
|
19
17
|
};
|
|
20
|
-
const useXYChartTheme = (data) => {
|
|
21
|
-
const providerTheme = useChartTheme();
|
|
22
|
-
return react.useMemo(() => {
|
|
23
|
-
const seriesColors = (data ?? [])
|
|
24
|
-
.map(series => series.options?.stroke)
|
|
25
|
-
.filter((color) => Boolean(color));
|
|
26
|
-
return xychart.buildChartTheme({
|
|
27
|
-
...providerTheme,
|
|
28
|
-
colors: [...seriesColors, ...(providerTheme.colors ?? [])],
|
|
29
|
-
});
|
|
30
|
-
}, [providerTheme, data]);
|
|
31
|
-
};
|
|
32
18
|
// Provider component for chart theming
|
|
33
19
|
// Allows theme customization through props while maintaining default values
|
|
34
20
|
const ThemeProvider = ({ theme = {}, children }) => {
|
|
35
|
-
|
|
36
|
-
return jsxRuntime.jsx(ThemeContext.Provider, { value: mergedTheme, children: children });
|
|
21
|
+
return jsxRuntime.jsx(ThemeContext.Provider, { value: theme, children: children });
|
|
37
22
|
};
|
|
38
23
|
|
|
39
24
|
exports.ThemeProvider = ThemeProvider;
|
|
40
25
|
exports.useChartTheme = useChartTheme;
|
|
41
|
-
exports.useXYChartTheme = useXYChartTheme;
|
package/dist/cjs/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.legend-module_legend--horizontal__IUN13{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.legend-module_legend--vertical__Scfzo{display:flex;flex-direction:column;gap:8px}.legend-module_legend--vertical__Scfzo.legend-module_legend--alignment-start__Na2Qp{align-items:flex-start}.legend-module_legend--vertical__Scfzo.legend-module_legend--alignment-center__FVB2r{align-items:center}.legend-module_legend--vertical__Scfzo.legend-module_legend--alignment-end__6Vuay{align-items:flex-end}.legend-module_legend--position-top__uh7-2{position:relative}.legend-module_legend--position-top__uh7-2.legend-module_legend--alignment-start__Na2Qp{justify-content:flex-start}.legend-module_legend--position-top__uh7-2.legend-module_legend--alignment-center__FVB2r{justify-content:center}.legend-module_legend--position-top__uh7-2.legend-module_legend--alignment-end__6Vuay{justify-content:flex-end}.legend-module_legend--position-bottom__6Q3j-{position:relative}.legend-module_legend--position-bottom__6Q3j-.legend-module_legend--alignment-start__Na2Qp{justify-content:flex-start}.legend-module_legend--position-bottom__6Q3j-.legend-module_legend--alignment-center__FVB2r{justify-content:center}.legend-module_legend--position-bottom__6Q3j-.legend-module_legend--alignment-end__6Vuay{justify-content:flex-end}.legend-module_legend-item__feemn{align-items:center;display:flex;font-size:.875rem}.legend-module_legend-item-label__ksx6I{align-items:center;display:flex;gap:.5rem}.legend-module_legend-item-value__d9x1j{font-weight:500}.bar-chart-module_bar-chart__lmYNi{display:flex;flex-direction:column}.bar-chart-module_bar-chart__lmYNi svg{overflow:visible}.bar-chart-module_bar-chart-legend__vgKKq{margin-top:1rem}.line-chart-module_line-chart__ITM3d{display:flex;flex-direction:column}.line-chart-module_line-chart__ITM3d svg{overflow:visible}.line-chart-module_line-chart__annotation-label-popover__TqNZk,.line-chart-module_line-chart__tooltip__aqcme{background:#fff;padding:.5rem}.line-chart-module_line-chart__tooltip-date__4Dzab{font-weight:700;padding-bottom:10px}.line-chart-module_line-chart__tooltip-row__6A37G{align-items:center;display:flex;justify-content:space-between;padding:4px 0}.line-chart-module_line-chart__tooltip-label__IvnFF{font-weight:500;padding-right:1rem}.line-chart-module_line-chart__annotations-overlay__4nR2p{left:0;overflow:visible;pointer-events:none;position:absolute;top:0}.line-chart-module_line-chart__annotation-label__OmgiT{pointer-events:auto}.line-chart-module_line-chart__annotation-label-trigger-button__mcIb3{align-items:center;background:none;border:none;cursor:pointer;display:flex;justify-content:center;padding:0;pointer-events:auto}.line-chart-module_line-chart__annotation-label-popover__TqNZk{background:#fff;border:none;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);font-size:14px;margin:.5rem;min-width:125px;position:fixed;visibility:hidden}.line-chart-module_line-chart__annotation-label-popover--visible__dE0cV{visibility:visible}.line-chart-module_line-chart__annotation-label-popover--safari__i3NHT{margin:auto;position:static}.line-chart-module_line-chart__annotation-label-popover-header__Owypo{align-items:start;display:flex;flex-direction:row;justify-content:space-between}.line-chart-module_line-chart__annotation-label-popover-content__vtgQt{padding:.5rem}.line-chart-module_line-chart__annotation-label-popover-close-button__i8KUc{align-items:center;background:none;border:none;cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;width:44px}.visx-tooltip-glyph svg{height:10px;width:10px}.base-tooltip-module_tooltip__OfX6n{background-color:rgba(0,0,0,.85);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);color:#fff;font-size:14px;padding:.5rem;pointer-events:none;position:absolute;transform:translate(-50%,-100%)}.pie-chart-module_pie-chart__R12Vh{display:flex;flex-direction:column;overflow:hidden}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9{display:flex;flex-direction:column;text-align:center}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_label__nPqOg{font-size:16px;font-weight:600;margin-bottom:0}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_note__LpBZQ{font-size:14px;margin-top:0}.leaderboard-chart-module_leaderboardChart__zxakP{transition:opacity .3s ease-in-out}.leaderboard-chart-module_leaderboardChart__zxakP.leaderboard-chart-module_loading__-AGv-{opacity:.5}.leaderboard-chart-module_progressContainer__BZGbj{display:flex;flex-direction:column;gap:6px}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj{background-color:transparent;border-radius:2px;height:6px;overflow:hidden;transition:width .3s ease-in-out;width:100%}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj>div{background-color:var(--progress-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_primaryBar__iybII{--progress-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_secondaryBar__A7tLz{--progress-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}
|
|
1
|
+
.legend-module_legend--horizontal__IUN13{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.legend-module_legend--vertical__Scfzo{display:flex;flex-direction:column;gap:8px}.legend-module_legend--vertical__Scfzo.legend-module_legend--alignment-start__Na2Qp{align-items:flex-start}.legend-module_legend--vertical__Scfzo.legend-module_legend--alignment-center__FVB2r{align-items:center}.legend-module_legend--vertical__Scfzo.legend-module_legend--alignment-end__6Vuay{align-items:flex-end}.legend-module_legend--position-top__uh7-2{position:relative}.legend-module_legend--position-top__uh7-2.legend-module_legend--alignment-start__Na2Qp{justify-content:flex-start}.legend-module_legend--position-top__uh7-2.legend-module_legend--alignment-center__FVB2r{justify-content:center}.legend-module_legend--position-top__uh7-2.legend-module_legend--alignment-end__6Vuay{justify-content:flex-end}.legend-module_legend--position-bottom__6Q3j-{position:relative}.legend-module_legend--position-bottom__6Q3j-.legend-module_legend--alignment-start__Na2Qp{justify-content:flex-start}.legend-module_legend--position-bottom__6Q3j-.legend-module_legend--alignment-center__FVB2r{justify-content:center}.legend-module_legend--position-bottom__6Q3j-.legend-module_legend--alignment-end__6Vuay{justify-content:flex-end}.legend-module_legend-item__feemn{align-items:center;display:flex;font-size:.875rem}.legend-module_legend-item-label__ksx6I{align-items:center;display:flex;gap:.5rem}.legend-module_legend-item-value__d9x1j{font-weight:500}.bar-chart-module_bar-chart__lmYNi{display:flex;flex-direction:column}.bar-chart-module_bar-chart__lmYNi svg{overflow:visible}.bar-chart-module_bar-chart-legend__vgKKq{margin-top:1rem}.line-chart-module_line-chart__ITM3d{display:flex;flex-direction:column}.line-chart-module_line-chart__ITM3d svg{overflow:visible}.line-chart-module_line-chart__annotation-label-popover__TqNZk,.line-chart-module_line-chart__tooltip__aqcme{background:#fff;padding:.5rem}.line-chart-module_line-chart__tooltip-date__4Dzab{font-weight:700;padding-bottom:10px}.line-chart-module_line-chart__tooltip-row__6A37G{align-items:center;display:flex;justify-content:space-between;padding:4px 0}.line-chart-module_line-chart__tooltip-label__IvnFF{font-weight:500;padding-right:1rem}.line-chart-module_line-chart__annotations-overlay__4nR2p{left:0;overflow:visible;pointer-events:none;position:absolute;top:0}.line-chart-module_line-chart__annotation-label__OmgiT{pointer-events:auto}.line-chart-module_line-chart__annotation-label-trigger-button__mcIb3{align-items:center;background:none;border:none;cursor:pointer;display:flex;justify-content:center;padding:0;pointer-events:auto}.line-chart-module_line-chart__annotation-label-popover__TqNZk{background:#fff;border:none;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);font-size:14px;margin:.5rem;min-width:125px;position:fixed;visibility:hidden}.line-chart-module_line-chart__annotation-label-popover--visible__dE0cV{visibility:visible}.line-chart-module_line-chart__annotation-label-popover--safari__i3NHT{margin:auto;position:static}.line-chart-module_line-chart__annotation-label-popover-header__Owypo{align-items:start;display:flex;flex-direction:row;justify-content:space-between}.line-chart-module_line-chart__annotation-label-popover-content__vtgQt{padding:.5rem}.line-chart-module_line-chart__annotation-label-popover-close-button__i8KUc{align-items:center;background:none;border:none;cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;width:44px}.visx-tooltip-glyph svg{height:10px;width:10px}.base-tooltip-module_tooltip__OfX6n{background-color:rgba(0,0,0,.85);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);color:#fff;font-size:14px;padding:.5rem;pointer-events:none;position:absolute;transform:translate(-50%,-100%)}.pie-chart-module_pie-chart__R12Vh{display:flex;flex-direction:column;overflow:hidden}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9{display:flex;flex-direction:column;text-align:center}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_label__nPqOg{font-size:16px;font-weight:600;margin-bottom:0}.pie-semi-circle-chart-module_pie-semi-circle-chart__r5jk9 .pie-semi-circle-chart-module_note__LpBZQ{font-size:14px;margin-top:0}.leaderboard-chart-module_leaderboardChart__zxakP{transition:opacity .3s ease-in-out}.leaderboard-chart-module_leaderboardChart__zxakP.leaderboard-chart-module_loading__-AGv-{opacity:.5}.leaderboard-chart-module_progressContainerWithOverlayLabel__YFPY0{align-items:center;display:grid;grid-template:"overlap" 1fr/1fr}.leaderboard-chart-module_progressContainerWithOverlayLabel__YFPY0>*{grid-area:overlap}.leaderboard-chart-module_progressContainerWithOverlayLabel__YFPY0 .leaderboard-chart-module_progressBar__LAQaj{background-color:var(--primary-color,#3858e9);border-radius:var(--bar-border,9999px);height:100%;transition:width .3s ease-in-out;z-index:-1}.leaderboard-chart-module_progressContainerWithOverlayLabel__YFPY0 .leaderboard-chart-module_progressBarLabel__24t-j{padding-left:8px}.leaderboard-chart-module_progressContainer__BZGbj{display:flex;flex-direction:column;gap:6px}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj{background-color:transparent;border-radius:2px;height:6px;overflow:hidden;transition:width .3s ease-in-out;width:100%}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_progressBar__LAQaj>div{background-color:var(--progress-color,#3858e9);border-radius:var(--bar-border,9999px)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_primaryBar__iybII{--progress-color:var(--primary-color,#3858e9)}.leaderboard-chart-module_progressContainer__BZGbj .leaderboard-chart-module_secondaryBar__A7tLz{--progress-color:var(--secondary-color,#66bdff)}.leaderboard-chart-module_valueContainer__ZlLh4{display:flex;gap:4px;justify-content:flex-end}.leaderboard-chart-module_overlayLabel__pRqSh{align-items:center}.leaderboard-chart-module_emptyState__0dkfy{color:#666;font-size:14px;font-style:italic;padding:32px 16px;text-align:center}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var deepmerge = require('deepmerge');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Merges chart themes with proper precedence.
|
|
7
|
+
* The second theme (override) takes precedence over the first theme (base).
|
|
8
|
+
*
|
|
9
|
+
* @param baseTheme - Base theme object
|
|
10
|
+
* @param overrideTheme - Theme to override base with (takes precedence)
|
|
11
|
+
* @return Merged theme with overrideTheme values taking precedence
|
|
12
|
+
*/
|
|
13
|
+
function mergeThemes(baseTheme, overrideTheme) {
|
|
14
|
+
// Use deepmerge to properly merge nested objects, with overrideTheme taking precedence
|
|
15
|
+
return deepmerge(baseTheme, overrideTheme, {
|
|
16
|
+
// Ensure arrays are replaced rather than concatenated
|
|
17
|
+
arrayMerge: (_destinationArray, sourceArray) => sourceArray,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
exports.mergeThemes = mergeThemes;
|
|
@@ -4,9 +4,13 @@ import { XYChart, Grid, BarGroup, BarSeries, Axis } from '@visx/xychart';
|
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
import clsx from 'clsx';
|
|
6
6
|
import { useContext, useRef, useState, useCallback, useMemo } from 'react';
|
|
7
|
+
import 'fast-deep-equal';
|
|
8
|
+
import { useGlobalChartTheme } from '../../hooks/use-global-chart-theme.js';
|
|
9
|
+
import '@visx/event';
|
|
10
|
+
import '@visx/tooltip';
|
|
11
|
+
import { useXYChartTheme } from '../../hooks/use-xychart-theme.js';
|
|
7
12
|
import { GlobalChartsContext, GlobalChartsProvider } from '../../providers/chart-context/global-charts-provider.js';
|
|
8
13
|
import { useChartId, useChartRegistration } from '../../providers/chart-context/utils.js';
|
|
9
|
-
import { useChartTheme, useXYChartTheme } from '../../providers/theme/theme-provider.js';
|
|
10
14
|
import { attachSubComponents } from '../../utils/create-composition.js';
|
|
11
15
|
import { Legend } from '../legend/legend.js';
|
|
12
16
|
import '../legend/base-legend.js';
|
|
@@ -38,7 +42,7 @@ const getPatternId = (chartId, index) => `bar-pattern-${chartId}-${index}`;
|
|
|
38
42
|
const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400, className, margin, withTooltips = false, showLegend = false, legendOrientation = 'horizontal', legendPosition = 'bottom', legendAlignment = 'center', legendShape = 'rect', gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = 'vertical', withPatterns = false, showZeroValues = false, children, }) => {
|
|
39
43
|
const horizontal = orientation === 'horizontal';
|
|
40
44
|
const chartId = useChartId(providedChartId);
|
|
41
|
-
const providerTheme =
|
|
45
|
+
const providerTheme = useGlobalChartTheme();
|
|
42
46
|
const theme = useXYChartTheme(data);
|
|
43
47
|
const dataSorted = useChartDataTransform(data);
|
|
44
48
|
// Transform data to add a small value for zero bars to make them visible
|
|
@@ -46,7 +50,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
|
|
|
46
50
|
enabled: showZeroValues,
|
|
47
51
|
});
|
|
48
52
|
// Create legend items using the reusable hook
|
|
49
|
-
const legendItems = useChartLegendData(dataSorted
|
|
53
|
+
const legendItems = useChartLegendData(dataSorted);
|
|
50
54
|
const chartOptions = useBarChartOptions(dataWithVisibleZeros, horizontal, options);
|
|
51
55
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme, horizontal);
|
|
52
56
|
const [legendRef, legendHeight] = useElementHeight();
|
|
@@ -63,7 +67,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
|
|
|
63
67
|
chartRef,
|
|
64
68
|
totalPoints,
|
|
65
69
|
});
|
|
66
|
-
const getColor = useCallback((seriesData, index) => seriesData?.options?.stroke ||
|
|
70
|
+
const getColor = useCallback((seriesData, index) => seriesData?.options?.stroke || providerTheme.colors[index % providerTheme.colors.length], [providerTheme]);
|
|
67
71
|
const getBarBackground = useCallback((index) => () => withPatterns
|
|
68
72
|
? `url(#${getPatternId(chartId, index)})`
|
|
69
73
|
: getColor(dataSorted[index], index), [withPatterns, getColor, dataSorted, chartId]);
|
|
@@ -142,7 +146,13 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
|
|
|
142
146
|
withPatterns,
|
|
143
147
|
}), [orientation, withPatterns]);
|
|
144
148
|
// Register chart with context only if data is valid
|
|
145
|
-
useChartRegistration(
|
|
149
|
+
useChartRegistration({
|
|
150
|
+
chartId,
|
|
151
|
+
legendItems,
|
|
152
|
+
chartType: 'bar',
|
|
153
|
+
isDataValid,
|
|
154
|
+
metadata: chartMetadata,
|
|
155
|
+
});
|
|
146
156
|
if (error) {
|
|
147
157
|
return jsx("div", { className: clsx('bar-chart', styles['bar-chart']), children: error });
|
|
148
158
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
2
2
|
import { __experimentalGrid, __experimentalVStack, __experimentalText, ProgressBar } from '@wordpress/components';
|
|
3
3
|
import { Fragment } from '@wordpress/element';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
import 'react';
|
|
6
|
-
import
|
|
6
|
+
import 'fast-deep-equal';
|
|
7
|
+
import { useGlobalChartTheme } from '../../hooks/use-global-chart-theme.js';
|
|
8
|
+
import '@visx/event';
|
|
9
|
+
import '@visx/tooltip';
|
|
10
|
+
import '@visx/xychart';
|
|
7
11
|
import { formatMetricValue } from '../shared/format-metric-value.js';
|
|
8
12
|
import styles from './leaderboard-chart.module.scss.js';
|
|
9
13
|
|
|
@@ -42,24 +46,27 @@ const defaultDeltaFormatter = (value) => {
|
|
|
42
46
|
signDisplay: 'exceptZero',
|
|
43
47
|
});
|
|
44
48
|
};
|
|
49
|
+
const ProgressBarWithOverlayLabel = ({ entry }) => (jsxs("div", { className: styles.progressContainerWithOverlayLabel, children: [typeof entry.label === 'string' ? (jsx(__experimentalText, { className: styles.progressBarLabel, children: entry.label })) : (entry.label), jsx("div", { className: styles.progressBar, style: { width: entry.currentShare + '%' } })] }));
|
|
50
|
+
const ProgressBarWithLabel = ({ entry, withComparison, }) => (jsxs(Fragment$1, { children: [typeof entry.label === 'string' ? jsx(__experimentalText, { children: entry.label }) : entry.label, jsxs("div", { className: styles.progressContainer, children: [jsx(ProgressBar, { value: entry.currentShare, className: clsx(styles.progressBar, styles.primaryBar) }), withComparison && (jsx(ProgressBar, { value: entry.previousShare, className: clsx(styles.progressBar, styles.secondaryBar) }))] })] }));
|
|
45
51
|
/**
|
|
46
52
|
* LeaderboardChart component displays a ranked list of data with progress bars
|
|
47
53
|
* and optional comparison values.
|
|
48
54
|
*
|
|
49
|
-
* @param props
|
|
50
|
-
* @param props.data
|
|
51
|
-
* @param props.withComparison
|
|
52
|
-
* @param props.
|
|
53
|
-
* @param props.
|
|
54
|
-
* @param props.
|
|
55
|
-
* @param props.
|
|
56
|
-
* @param props.
|
|
57
|
-
* @param props.
|
|
58
|
-
* @param props.
|
|
55
|
+
* @param props - Component props
|
|
56
|
+
* @param props.data - Array of leaderboard entries to display
|
|
57
|
+
* @param props.withComparison - Whether to show comparison data
|
|
58
|
+
* @param props.withOverlayLabel - Whether to overlay the label on top of the bar
|
|
59
|
+
* @param props.primaryColor - Primary color for current period bars
|
|
60
|
+
* @param props.secondaryColor - Secondary color for comparison period bars
|
|
61
|
+
* @param props.valueFormatter - Custom formatter for values
|
|
62
|
+
* @param props.deltaFormatter - Custom formatter for delta values
|
|
63
|
+
* @param props.loading - Whether the chart is in loading state
|
|
64
|
+
* @param props.className - Additional CSS class name
|
|
65
|
+
* @param props.style - Custom styling for the chart container
|
|
59
66
|
* @return JSX element representing the leaderboard chart
|
|
60
67
|
*/
|
|
61
|
-
const LeaderboardChart = ({ data, withComparison = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, loading = false, className, style, }) => {
|
|
62
|
-
const theme =
|
|
68
|
+
const LeaderboardChart = ({ data, withComparison = false, withOverlayLabel = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, loading = false, className, style, }) => {
|
|
69
|
+
const theme = useGlobalChartTheme();
|
|
63
70
|
// Get component settings from theme with fallbacks
|
|
64
71
|
const leaderboardSettings = theme.leaderboardChart;
|
|
65
72
|
const labelSpacing = leaderboardSettings?.labelSpacing ?? DEFAULT_LEADERBOARD_SETTINGS.labelSpacing;
|
|
@@ -84,7 +91,9 @@ const LeaderboardChart = ({ data, withComparison = false, primaryColor, secondar
|
|
|
84
91
|
return (jsx(__experimentalGrid, { className: clsx(styles.leaderboardChart, loading && styles.loading, className), templateColumns: "minmax(0, 1fr) auto", rowGap: rowGap, columnGap: columnGap, style: chartStyle, children: data.map(entry => {
|
|
85
92
|
const colorIndex = Math.sign(entry.delta) + 1;
|
|
86
93
|
const deltaColor = signColors[colorIndex];
|
|
87
|
-
return (jsxs(Fragment, { children: [
|
|
94
|
+
return (jsxs(Fragment, { children: [jsx(__experimentalVStack, { spacing: labelSpacing, children: withOverlayLabel ? (jsx(ProgressBarWithOverlayLabel, { entry: entry })) : (jsx(ProgressBarWithLabel, { entry: entry, withComparison: withComparison })) }), jsxs("div", { className: clsx(styles.valueContainer, {
|
|
95
|
+
[styles.overlayLabel]: withOverlayLabel,
|
|
96
|
+
}), children: [jsx(__experimentalText, { children: valueFormatter(entry.currentValue) }), withComparison && (jsx(__experimentalText, { style: { color: deltaColor }, children: deltaFormatter(entry.delta) }))] })] }, entry.id));
|
|
88
97
|
}) }));
|
|
89
98
|
};
|
|
90
99
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var styles = {"leaderboardChart":"leaderboard-chart-module_leaderboardChart__zxakP","loading":"leaderboard-chart-module_loading__-AGv-","
|
|
1
|
+
var styles = {"leaderboardChart":"leaderboard-chart-module_leaderboardChart__zxakP","loading":"leaderboard-chart-module_loading__-AGv-","progressContainerWithOverlayLabel":"leaderboard-chart-module_progressContainerWithOverlayLabel__YFPY0","progressBar":"leaderboard-chart-module_progressBar__LAQaj","progressBarLabel":"leaderboard-chart-module_progressBarLabel__24t-j","progressContainer":"leaderboard-chart-module_progressContainer__BZGbj","primaryBar":"leaderboard-chart-module_primaryBar__iybII","secondaryBar":"leaderboard-chart-module_secondaryBar__A7tLz","valueContainer":"leaderboard-chart-module_valueContainer__ZlLh4","overlayLabel":"leaderboard-chart-module_overlayLabel__pRqSh","emptyState":"leaderboard-chart-module_emptyState__0dkfy"};
|
|
2
2
|
|
|
3
3
|
export { styles as default };
|
|
@@ -4,7 +4,11 @@ import { LegendOrdinal, LegendItem, LegendShape, LegendLabel } from '@visx/legen
|
|
|
4
4
|
import { scaleOrdinal } from '@visx/scale';
|
|
5
5
|
import clsx from 'clsx';
|
|
6
6
|
import { forwardRef, useCallback } from 'react';
|
|
7
|
-
import
|
|
7
|
+
import 'fast-deep-equal';
|
|
8
|
+
import { useGlobalChartTheme } from '../../hooks/use-global-chart-theme.js';
|
|
9
|
+
import '@visx/event';
|
|
10
|
+
import '@visx/tooltip';
|
|
11
|
+
import '@visx/xychart';
|
|
8
12
|
import styles from './legend.module.scss.js';
|
|
9
13
|
import { valueOrIdentityString, valueOrIdentity, labelTransformFactory } from './utils.js';
|
|
10
14
|
|
|
@@ -18,7 +22,7 @@ const orientationToFlexDirection = {
|
|
|
18
22
|
*/
|
|
19
23
|
const BaseLegend = forwardRef(({ items, className, orientation = 'horizontal', position = 'bottom', alignment = 'center', shape = 'rect', fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform = labelTransformFactory, shapeWidth = 16, shapeHeight = 16, shapeMargin = '2px 4px 2px 0', labelAlign = 'left', labelFlex = '0 0 auto', // Use natural width instead of expanding to fill space
|
|
20
24
|
labelMargin = '0 4px', itemMargin = '0', itemDirection = 'row', legendLabelProps, ...legendItemProps }, ref) => {
|
|
21
|
-
const theme =
|
|
25
|
+
const theme = useGlobalChartTheme();
|
|
22
26
|
const legendScale = scaleOrdinal({
|
|
23
27
|
domain: items.map(item => item.label),
|
|
24
28
|
range: items.map(item => item.color),
|