@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
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.28.0] - 2025-08-21
|
|
9
|
+
### Added
|
|
10
|
+
- Charts: adds composition legend to pie family charts [#44796]
|
|
11
|
+
- Charts: Add theme to global context and use instead of that from theme provider [#44809]
|
|
12
|
+
|
|
13
|
+
## [0.27.0] - 2025-08-18
|
|
14
|
+
### Added
|
|
15
|
+
- Add support for custom labels in the leaderboard chart for greater flexibility. [#44751]
|
|
16
|
+
|
|
8
17
|
## [0.26.0] - 2025-08-14
|
|
9
18
|
### Added
|
|
10
19
|
- Bar Chart: Add composition API. [#44771]
|
|
@@ -371,6 +380,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
371
380
|
- Fixed lints following ESLint rule changes for TS [#40584]
|
|
372
381
|
- Fixing a bug in Chart storybook data. [#40640]
|
|
373
382
|
|
|
383
|
+
[0.28.0]: https://github.com/Automattic/charts/compare/v0.27.0...v0.28.0
|
|
384
|
+
[0.27.0]: https://github.com/Automattic/charts/compare/v0.26.0...v0.27.0
|
|
374
385
|
[0.26.0]: https://github.com/Automattic/charts/compare/v0.25.0...v0.26.0
|
|
375
386
|
[0.25.0]: https://github.com/Automattic/charts/compare/v0.24.0...v0.25.0
|
|
376
387
|
[0.24.0]: https://github.com/Automattic/charts/compare/v0.23.1...v0.24.0
|
|
@@ -8,9 +8,13 @@ var xychart = require('@visx/xychart');
|
|
|
8
8
|
var i18n = require('@wordpress/i18n');
|
|
9
9
|
var clsx = require('clsx');
|
|
10
10
|
var react = require('react');
|
|
11
|
+
require('fast-deep-equal');
|
|
12
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
13
|
+
require('@visx/event');
|
|
14
|
+
require('@visx/tooltip');
|
|
15
|
+
var useXychartTheme = require('../../hooks/use-xychart-theme.js');
|
|
11
16
|
var globalChartsProvider = require('../../providers/chart-context/global-charts-provider.js');
|
|
12
17
|
var utils = require('../../providers/chart-context/utils.js');
|
|
13
|
-
var themeProvider = require('../../providers/theme/theme-provider.js');
|
|
14
18
|
var createComposition = require('../../utils/create-composition.js');
|
|
15
19
|
var legend = require('../legend/legend.js');
|
|
16
20
|
require('../legend/base-legend.js');
|
|
@@ -42,15 +46,15 @@ const getPatternId = (chartId, index) => `bar-pattern-${chartId}-${index}`;
|
|
|
42
46
|
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, }) => {
|
|
43
47
|
const horizontal = orientation === 'horizontal';
|
|
44
48
|
const chartId = utils.useChartId(providedChartId);
|
|
45
|
-
const providerTheme =
|
|
46
|
-
const theme =
|
|
49
|
+
const providerTheme = useGlobalChartTheme.useGlobalChartTheme();
|
|
50
|
+
const theme = useXychartTheme.useXYChartTheme(data);
|
|
47
51
|
const dataSorted = useChartDataTransform.useChartDataTransform(data);
|
|
48
52
|
// Transform data to add a small value for zero bars to make them visible
|
|
49
53
|
const dataWithVisibleZeros = useZeroValueDisplay.useZeroValueDisplay(dataSorted, {
|
|
50
54
|
enabled: showZeroValues,
|
|
51
55
|
});
|
|
52
56
|
// Create legend items using the reusable hook
|
|
53
|
-
const legendItems = useChartLegendData.useChartLegendData(dataSorted
|
|
57
|
+
const legendItems = useChartLegendData.useChartLegendData(dataSorted);
|
|
54
58
|
const chartOptions = useBarChartOptions.useBarChartOptions(dataWithVisibleZeros, horizontal, options);
|
|
55
59
|
const defaultMargin = useChartMargin.useChartMargin(height, chartOptions, dataSorted, theme, horizontal);
|
|
56
60
|
const [legendRef, legendHeight] = useElementHeight.useElementHeight();
|
|
@@ -67,7 +71,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
|
|
|
67
71
|
chartRef,
|
|
68
72
|
totalPoints,
|
|
69
73
|
});
|
|
70
|
-
const getColor = react.useCallback((seriesData, index) => seriesData?.options?.stroke ||
|
|
74
|
+
const getColor = react.useCallback((seriesData, index) => seriesData?.options?.stroke || providerTheme.colors[index % providerTheme.colors.length], [providerTheme]);
|
|
71
75
|
const getBarBackground = react.useCallback((index) => () => withPatterns
|
|
72
76
|
? `url(#${getPatternId(chartId, index)})`
|
|
73
77
|
: getColor(dataSorted[index], index), [withPatterns, getColor, dataSorted, chartId]);
|
|
@@ -146,7 +150,13 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height = 400,
|
|
|
146
150
|
withPatterns,
|
|
147
151
|
}), [orientation, withPatterns]);
|
|
148
152
|
// Register chart with context only if data is valid
|
|
149
|
-
utils.useChartRegistration(
|
|
153
|
+
utils.useChartRegistration({
|
|
154
|
+
chartId,
|
|
155
|
+
legendItems,
|
|
156
|
+
chartType: 'bar',
|
|
157
|
+
isDataValid,
|
|
158
|
+
metadata: chartMetadata,
|
|
159
|
+
});
|
|
150
160
|
if (error) {
|
|
151
161
|
return jsxRuntime.jsx("div", { className: clsx('bar-chart', barChart_module.default['bar-chart']), children: error });
|
|
152
162
|
}
|
|
@@ -7,7 +7,11 @@ var components = require('@wordpress/components');
|
|
|
7
7
|
var element = require('@wordpress/element');
|
|
8
8
|
var clsx = require('clsx');
|
|
9
9
|
require('react');
|
|
10
|
-
|
|
10
|
+
require('fast-deep-equal');
|
|
11
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
12
|
+
require('@visx/event');
|
|
13
|
+
require('@visx/tooltip');
|
|
14
|
+
require('@visx/xychart');
|
|
11
15
|
var formatMetricValue = require('../shared/format-metric-value.js');
|
|
12
16
|
var leaderboardChart_module = require('./leaderboard-chart.module.scss.js');
|
|
13
17
|
|
|
@@ -46,24 +50,27 @@ const defaultDeltaFormatter = (value) => {
|
|
|
46
50
|
signDisplay: 'exceptZero',
|
|
47
51
|
});
|
|
48
52
|
};
|
|
53
|
+
const ProgressBarWithOverlayLabel = ({ entry }) => (jsxRuntime.jsxs("div", { className: leaderboardChart_module.default.progressContainerWithOverlayLabel, children: [typeof entry.label === 'string' ? (jsxRuntime.jsx(components.__experimentalText, { className: leaderboardChart_module.default.progressBarLabel, children: entry.label })) : (entry.label), jsxRuntime.jsx("div", { className: leaderboardChart_module.default.progressBar, style: { width: entry.currentShare + '%' } })] }));
|
|
54
|
+
const ProgressBarWithLabel = ({ entry, withComparison, }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [typeof entry.label === 'string' ? jsxRuntime.jsx(components.__experimentalText, { children: entry.label }) : entry.label, jsxRuntime.jsxs("div", { className: leaderboardChart_module.default.progressContainer, children: [jsxRuntime.jsx(components.ProgressBar, { value: entry.currentShare, className: clsx(leaderboardChart_module.default.progressBar, leaderboardChart_module.default.primaryBar) }), withComparison && (jsxRuntime.jsx(components.ProgressBar, { value: entry.previousShare, className: clsx(leaderboardChart_module.default.progressBar, leaderboardChart_module.default.secondaryBar) }))] })] }));
|
|
49
55
|
/**
|
|
50
56
|
* LeaderboardChart component displays a ranked list of data with progress bars
|
|
51
57
|
* and optional comparison values.
|
|
52
58
|
*
|
|
53
|
-
* @param props
|
|
54
|
-
* @param props.data
|
|
55
|
-
* @param props.withComparison
|
|
56
|
-
* @param props.
|
|
57
|
-
* @param props.
|
|
58
|
-
* @param props.
|
|
59
|
-
* @param props.
|
|
60
|
-
* @param props.
|
|
61
|
-
* @param props.
|
|
62
|
-
* @param props.
|
|
59
|
+
* @param props - Component props
|
|
60
|
+
* @param props.data - Array of leaderboard entries to display
|
|
61
|
+
* @param props.withComparison - Whether to show comparison data
|
|
62
|
+
* @param props.withOverlayLabel - Whether to overlay the label on top of the bar
|
|
63
|
+
* @param props.primaryColor - Primary color for current period bars
|
|
64
|
+
* @param props.secondaryColor - Secondary color for comparison period bars
|
|
65
|
+
* @param props.valueFormatter - Custom formatter for values
|
|
66
|
+
* @param props.deltaFormatter - Custom formatter for delta values
|
|
67
|
+
* @param props.loading - Whether the chart is in loading state
|
|
68
|
+
* @param props.className - Additional CSS class name
|
|
69
|
+
* @param props.style - Custom styling for the chart container
|
|
63
70
|
* @return JSX element representing the leaderboard chart
|
|
64
71
|
*/
|
|
65
|
-
const LeaderboardChart = ({ data, withComparison = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, loading = false, className, style, }) => {
|
|
66
|
-
const theme =
|
|
72
|
+
const LeaderboardChart = ({ data, withComparison = false, withOverlayLabel = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, loading = false, className, style, }) => {
|
|
73
|
+
const theme = useGlobalChartTheme.useGlobalChartTheme();
|
|
67
74
|
// Get component settings from theme with fallbacks
|
|
68
75
|
const leaderboardSettings = theme.leaderboardChart;
|
|
69
76
|
const labelSpacing = leaderboardSettings?.labelSpacing ?? DEFAULT_LEADERBOARD_SETTINGS.labelSpacing;
|
|
@@ -88,7 +95,9 @@ const LeaderboardChart = ({ data, withComparison = false, primaryColor, secondar
|
|
|
88
95
|
return (jsxRuntime.jsx(components.__experimentalGrid, { className: clsx(leaderboardChart_module.default.leaderboardChart, loading && leaderboardChart_module.default.loading, className), templateColumns: "minmax(0, 1fr) auto", rowGap: rowGap, columnGap: columnGap, style: chartStyle, children: data.map(entry => {
|
|
89
96
|
const colorIndex = Math.sign(entry.delta) + 1;
|
|
90
97
|
const deltaColor = signColors[colorIndex];
|
|
91
|
-
return (jsxRuntime.jsxs(element.Fragment, { children: [jsxRuntime.
|
|
98
|
+
return (jsxRuntime.jsxs(element.Fragment, { children: [jsxRuntime.jsx(components.__experimentalVStack, { spacing: labelSpacing, children: withOverlayLabel ? (jsxRuntime.jsx(ProgressBarWithOverlayLabel, { entry: entry })) : (jsxRuntime.jsx(ProgressBarWithLabel, { entry: entry, withComparison: withComparison })) }), jsxRuntime.jsxs("div", { className: clsx(leaderboardChart_module.default.valueContainer, {
|
|
99
|
+
[leaderboardChart_module.default.overlayLabel]: withOverlayLabel,
|
|
100
|
+
}), children: [jsxRuntime.jsx(components.__experimentalText, { children: valueFormatter(entry.currentValue) }), withComparison && (jsxRuntime.jsx(components.__experimentalText, { style: { color: deltaColor }, children: deltaFormatter(entry.delta) }))] })] }, entry.id));
|
|
92
101
|
}) }));
|
|
93
102
|
};
|
|
94
103
|
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var styles = {"leaderboardChart":"leaderboard-chart-module_leaderboardChart__zxakP","loading":"leaderboard-chart-module_loading__-AGv-","
|
|
5
|
+
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"};
|
|
6
6
|
|
|
7
7
|
exports.default = styles;
|
|
@@ -6,7 +6,11 @@ var legend = require('@visx/legend');
|
|
|
6
6
|
var scale = require('@visx/scale');
|
|
7
7
|
var clsx = require('clsx');
|
|
8
8
|
var react = require('react');
|
|
9
|
-
|
|
9
|
+
require('fast-deep-equal');
|
|
10
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
11
|
+
require('@visx/event');
|
|
12
|
+
require('@visx/tooltip');
|
|
13
|
+
require('@visx/xychart');
|
|
10
14
|
var legend_module = require('./legend.module.scss.js');
|
|
11
15
|
var utils = require('./utils.js');
|
|
12
16
|
|
|
@@ -20,7 +24,7 @@ const orientationToFlexDirection = {
|
|
|
20
24
|
*/
|
|
21
25
|
const BaseLegend = react.forwardRef(({ items, className, orientation = 'horizontal', position = 'bottom', alignment = 'center', shape = 'rect', fill = utils.valueOrIdentityString, size = utils.valueOrIdentityString, labelFormat = utils.valueOrIdentity, labelTransform = utils.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
|
|
22
26
|
labelMargin = '0 4px', itemMargin = '0', itemDirection = 'row', legendLabelProps, ...legendItemProps }, ref) => {
|
|
23
|
-
const theme =
|
|
27
|
+
const theme = useGlobalChartTheme.useGlobalChartTheme();
|
|
24
28
|
const legendScale = scale.scaleOrdinal({
|
|
25
29
|
domain: items.map(item => item.label),
|
|
26
30
|
range: items.map(item => item.color),
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require('@visx/xychart');
|
|
4
4
|
var react = require('react');
|
|
5
|
+
require('fast-deep-equal');
|
|
6
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
7
|
+
require('@visx/event');
|
|
8
|
+
require('@visx/tooltip');
|
|
5
9
|
var getStyles = require('../../utils/get-styles.js');
|
|
6
10
|
|
|
7
11
|
/**
|
|
@@ -92,13 +96,13 @@ function processPointData(pointData, theme, showValues, withGlyph, glyphSize, re
|
|
|
92
96
|
/**
|
|
93
97
|
* Hook to transform chart data into legend items
|
|
94
98
|
* @param data - The chart data to transform
|
|
95
|
-
* @param theme - The chart theme for colors
|
|
96
99
|
* @param options - Configuration options for legend generation
|
|
97
100
|
* @param legendShape - The shape type for legend items (string literal or React component)
|
|
98
101
|
* @return Array of legend items ready for display
|
|
99
102
|
*/
|
|
100
|
-
function useChartLegendData(data,
|
|
103
|
+
function useChartLegendData(data, options = {}, legendShape) {
|
|
101
104
|
const { showValues = false, withGlyph = false, glyphSize = 8, renderGlyph } = options;
|
|
105
|
+
const theme = useGlobalChartTheme.useGlobalChartTheme();
|
|
102
106
|
return react.useMemo(() => {
|
|
103
107
|
if (!data || !Array.isArray(data) || data.length === 0) {
|
|
104
108
|
return [];
|
|
@@ -5,9 +5,12 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var annotation = require('@visx/annotation');
|
|
7
7
|
var xychart = require('@visx/xychart');
|
|
8
|
-
var
|
|
8
|
+
var deepmerge = require('deepmerge');
|
|
9
9
|
var react = require('react');
|
|
10
|
-
|
|
10
|
+
require('fast-deep-equal');
|
|
11
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
12
|
+
require('@visx/event');
|
|
13
|
+
require('@visx/tooltip');
|
|
11
14
|
var utils = require('../shared/utils.js');
|
|
12
15
|
var lineChartAnnotationLabelPopover = require('./line-chart-annotation-label-popover.js');
|
|
13
16
|
|
|
@@ -91,12 +94,12 @@ const getVerticalAnchor = (subjectType, isFlippedVertically, y, yMax, height) =>
|
|
|
91
94
|
return undefined;
|
|
92
95
|
};
|
|
93
96
|
const LineChartAnnotation = ({ datum, title, subtitle, subjectType = 'circle', styles: datumStyles, testId, renderLabel, renderLabelPopover, }) => {
|
|
94
|
-
const providerTheme =
|
|
97
|
+
const providerTheme = useGlobalChartTheme.useGlobalChartTheme();
|
|
95
98
|
const { xScale, yScale } = react.useContext(xychart.DataContext) || {};
|
|
96
99
|
const labelRef = react.useRef(null);
|
|
97
100
|
const [height, setHeight] = react.useState(null);
|
|
98
101
|
// Deep merge styles to preserve nested object properties
|
|
99
|
-
const styles =
|
|
102
|
+
const styles = deepmerge(providerTheme.annotationStyles ?? {}, datumStyles ?? {});
|
|
100
103
|
// Measure the label height once after initial render
|
|
101
104
|
react.useEffect(() => {
|
|
102
105
|
if (labelRef.current?.getBBox) {
|
|
@@ -10,9 +10,13 @@ var gradient = require('@visx/gradient');
|
|
|
10
10
|
var xychart = require('@visx/xychart');
|
|
11
11
|
var i18n = require('@wordpress/i18n');
|
|
12
12
|
var clsx = require('clsx');
|
|
13
|
+
require('fast-deep-equal');
|
|
14
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
15
|
+
require('@visx/event');
|
|
16
|
+
require('@visx/tooltip');
|
|
17
|
+
var useXychartTheme = require('../../hooks/use-xychart-theme.js');
|
|
13
18
|
var globalChartsProvider = require('../../providers/chart-context/global-charts-provider.js');
|
|
14
19
|
var utils = require('../../providers/chart-context/utils.js');
|
|
15
|
-
var themeProvider = require('../../providers/theme/theme-provider.js');
|
|
16
20
|
var createComposition = require('../../utils/create-composition.js');
|
|
17
21
|
var getStyles = require('../../utils/get-styles.js');
|
|
18
22
|
var legend = require('../legend/legend.js');
|
|
@@ -137,8 +141,8 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
137
141
|
return null; // This component only provides the ref interface
|
|
138
142
|
};
|
|
139
143
|
const LineChartInternal = react.forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legendOrientation = 'horizontal', legendAlignment = 'center', legendPosition = 'bottom', renderGlyph = defaultRenderGlyph, glyphStyle = {}, legendShape = 'line', withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, options = {}, onPointerDown = undefined, onPointerUp = undefined, onPointerMove = undefined, onPointerOut = undefined, children, }, ref) => {
|
|
140
|
-
const providerTheme =
|
|
141
|
-
const theme =
|
|
144
|
+
const providerTheme = useGlobalChartTheme.useGlobalChartTheme();
|
|
145
|
+
const theme = useXychartTheme.useXYChartTheme(data);
|
|
142
146
|
const chartId = utils.useChartId(providedChartId);
|
|
143
147
|
const [legendRef, legendHeight] = useElementHeight.useElementHeight();
|
|
144
148
|
const chartRef = react.useRef(null);
|
|
@@ -206,7 +210,7 @@ const LineChartInternal = react.forwardRef(({ data, chartId: providedChartId, wi
|
|
|
206
210
|
renderGlyph,
|
|
207
211
|
}), [withLegendGlyph, glyphStyle?.radius, renderGlyph]);
|
|
208
212
|
// Create legend items using the reusable hook
|
|
209
|
-
const legendItems = useChartLegendData.useChartLegendData(dataSorted,
|
|
213
|
+
const legendItems = useChartLegendData.useChartLegendData(dataSorted, legendOptions, legendShape);
|
|
210
214
|
// Memoize metadata to prevent unnecessary re-registration
|
|
211
215
|
const chartMetadata = react.useMemo(() => ({
|
|
212
216
|
withGradientFill,
|
|
@@ -216,7 +220,13 @@ const LineChartInternal = react.forwardRef(({ data, chartId: providedChartId, wi
|
|
|
216
220
|
withLegendGlyph,
|
|
217
221
|
}), [withGradientFill, smoothing, curveType, withStartGlyphs, withLegendGlyph]);
|
|
218
222
|
// Register chart with context only if data is valid
|
|
219
|
-
utils.useChartRegistration(
|
|
223
|
+
utils.useChartRegistration({
|
|
224
|
+
chartId,
|
|
225
|
+
legendItems,
|
|
226
|
+
chartType: 'line',
|
|
227
|
+
isDataValid,
|
|
228
|
+
metadata: chartMetadata,
|
|
229
|
+
});
|
|
220
230
|
const accessors = {
|
|
221
231
|
xAccessor: (d) => d?.date,
|
|
222
232
|
yAccessor: (d) => d?.value,
|
|
@@ -250,7 +260,7 @@ const LineChartInternal = react.forwardRef(({ data, chartId: providedChartId, wi
|
|
|
250
260
|
stroke,
|
|
251
261
|
...lineStyles,
|
|
252
262
|
};
|
|
253
|
-
return (jsxRuntime.jsxs("g", { children: [withStartGlyphs && (jsxRuntime.jsx(StartGlyph, { index: index, data: seriesData, color: stroke, renderGlyph: providerTheme.glyphs?.[index] ?? renderGlyph, accessors: accessors, glyphStyle: glyphStyle })), withGradientFill && (jsxRuntime.jsx(gradient.LinearGradient, { id: `area-gradient-${chartId}-${index + 1}`, from: stroke, fromOpacity: 0.4, toOpacity: 0.1, to:
|
|
263
|
+
return (jsxRuntime.jsxs("g", { children: [withStartGlyphs && (jsxRuntime.jsx(StartGlyph, { index: index, data: seriesData, color: stroke, renderGlyph: providerTheme.glyphs?.[index] ?? renderGlyph, accessors: accessors, glyphStyle: glyphStyle })), withGradientFill && (jsxRuntime.jsx(gradient.LinearGradient, { id: `area-gradient-${chartId}-${index + 1}`, from: stroke, fromOpacity: 0.4, toOpacity: 0.1, to: providerTheme.backgroundColor, ...seriesData.options?.gradient, "data-testid": "line-gradient" })), jsxRuntime.jsx(xychart.AreaSeries, { dataKey: seriesData?.label, data: seriesData.data, ...accessors, fill: withGradientFill
|
|
254
264
|
? `url(#area-gradient-${chartId}-${index + 1})`
|
|
255
265
|
: 'transparent', renderLine: true, curve: getCurveType(curveType, smoothing), lineProps: lineProps }, seriesData?.label)] }, seriesData?.label || index));
|
|
256
266
|
}), withTooltips && (jsxRuntime.jsx(accessibleTooltip.AccessibleTooltip, { detectBounds: true, snapTooltipToDatumX: true, snapTooltipToDatumY: true, showSeriesGlyphs: true, renderTooltip: renderTooltip, renderGlyph: tooltipRenderGlyph, glyphStyle: glyphStyle, showVerticalCrosshair: withTooltipCrosshairs?.showVertical, showHorizontalCrosshair: withTooltipCrosshairs?.showHorizontal, selectedIndex: selectedIndex, tooltipRef: tooltipRef, keyboardFocusedClassName: lineChart_module.default['line-chart__tooltip--keyboard-focused'], series: dataSorted })), jsxRuntime.jsx(LineChartScalesRef, { chartRef: internalChartRef, width: width, height: height, margin: margin })] }) }), showLegend && (jsxRuntime.jsx(legend.Legend, { items: legendItems, orientation: legendOrientation, alignment: legendAlignment, position: legendPosition, className: lineChart_module.default['line-chart-legend'], shape: legendShape, chartId: chartId, ref: legendRef })), children] }) }));
|
|
@@ -7,14 +7,17 @@ var group = require('@visx/group');
|
|
|
7
7
|
var shape = require('@visx/shape');
|
|
8
8
|
var clsx = require('clsx');
|
|
9
9
|
var react = require('react');
|
|
10
|
+
require('fast-deep-equal');
|
|
11
|
+
var useGlobalChartTheme = require('../../hooks/use-global-chart-theme.js');
|
|
10
12
|
var useChartMouseHandler = require('../../hooks/use-chart-mouse-handler.js');
|
|
13
|
+
require('@visx/xychart');
|
|
11
14
|
var globalChartsProvider = require('../../providers/chart-context/global-charts-provider.js');
|
|
12
15
|
var utils = require('../../providers/chart-context/utils.js');
|
|
13
|
-
var
|
|
14
|
-
var themes = require('../../providers/theme/themes.js');
|
|
16
|
+
var createComposition = require('../../utils/create-composition.js');
|
|
15
17
|
var legend = require('../legend/legend.js');
|
|
16
18
|
require('../legend/base-legend.js');
|
|
17
19
|
var useChartLegendData = require('../legend/use-chart-legend-data.js');
|
|
20
|
+
var singleChartContext = require('../shared/single-chart-context.js');
|
|
18
21
|
var useElementHeight = require('../shared/use-element-height.js');
|
|
19
22
|
var withResponsive = require('../shared/with-responsive.js');
|
|
20
23
|
var baseTooltip = require('../tooltip/base-tooltip.js');
|
|
@@ -42,6 +45,32 @@ const validateData = (data) => {
|
|
|
42
45
|
}
|
|
43
46
|
return { isValid: true, message: '' };
|
|
44
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Compound component for SVG children in the PieChart
|
|
50
|
+
* @param {PropsWithChildren} props - Component props
|
|
51
|
+
* @param {ReactNode} props.children - Child elements to render
|
|
52
|
+
* @return {JSX.Element} The children wrapped in a fragment
|
|
53
|
+
*/
|
|
54
|
+
const PieChartSVG = ({ children }) => {
|
|
55
|
+
// This component doesn't render directly - its children are extracted by PieChart
|
|
56
|
+
// We just return the children as-is
|
|
57
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
|
|
58
|
+
};
|
|
59
|
+
// Set displayName for better debugging and type checking
|
|
60
|
+
PieChartSVG.displayName = 'PieChart.SVG';
|
|
61
|
+
/**
|
|
62
|
+
* Compound component for HTML children in the PieChart
|
|
63
|
+
* @param {PropsWithChildren} props - Component props
|
|
64
|
+
* @param {ReactNode} props.children - Child elements to render
|
|
65
|
+
* @return {JSX.Element} The children wrapped in a fragment
|
|
66
|
+
*/
|
|
67
|
+
const PieChartHTML = ({ children }) => {
|
|
68
|
+
// This component doesn't render directly - its children are extracted by PieChart
|
|
69
|
+
// We just return the children as-is
|
|
70
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
|
|
71
|
+
};
|
|
72
|
+
// Set displayName for better debugging and type checking
|
|
73
|
+
PieChartHTML.displayName = 'PieChart.HTML';
|
|
45
74
|
/**
|
|
46
75
|
* Renders a pie or donut chart using the provided data.
|
|
47
76
|
*
|
|
@@ -49,17 +78,50 @@ const validateData = (data) => {
|
|
|
49
78
|
* @return {JSX.Element} The rendered chart component
|
|
50
79
|
*/
|
|
51
80
|
const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legendOrientation = 'horizontal', legendPosition = 'bottom', legendAlignment = 'center', legendShape = 'circle', size, thickness = 1, padding = 20, gapScale = 0, cornerScale = 0, children = null, }) => {
|
|
52
|
-
const providerTheme =
|
|
81
|
+
const providerTheme = useGlobalChartTheme.useGlobalChartTheme();
|
|
53
82
|
const chartId = utils.useChartId(providedChartId);
|
|
54
83
|
const [legendRef, legendHeight] = useElementHeight.useElementHeight();
|
|
55
|
-
const { onMouseMove, onMouseLeave, tooltipOpen, tooltipData, tooltipLeft, tooltipTop } = useChartMouseHandler.
|
|
84
|
+
const { onMouseMove, onMouseLeave, tooltipOpen, tooltipData, tooltipLeft, tooltipTop } = useChartMouseHandler.useChartMouseHandler({
|
|
56
85
|
withTooltips,
|
|
57
86
|
});
|
|
58
87
|
// Memoize legend options to prevent unnecessary re-calculations
|
|
59
88
|
const legendOptions = react.useMemo(() => ({ showValues: true }), []);
|
|
60
89
|
// Create legend items using the reusable hook
|
|
61
|
-
const legendItems = useChartLegendData.useChartLegendData(data,
|
|
90
|
+
const legendItems = useChartLegendData.useChartLegendData(data, legendOptions);
|
|
62
91
|
const { isValid, message } = validateData(data);
|
|
92
|
+
// Process children to extract compound components
|
|
93
|
+
const { svgChildren, htmlChildren, otherChildren } = react.useMemo(() => {
|
|
94
|
+
const svg = [];
|
|
95
|
+
const html = [];
|
|
96
|
+
const other = [];
|
|
97
|
+
react.Children.forEach(children, child => {
|
|
98
|
+
if (react.isValidElement(child)) {
|
|
99
|
+
// Check displayName for compound components
|
|
100
|
+
const childType = child.type;
|
|
101
|
+
const displayName = childType?.displayName;
|
|
102
|
+
if (displayName === 'PieChart.SVG') {
|
|
103
|
+
// Extract children from PieChart.SVG
|
|
104
|
+
react.Children.forEach(child.props.children, svgChild => {
|
|
105
|
+
svg.push(svgChild);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
else if (displayName === 'PieChart.HTML') {
|
|
109
|
+
// Extract children from PieChart.HTML
|
|
110
|
+
react.Children.forEach(child.props.children, htmlChild => {
|
|
111
|
+
html.push(htmlChild);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else if (child.type === group.Group) {
|
|
115
|
+
// Legacy support: still check for Group type for backward compatibility
|
|
116
|
+
svg.push(child);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
other.push(child);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
return { svgChildren: svg, htmlChildren: html, otherChildren: other };
|
|
124
|
+
}, [children]);
|
|
63
125
|
// Memoize metadata to prevent unnecessary re-registration
|
|
64
126
|
const chartMetadata = react.useMemo(() => ({
|
|
65
127
|
thickness,
|
|
@@ -67,7 +129,13 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
67
129
|
cornerScale,
|
|
68
130
|
}), [thickness, gapScale, cornerScale]);
|
|
69
131
|
// Register chart with context only if data is valid
|
|
70
|
-
utils.useChartRegistration(
|
|
132
|
+
utils.useChartRegistration({
|
|
133
|
+
chartId,
|
|
134
|
+
legendItems,
|
|
135
|
+
chartType: 'pie',
|
|
136
|
+
isDataValid: isValid,
|
|
137
|
+
metadata: chartMetadata,
|
|
138
|
+
});
|
|
71
139
|
if (!isValid) {
|
|
72
140
|
return (jsxRuntime.jsx("div", { className: clsx('pie-chart', pieChart_module.default['pie-chart'], className), children: jsxRuntime.jsx("div", { className: pieChart_module.default['error-message'], children: message }) }));
|
|
73
141
|
}
|
|
@@ -95,29 +163,33 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
95
163
|
// Use the color property from the data object as a last resort. The theme provides colours by default.
|
|
96
164
|
fill: (d) => d?.color || providerTheme.colors[d.index],
|
|
97
165
|
};
|
|
98
|
-
return (jsxRuntime.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
166
|
+
return (jsxRuntime.jsx(singleChartContext.SingleChartContext.Provider, { value: {
|
|
167
|
+
chartId,
|
|
168
|
+
chartWidth: size,
|
|
169
|
+
chartHeight: adjustedHeight,
|
|
170
|
+
}, children: jsxRuntime.jsxs("div", { className: clsx('pie-chart', pieChart_module.default['pie-chart'], className), style: {
|
|
171
|
+
display: 'flex',
|
|
172
|
+
flexDirection: showLegend && legendPosition === 'top' ? 'column-reverse' : 'column',
|
|
173
|
+
}, children: [jsxRuntime.jsx("svg", { viewBox: `0 0 ${size} ${adjustedHeight}`, preserveAspectRatio: "xMidYMid meet", width: size, height: adjustedHeight, children: jsxRuntime.jsxs(group.Group, { top: centerY, left: centerX, children: [jsxRuntime.jsx(shape.Pie, { data: dataWithIndex, pieValue: accessors.value, outerRadius: outerRadius, innerRadius: innerRadius, padAngle: padAngle, cornerRadius: cornerRadius, children: pie => {
|
|
174
|
+
return pie.arcs.map((arc, index) => {
|
|
175
|
+
const [centroidX, centroidY] = pie.path.centroid(arc);
|
|
176
|
+
const hasSpaceForLabel = arc.endAngle - arc.startAngle >= 0.25;
|
|
177
|
+
const handleMouseMove = (event) => onMouseMove(event, arc.data);
|
|
178
|
+
const pathProps = {
|
|
179
|
+
d: pie.path(arc) || '',
|
|
180
|
+
fill: accessors.fill(arc.data),
|
|
181
|
+
};
|
|
182
|
+
if (withTooltips) {
|
|
183
|
+
pathProps.onMouseMove = handleMouseMove;
|
|
184
|
+
pathProps.onMouseLeave = onMouseLeave;
|
|
185
|
+
}
|
|
186
|
+
return (jsxRuntime.jsxs("g", { children: [jsxRuntime.jsx("path", { ...pathProps }), hasSpaceForLabel && (jsxRuntime.jsx("text", { x: centroidX, y: centroidY, dy: ".33em", fill: providerTheme.labelBackgroundColor || '#333', fontSize: 12, textAnchor: "middle", pointerEvents: "none", children: arc.data.label }))] }, `arc-${index}`));
|
|
187
|
+
});
|
|
188
|
+
} }), svgChildren] }) }), showLegend && (jsxRuntime.jsx(legend.Legend, { items: legendItems, orientation: legendOrientation, position: legendPosition, alignment: legendAlignment, className: pieChart_module.default['pie-chart-legend'], shape: legendShape, ref: legendRef, chartId: chartId })), withTooltips && tooltipOpen && tooltipData && (jsxRuntime.jsx(baseTooltip.BaseTooltip, { data: tooltipData, top: tooltipTop || 0, left: tooltipLeft || 0, style: {
|
|
189
|
+
transform: 'translate(-50%, -100%)',
|
|
190
|
+
} })), htmlChildren, otherChildren] }) }));
|
|
119
191
|
};
|
|
120
|
-
const
|
|
192
|
+
const PieChartWithProvider = props => {
|
|
121
193
|
const existingContext = react.useContext(globalChartsProvider.GlobalChartsContext);
|
|
122
194
|
// If we're already in a GlobalChartsProvider context, don't create a new one
|
|
123
195
|
if (existingContext) {
|
|
@@ -126,7 +198,19 @@ const PieChart = (props) => {
|
|
|
126
198
|
// Otherwise, create our own GlobalChartsProvider
|
|
127
199
|
return (jsxRuntime.jsx(globalChartsProvider.GlobalChartsProvider, { children: jsxRuntime.jsx(PieChartInternal, { ...props }) }));
|
|
128
200
|
};
|
|
129
|
-
|
|
130
|
-
|
|
201
|
+
PieChartWithProvider.displayName = 'PieChart';
|
|
202
|
+
// Create PieChart with composition API
|
|
203
|
+
const PieChart = createComposition.attachSubComponents(PieChartWithProvider, {
|
|
204
|
+
Legend: legend.Legend,
|
|
205
|
+
SVG: PieChartSVG,
|
|
206
|
+
HTML: PieChartHTML,
|
|
207
|
+
});
|
|
208
|
+
// Create responsive PieChart with composition API
|
|
209
|
+
const PieChartResponsive = createComposition.attachSubComponents(withResponsive.withResponsive(PieChartWithProvider), {
|
|
210
|
+
Legend: legend.Legend,
|
|
211
|
+
SVG: PieChartSVG,
|
|
212
|
+
HTML: PieChartHTML,
|
|
213
|
+
});
|
|
131
214
|
|
|
132
|
-
exports.
|
|
215
|
+
exports.PieChartUnresponsive = PieChart;
|
|
216
|
+
exports.default = PieChartResponsive;
|