@mui/x-charts-pro 8.11.2 → 8.11.3

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 (32) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
  3. package/ChartZoomSlider/internals/ChartAxisZoomSliderThumb.js +2 -2
  4. package/FunnelChart/FunnelPlot.js +2 -2
  5. package/FunnelChart/useFunnelChartProps.js +4 -3
  6. package/Heatmap/Heatmap.js +2 -1
  7. package/PieChartPro/PieChartPro.js +1 -0
  8. package/SankeyChart/useSankeyChartProps.js +4 -3
  9. package/esm/ChartDataProviderPro/ChartDataProviderPro.js +1 -1
  10. package/esm/ChartZoomSlider/internals/ChartAxisZoomSliderThumb.js +2 -2
  11. package/esm/FunnelChart/FunnelPlot.js +3 -3
  12. package/esm/FunnelChart/useFunnelChartProps.js +4 -3
  13. package/esm/Heatmap/Heatmap.js +2 -1
  14. package/esm/PieChartPro/PieChartPro.js +1 -0
  15. package/esm/SankeyChart/useSankeyChartProps.js +4 -3
  16. package/esm/index.js +1 -1
  17. package/esm/internals/material/components/BasePopper.js +2 -2
  18. package/esm/internals/plugins/useChartProExport/common.d.ts +5 -1
  19. package/esm/internals/plugins/useChartProExport/common.js +13 -0
  20. package/esm/internals/plugins/useChartProExport/exportImage.d.ts +1 -1
  21. package/esm/internals/plugins/useChartProExport/exportImage.js +23 -17
  22. package/esm/internals/plugins/useChartProExport/print.js +2 -3
  23. package/esm/internals/plugins/useChartProExport/useChartProExport.js +4 -2
  24. package/index.js +1 -1
  25. package/internals/material/components/BasePopper.js +2 -2
  26. package/internals/plugins/useChartProExport/common.d.ts +5 -1
  27. package/internals/plugins/useChartProExport/common.js +14 -0
  28. package/internals/plugins/useChartProExport/exportImage.d.ts +1 -1
  29. package/internals/plugins/useChartProExport/exportImage.js +22 -16
  30. package/internals/plugins/useChartProExport/print.js +2 -3
  31. package/internals/plugins/useChartProExport/useChartProExport.js +4 -2
  32. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -5,6 +5,92 @@
5
5
  All notable changes to this project will be documented in this file.
6
6
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
7
7
 
8
+ ## 8.11.3
9
+
10
+ _Sep 16, 2025_
11
+
12
+ We'd like to extend a big thank you to the 11 contributors who made this release possible. Here are some highlights ✨:
13
+
14
+ - 🐞 Bugfixes
15
+ - 📚 Documentation improvements
16
+
17
+ Special thanks go out to the community members for their valuable contributions:
18
+ @sai6855
19
+
20
+ The following are all team members who have contributed to this release:
21
+ @alexfauquette, @bernardobelchior, @brijeshb42, @cherniavskii, @flaviendelangle, @Janpot, @JCQuintas, @LukasTy, @rita-codes, @siriwatknp
22
+
23
+ ### Data Grid
24
+
25
+ #### `@mui/x-data-grid@8.11.3`
26
+
27
+ - [DataGrid] Fix numeric font size not being applied (#19552) @cherniavskii
28
+ - [DataGrid] Improve `operator` types to display literal values (#19529) @siriwatknp
29
+
30
+ #### `@mui/x-data-grid-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link "Pro plan")
31
+
32
+ Same changes as in `@mui/x-data-grid@8.11.3`.
33
+
34
+ #### `@mui/x-data-grid-premium@8.11.3` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link "Premium plan")
35
+
36
+ Same changes as in `@mui/x-data-grid-pro@8.11.3`.
37
+
38
+ ### Date and Time Pickers
39
+
40
+ #### `@mui/x-date-pickers@8.11.3`
41
+
42
+ - [pickers] Refactor `slots` and `slotProps` propagation strategy (#18867) @LukasTy
43
+
44
+ #### `@mui/x-date-pickers-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link "Pro plan")
45
+
46
+ Same changes as in `@mui/x-date-pickers@8.11.3`.
47
+
48
+ ### Charts
49
+
50
+ #### `@mui/x-charts@8.11.3`
51
+
52
+ - [charts] Add `inline-` piecewise legend options (#19382) @JCQuintas
53
+ - [charts] Add bar gradient example (#19174) @bernardobelchior
54
+ - [charts] Ignore empty tick labels in label overlap computation (#19547) @alexfauquette
55
+ - [charts] Rename `isBandScale` to `isDiscreteScale` (#19514) @bernardobelchior
56
+ - [charts] Fix legend position affecting toolbar's position (#19257) @sai6855
57
+
58
+ #### `@mui/x-charts-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link "Pro plan")
59
+
60
+ Same changes as in `@mui/x-charts@8.11.3`, plus:
61
+
62
+ - [charts-pro] Add chart title and caption to export demo (#19524) @bernardobelchior
63
+
64
+ ### Tree View
65
+
66
+ #### `@mui/x-tree-view@8.11.3`
67
+
68
+ - [tree view] Stop looping through all items to publish the `removeItem` event (#19500) @flaviendelangle
69
+ - [tree view] Support flat DOM structure (#19350) @flaviendelangle
70
+ - [tree view] Update cursor styles for disabled TreeItem (#19548) @sai6855
71
+
72
+ #### `@mui/x-tree-view-pro@8.11.3` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link "Pro plan")
73
+
74
+ Same changes as in `@mui/x-tree-view@8.11.3`.
75
+
76
+ ### Codemod
77
+
78
+ #### `@mui/x-codemod@8.11.3`
79
+
80
+ Internal changes.
81
+
82
+ ### Docs
83
+
84
+ - [docs] Add styling row group recipe (#19349) @siriwatknp
85
+ - [docs] Group demos data into the dataset folder (#19549) @alexfauquette
86
+ - [docs] Add `shiny` bar chart example at the top (#19416) @JCQuintas
87
+
88
+ ### Core
89
+
90
+ - [code-infra] Axios update (#19577) @Janpot
91
+ - [code-infra] Remove usage of copy-files command from code-infra (#19518) @brijeshb42
92
+ - [internal] Fix naming to match convention @oliviertassinari
93
+
8
94
  ## 8.11.2
9
95
 
10
96
  _Sep 10, 2025_
@@ -18,7 +18,7 @@ var _material = require("../internals/material");
18
18
  var _allPlugins = require("../internals/plugins/allPlugins");
19
19
  var _useChartDataProviderProProps = require("./useChartDataProviderProProps");
20
20
  var _jsxRuntime = require("react/jsx-runtime");
21
- const releaseInfo = "MTc1NzQ2MjQwMDAwMA==";
21
+ const releaseInfo = "MTc1ODA2NzIwMDAwMA==";
22
22
  const packageIdentifier = 'x-charts-pro';
23
23
  /**
24
24
  * Orchestrates the data providers for the chart components and hooks.
@@ -45,7 +45,7 @@ const ChartAxisZoomSliderThumb = exports.ChartAxisZoomSliderThumb = /*#__PURE__*
45
45
  rx = 4,
46
46
  ry = 4
47
47
  } = _ref,
48
- rest = (0, _objectWithoutPropertiesLoose2.default)(_ref, _excluded);
48
+ other = (0, _objectWithoutPropertiesLoose2.default)(_ref, _excluded);
49
49
  const classes = (0, _chartAxisZoomSliderThumbClasses.useUtilityClasses)({
50
50
  onMove,
51
51
  orientation,
@@ -87,6 +87,6 @@ const ChartAxisZoomSliderThumb = exports.ChartAxisZoomSliderThumb = /*#__PURE__*
87
87
  ref: ref,
88
88
  rx: rx,
89
89
  ry: ry
90
- }, rest));
90
+ }, other));
91
91
  });
92
92
  if (process.env.NODE_ENV !== "production") ChartAxisZoomSliderThumb.displayName = "ChartAxisZoomSliderThumb";
@@ -57,7 +57,7 @@ const useAggregatedData = () => {
57
57
  const xScale = xAxis[xAxisId].scale;
58
58
  const yScale = yAxis[yAxisId].scale;
59
59
  const xPosition = (value, bandIndex, bandIdentifier, stackOffset, useBand) => {
60
- if ((0, _internals.isBandScale)(xScale)) {
60
+ if ((0, _internals.isOrdinalScale)(xScale)) {
61
61
  const position = xScale(bandIdentifier);
62
62
  return useBand ? position + bandWidth : position;
63
63
  }
@@ -67,7 +67,7 @@ const useAggregatedData = () => {
67
67
  return xScale(value);
68
68
  };
69
69
  const yPosition = (value, bandIndex, bandIdentifier, stackOffset, useBand) => {
70
- if ((0, _internals.isBandScale)(yScale)) {
70
+ if ((0, _internals.isOrdinalScale)(yScale)) {
71
71
  const position = yScale(bandIdentifier);
72
72
  return useBand ? position + bandWidth : position;
73
73
  }
@@ -93,7 +93,7 @@ const useFunnelChartProps = props => {
93
93
  axisHighlight,
94
94
  apiRef
95
95
  } = props,
96
- rest = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
96
+ other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
97
97
  const margin = (0, _internals.defaultizeMargin)(marginProps, _constants.DEFAULT_MARGINS);
98
98
  const isHorizontal = series.some(s => s.layout === 'horizontal');
99
99
  const valueAxisConfig = {
@@ -104,7 +104,7 @@ const useFunnelChartProps = props => {
104
104
  };
105
105
  const xAxis = isHorizontal ? getCategoryAxisConfig(categoryAxis, series, isHorizontal, 'x') : valueAxisConfig;
106
106
  const yAxis = isHorizontal ? valueAxisConfig : getCategoryAxisConfig(categoryAxis, series, isHorizontal, 'y');
107
- const chartContainerProps = (0, _extends2.default)({}, rest, {
107
+ const chartContainerProps = (0, _extends2.default)({}, other, {
108
108
  series: series.map(s => (0, _extends2.default)({
109
109
  type: 'funnel',
110
110
  layout: isHorizontal ? 'horizontal' : 'vertical'
@@ -143,7 +143,8 @@ const useFunnelChartProps = props => {
143
143
  const chartsWrapperProps = {
144
144
  sx,
145
145
  legendPosition: props.slotProps?.legend?.position,
146
- legendDirection: props.slotProps?.legend?.direction
146
+ legendDirection: props.slotProps?.legend?.direction,
147
+ hideLegend: props.hideLegend ?? false
147
148
  };
148
149
  const axisHighlightProps = (0, _extends2.default)({}, axisHighlight);
149
150
  return {
@@ -98,7 +98,8 @@ const Heatmap = exports.Heatmap = /*#__PURE__*/React.forwardRef(function Heatmap
98
98
  const chartsWrapperProps = {
99
99
  sx,
100
100
  legendPosition: props.slotProps?.legend?.position,
101
- legendDirection: props.slotProps?.legend?.direction
101
+ legendDirection: props.slotProps?.legend?.direction,
102
+ hideLegend
102
103
  };
103
104
  const Tooltip = slots?.tooltip ?? _HeatmapTooltip.HeatmapTooltip;
104
105
  const Toolbar = slots?.toolbar ?? _ChartsToolbarPro.ChartsToolbarPro;
@@ -74,6 +74,7 @@ const PieChartPro = exports.PieChartPro = /*#__PURE__*/React.forwardRef(function
74
74
  legendPosition: props.slotProps?.legend?.position,
75
75
  legendDirection: props.slotProps?.legend?.direction ?? 'vertical',
76
76
  sx: sx,
77
+ hideLegend: hideLegend ?? false,
77
78
  children: [showToolbar ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Toolbar, {}) : null, !hideLegend && /*#__PURE__*/(0, _jsxRuntime.jsx)(_ChartsLegend.ChartsLegend, {
78
79
  direction: props.slotProps?.legend?.direction ?? 'vertical',
79
80
  slots: slots,
@@ -37,9 +37,9 @@ const useSankeyChartProps = props => {
37
37
  onNodeClick,
38
38
  onLinkClick
39
39
  } = props,
40
- rest = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
40
+ other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
41
41
  const margin = (0, _internals.defaultizeMargin)(marginProps, _constants.DEFAULT_MARGINS);
42
- const chartContainerProps = (0, _extends2.default)({}, rest, {
42
+ const chartContainerProps = (0, _extends2.default)({}, other, {
43
43
  series: [(0, _extends2.default)({
44
44
  type: 'sankey'
45
45
  }, series)],
@@ -64,7 +64,8 @@ const useSankeyChartProps = props => {
64
64
  loading
65
65
  };
66
66
  const chartsWrapperProps = {
67
- sx
67
+ sx,
68
+ hideLegend: false
68
69
  };
69
70
  return {
70
71
  chartContainerProps,
@@ -11,7 +11,7 @@ import { defaultSlotsMaterial } from "../internals/material/index.js";
11
11
  import { DEFAULT_PLUGINS } from "../internals/plugins/allPlugins.js";
12
12
  import { useChartDataProviderProProps } from "./useChartDataProviderProProps.js";
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- const releaseInfo = "MTc1NzQ2MjQwMDAwMA==";
14
+ const releaseInfo = "MTc1ODA2NzIwMDAwMA==";
15
15
  const packageIdentifier = 'x-charts-pro';
16
16
  /**
17
17
  * Orchestrates the data providers for the chart components and hooks.
@@ -38,7 +38,7 @@ export const ChartAxisZoomSliderThumb = /*#__PURE__*/React.forwardRef(function C
38
38
  rx = 4,
39
39
  ry = 4
40
40
  } = _ref,
41
- rest = _objectWithoutPropertiesLoose(_ref, _excluded);
41
+ other = _objectWithoutPropertiesLoose(_ref, _excluded);
42
42
  const classes = useUtilityClasses({
43
43
  onMove,
44
44
  orientation,
@@ -80,6 +80,6 @@ export const ChartAxisZoomSliderThumb = /*#__PURE__*/React.forwardRef(function C
80
80
  ref: ref,
81
81
  rx: rx,
82
82
  ry: ry
83
- }, rest));
83
+ }, other));
84
84
  });
85
85
  if (process.env.NODE_ENV !== "production") ChartAxisZoomSliderThumb.displayName = "ChartAxisZoomSliderThumb";
@@ -4,7 +4,7 @@ const _excluded = ["onItemClick"];
4
4
  import * as React from 'react';
5
5
  import PropTypes from 'prop-types';
6
6
  import { line as d3Line } from '@mui/x-charts-vendor/d3-shape';
7
- import { cartesianSeriesTypes, useSelector, useStore, isBandScale } from '@mui/x-charts/internals';
7
+ import { cartesianSeriesTypes, useSelector, useStore, isOrdinalScale } from '@mui/x-charts/internals';
8
8
  import { FunnelSection } from "./FunnelSection.js";
9
9
  import { alignLabel, positionLabel } from "./labelUtils.js";
10
10
  import { useFunnelSeriesContext } from "../hooks/useFunnelSeries.js";
@@ -49,7 +49,7 @@ const useAggregatedData = () => {
49
49
  const xScale = xAxis[xAxisId].scale;
50
50
  const yScale = yAxis[yAxisId].scale;
51
51
  const xPosition = (value, bandIndex, bandIdentifier, stackOffset, useBand) => {
52
- if (isBandScale(xScale)) {
52
+ if (isOrdinalScale(xScale)) {
53
53
  const position = xScale(bandIdentifier);
54
54
  return useBand ? position + bandWidth : position;
55
55
  }
@@ -59,7 +59,7 @@ const useAggregatedData = () => {
59
59
  return xScale(value);
60
60
  };
61
61
  const yPosition = (value, bandIndex, bandIdentifier, stackOffset, useBand) => {
62
- if (isBandScale(yScale)) {
62
+ if (isOrdinalScale(yScale)) {
63
63
  const position = yScale(bandIdentifier);
64
64
  return useBand ? position + bandWidth : position;
65
65
  }
@@ -87,7 +87,7 @@ export const useFunnelChartProps = props => {
87
87
  axisHighlight,
88
88
  apiRef
89
89
  } = props,
90
- rest = _objectWithoutPropertiesLoose(props, _excluded);
90
+ other = _objectWithoutPropertiesLoose(props, _excluded);
91
91
  const margin = defaultizeMargin(marginProps, DEFAULT_MARGINS);
92
92
  const isHorizontal = series.some(s => s.layout === 'horizontal');
93
93
  const valueAxisConfig = {
@@ -98,7 +98,7 @@ export const useFunnelChartProps = props => {
98
98
  };
99
99
  const xAxis = isHorizontal ? getCategoryAxisConfig(categoryAxis, series, isHorizontal, 'x') : valueAxisConfig;
100
100
  const yAxis = isHorizontal ? valueAxisConfig : getCategoryAxisConfig(categoryAxis, series, isHorizontal, 'y');
101
- const chartContainerProps = _extends({}, rest, {
101
+ const chartContainerProps = _extends({}, other, {
102
102
  series: series.map(s => _extends({
103
103
  type: 'funnel',
104
104
  layout: isHorizontal ? 'horizontal' : 'vertical'
@@ -137,7 +137,8 @@ export const useFunnelChartProps = props => {
137
137
  const chartsWrapperProps = {
138
138
  sx,
139
139
  legendPosition: props.slotProps?.legend?.position,
140
- legendDirection: props.slotProps?.legend?.direction
140
+ legendDirection: props.slotProps?.legend?.direction,
141
+ hideLegend: props.hideLegend ?? false
141
142
  };
142
143
  const axisHighlightProps = _extends({}, axisHighlight);
143
144
  return {
@@ -91,7 +91,8 @@ const Heatmap = /*#__PURE__*/React.forwardRef(function Heatmap(inProps, ref) {
91
91
  const chartsWrapperProps = {
92
92
  sx,
93
93
  legendPosition: props.slotProps?.legend?.position,
94
- legendDirection: props.slotProps?.legend?.direction
94
+ legendDirection: props.slotProps?.legend?.direction,
95
+ hideLegend
95
96
  };
96
97
  const Tooltip = slots?.tooltip ?? HeatmapTooltip;
97
98
  const Toolbar = slots?.toolbar ?? ChartsToolbarPro;
@@ -66,6 +66,7 @@ const PieChartPro = /*#__PURE__*/React.forwardRef(function PieChartPro(inProps,
66
66
  legendPosition: props.slotProps?.legend?.position,
67
67
  legendDirection: props.slotProps?.legend?.direction ?? 'vertical',
68
68
  sx: sx,
69
+ hideLegend: hideLegend ?? false,
69
70
  children: [showToolbar ? /*#__PURE__*/_jsx(Toolbar, {}) : null, !hideLegend && /*#__PURE__*/_jsx(ChartsLegend, {
70
71
  direction: props.slotProps?.legend?.direction ?? 'vertical',
71
72
  slots: slots,
@@ -31,9 +31,9 @@ export const useSankeyChartProps = props => {
31
31
  onNodeClick,
32
32
  onLinkClick
33
33
  } = props,
34
- rest = _objectWithoutPropertiesLoose(props, _excluded);
34
+ other = _objectWithoutPropertiesLoose(props, _excluded);
35
35
  const margin = defaultizeMargin(marginProps, DEFAULT_MARGINS);
36
- const chartContainerProps = _extends({}, rest, {
36
+ const chartContainerProps = _extends({}, other, {
37
37
  series: [_extends({
38
38
  type: 'sankey'
39
39
  }, series)],
@@ -58,7 +58,8 @@ export const useSankeyChartProps = props => {
58
58
  loading
59
59
  };
60
60
  const chartsWrapperProps = {
61
- sx
61
+ sx,
62
+ hideLegend: false
62
63
  };
63
64
  return {
64
65
  chartContainerProps,
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-charts-pro v8.11.2
2
+ * @mui/x-charts-pro v8.11.3
3
3
  *
4
4
  * @license SEE LICENSE IN LICENSE
5
5
  * This source code is licensed under the SEE LICENSE IN LICENSE license found in the
@@ -54,7 +54,7 @@ export function BasePopper(props) {
54
54
  transition,
55
55
  placement
56
56
  } = props,
57
- rest = _objectWithoutPropertiesLoose(props, _excluded);
57
+ other = _objectWithoutPropertiesLoose(props, _excluded);
58
58
  const modifiers = React.useMemo(() => {
59
59
  const result = [{
60
60
  name: 'preventOverflow',
@@ -116,7 +116,7 @@ export function BasePopper(props) {
116
116
  transition: transition,
117
117
  placement: placement,
118
118
  modifiers: modifiers
119
- }, rest, {
119
+ }, other, {
120
120
  children: content
121
121
  }));
122
122
  }
@@ -1 +1,5 @@
1
- export declare function createExportIframe(title?: string): HTMLIFrameElement;
1
+ export declare function createExportIframe(title?: string): HTMLIFrameElement;
2
+ /**
3
+ * Applies styles to an element and returns the previous styles.
4
+ */
5
+ export declare function applyStyles(element: HTMLElement | SVGElement, styles: Record<string, string | null>): Record<string, string | null>;
@@ -5,4 +5,17 @@ export function createExportIframe(title) {
5
5
  iframeEl.style.height = '0px';
6
6
  iframeEl.title = title || document.title;
7
7
  return iframeEl;
8
+ }
9
+
10
+ /**
11
+ * Applies styles to an element and returns the previous styles.
12
+ */
13
+ export function applyStyles(element, styles) {
14
+ const previousStyles = {};
15
+ Object.entries(styles).forEach(([key, value]) => {
16
+ const prev = element.style.getPropertyValue(key);
17
+ previousStyles[key] = prev;
18
+ element.style.setProperty(key, value);
19
+ });
20
+ return previousStyles;
8
21
  }
@@ -1,3 +1,3 @@
1
1
  import { ChartImageExportOptions } from "./useChartProExport.types.js";
2
2
  export declare const getDrawDocument: () => Promise<typeof import("rasterizehtml").drawDocument>;
3
- export declare function exportImage(element: HTMLElement | SVGElement, params?: ChartImageExportOptions): Promise<void>;
3
+ export declare function exportImage(element: HTMLElement | SVGElement, svg: SVGElement, params?: ChartImageExportOptions): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import ownerDocument from '@mui/utils/ownerDocument';
2
2
  import { loadStyleSheets } from '@mui/x-internals/export';
3
- import { createExportIframe } from "./common.js";
3
+ import { applyStyles, createExportIframe } from "./common.js";
4
4
  import { defaultOnBeforeExport } from "./defaults.js";
5
5
  export const getDrawDocument = async () => {
6
6
  try {
@@ -12,7 +12,7 @@ export const getDrawDocument = async () => {
12
12
  });
13
13
  }
14
14
  };
15
- export async function exportImage(element, params) {
15
+ export async function exportImage(element, svg, params) {
16
16
  const {
17
17
  fileName,
18
18
  type = 'image/png',
@@ -21,18 +21,14 @@ export async function exportImage(element, params) {
21
21
  copyStyles = true
22
22
  } = params ?? {};
23
23
  const drawDocumentPromise = getDrawDocument();
24
- const {
25
- width,
26
- height
27
- } = element.getBoundingClientRect();
28
24
  const doc = ownerDocument(element);
29
- const canvas = document.createElement('canvas');
30
- const ratio = window.devicePixelRatio || 1;
31
- canvas.width = width * ratio;
32
- canvas.height = height * ratio;
33
- canvas.style.width = `${width}px`;
34
- canvas.style.height = `${height}px`;
35
25
  const iframe = createExportIframe(fileName);
26
+ /* We apply the min/max width and height to ensure the SVG doesn't resize in the export.
27
+ * We apply to the original SVG so that the cloned tree will contain the styles and revert these
28
+ * styles changes after the chart is cloned. */
29
+ const previousStyles = applyStyles(svg, {
30
+ width: `${svg.getBoundingClientRect().width}px`
31
+ });
36
32
  let resolve;
37
33
  const iframeLoadPromise = new Promise(res => {
38
34
  resolve = res;
@@ -40,10 +36,12 @@ export async function exportImage(element, params) {
40
36
  iframe.onload = async () => {
41
37
  const exportDoc = iframe.contentDocument;
42
38
  const elementClone = element.cloneNode(true);
43
- const container = document.createElement('div');
44
- container.appendChild(elementClone);
45
- exportDoc.body.innerHTML = container.innerHTML;
39
+ applyStyles(svg, previousStyles);
40
+ exportDoc.body.replaceChildren(elementClone);
46
41
  exportDoc.body.style.margin = '0px';
42
+ /* The body's parent has a width of 0, so we use fit-content to ensure that the body adjusts its width to the width
43
+ * of its children. */
44
+ exportDoc.body.style.width = 'fit-content';
47
45
  const rootCandidate = element.getRootNode();
48
46
  const root = rootCandidate.constructor.name === 'ShadowRoot' ? rootCandidate : doc;
49
47
  if (copyStyles) {
@@ -55,6 +53,15 @@ export async function exportImage(element, params) {
55
53
  await iframeLoadPromise;
56
54
  await onBeforeExport(iframe);
57
55
  const drawDocument = await drawDocumentPromise;
56
+
57
+ /* Use the size from the export body in case `onBeforeExport` adds some elements that should be in the export. */
58
+ const exportDocBodySize = iframe.contentDocument.body.getBoundingClientRect();
59
+ const canvas = document.createElement('canvas');
60
+ const ratio = window.devicePixelRatio || 1;
61
+ canvas.width = exportDocBodySize.width * ratio;
62
+ canvas.height = exportDocBodySize.height * ratio;
63
+ canvas.style.width = `${exportDocBodySize.width}px`;
64
+ canvas.style.height = `${exportDocBodySize.height}px`;
58
65
  try {
59
66
  await drawDocument(iframe.contentDocument, canvas, {
60
67
  // Handle retina displays: https://github.com/cburgmer/rasterizeHTML.js/blob/262b3404d1c469ce4a7750a2976dec09b8ae2d6c/examples/retina.html#L71
@@ -67,9 +74,9 @@ export async function exportImage(element, params) {
67
74
  const blobPromise = new Promise(res => {
68
75
  resolveBlobPromise = res;
69
76
  });
70
- canvas.toBlob(blob => resolveBlobPromise(blob), type, quality);
71
77
  let blob;
72
78
  try {
79
+ canvas.toBlob(b => resolveBlobPromise(b), type, quality);
73
80
  blob = await blobPromise;
74
81
  } catch (error) {
75
82
  throw new Error('MUI X Charts: Failed to create blob from canvas.', {
@@ -78,7 +85,6 @@ export async function exportImage(element, params) {
78
85
  }
79
86
  if (!blob) {
80
87
  throw new Error('MUI X Charts: Failed to create blob from canvas.');
81
- return;
82
88
  }
83
89
  const url = URL.createObjectURL(blob);
84
90
  triggerDownload(url, fileName || document.title);
@@ -12,9 +12,8 @@ export function printChart(element, {
12
12
  printWindow.onload = async () => {
13
13
  const printDoc = printWindow.contentDocument;
14
14
  const elementClone = element.cloneNode(true);
15
- const container = document.createElement('div');
16
- container.appendChild(elementClone);
17
- printDoc.body.innerHTML = container.innerHTML;
15
+ printDoc.body.replaceChildren(elementClone);
16
+ printDoc.body.style.margin = '0px';
18
17
  const rootCandidate = element.getRootNode();
19
18
  const root = rootCandidate.constructor.name === 'ShadowRoot' ? rootCandidate : doc;
20
19
  if (copyStyles) {
@@ -13,6 +13,7 @@ function waitForAnimationFrame() {
13
13
  }
14
14
  export const useChartProExport = ({
15
15
  chartRootRef,
16
+ svgRef,
16
17
  instance
17
18
  }) => {
18
19
  const exportAsPrint = async options => {
@@ -32,12 +33,13 @@ export const useChartProExport = ({
32
33
  };
33
34
  const exportAsImage = async options => {
34
35
  const chartRoot = chartRootRef.current;
35
- if (chartRoot) {
36
+ const svg = svgRef.current;
37
+ if (chartRoot && svg) {
36
38
  const enableAnimation = instance.disableAnimation();
37
39
  try {
38
40
  // Wait for animation frame to ensure the animation finished
39
41
  await waitForAnimationFrame();
40
- await exportImage(chartRoot, options);
42
+ await exportImage(chartRoot, svg, options);
41
43
  } catch (error) {
42
44
  console.error('MUI X Charts: Error exporting chart as image:', error);
43
45
  } finally {
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-charts-pro v8.11.2
2
+ * @mui/x-charts-pro v8.11.3
3
3
  *
4
4
  * @license SEE LICENSE IN LICENSE
5
5
  * This source code is licensed under the SEE LICENSE IN LICENSE license found in the
@@ -62,7 +62,7 @@ function BasePopper(props) {
62
62
  transition,
63
63
  placement
64
64
  } = props,
65
- rest = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
65
+ other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
66
66
  const modifiers = React.useMemo(() => {
67
67
  const result = [{
68
68
  name: 'preventOverflow',
@@ -124,7 +124,7 @@ function BasePopper(props) {
124
124
  transition: transition,
125
125
  placement: placement,
126
126
  modifiers: modifiers
127
- }, rest, {
127
+ }, other, {
128
128
  children: content
129
129
  }));
130
130
  }
@@ -1 +1,5 @@
1
- export declare function createExportIframe(title?: string): HTMLIFrameElement;
1
+ export declare function createExportIframe(title?: string): HTMLIFrameElement;
2
+ /**
3
+ * Applies styles to an element and returns the previous styles.
4
+ */
5
+ export declare function applyStyles(element: HTMLElement | SVGElement, styles: Record<string, string | null>): Record<string, string | null>;
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.applyStyles = applyStyles;
6
7
  exports.createExportIframe = createExportIframe;
7
8
  function createExportIframe(title) {
8
9
  const iframeEl = document.createElement('iframe');
@@ -11,4 +12,17 @@ function createExportIframe(title) {
11
12
  iframeEl.style.height = '0px';
12
13
  iframeEl.title = title || document.title;
13
14
  return iframeEl;
15
+ }
16
+
17
+ /**
18
+ * Applies styles to an element and returns the previous styles.
19
+ */
20
+ function applyStyles(element, styles) {
21
+ const previousStyles = {};
22
+ Object.entries(styles).forEach(([key, value]) => {
23
+ const prev = element.style.getPropertyValue(key);
24
+ previousStyles[key] = prev;
25
+ element.style.setProperty(key, value);
26
+ });
27
+ return previousStyles;
14
28
  }
@@ -1,3 +1,3 @@
1
1
  import { ChartImageExportOptions } from "./useChartProExport.types.js";
2
2
  export declare const getDrawDocument: () => Promise<typeof import("rasterizehtml").drawDocument>;
3
- export declare function exportImage(element: HTMLElement | SVGElement, params?: ChartImageExportOptions): Promise<void>;
3
+ export declare function exportImage(element: HTMLElement | SVGElement, svg: SVGElement, params?: ChartImageExportOptions): Promise<void>;
@@ -22,7 +22,7 @@ const getDrawDocument = async () => {
22
22
  }
23
23
  };
24
24
  exports.getDrawDocument = getDrawDocument;
25
- async function exportImage(element, params) {
25
+ async function exportImage(element, svg, params) {
26
26
  const {
27
27
  fileName,
28
28
  type = 'image/png',
@@ -31,18 +31,14 @@ async function exportImage(element, params) {
31
31
  copyStyles = true
32
32
  } = params ?? {};
33
33
  const drawDocumentPromise = getDrawDocument();
34
- const {
35
- width,
36
- height
37
- } = element.getBoundingClientRect();
38
34
  const doc = (0, _ownerDocument.default)(element);
39
- const canvas = document.createElement('canvas');
40
- const ratio = window.devicePixelRatio || 1;
41
- canvas.width = width * ratio;
42
- canvas.height = height * ratio;
43
- canvas.style.width = `${width}px`;
44
- canvas.style.height = `${height}px`;
45
35
  const iframe = (0, _common.createExportIframe)(fileName);
36
+ /* We apply the min/max width and height to ensure the SVG doesn't resize in the export.
37
+ * We apply to the original SVG so that the cloned tree will contain the styles and revert these
38
+ * styles changes after the chart is cloned. */
39
+ const previousStyles = (0, _common.applyStyles)(svg, {
40
+ width: `${svg.getBoundingClientRect().width}px`
41
+ });
46
42
  let resolve;
47
43
  const iframeLoadPromise = new Promise(res => {
48
44
  resolve = res;
@@ -50,10 +46,12 @@ async function exportImage(element, params) {
50
46
  iframe.onload = async () => {
51
47
  const exportDoc = iframe.contentDocument;
52
48
  const elementClone = element.cloneNode(true);
53
- const container = document.createElement('div');
54
- container.appendChild(elementClone);
55
- exportDoc.body.innerHTML = container.innerHTML;
49
+ (0, _common.applyStyles)(svg, previousStyles);
50
+ exportDoc.body.replaceChildren(elementClone);
56
51
  exportDoc.body.style.margin = '0px';
52
+ /* The body's parent has a width of 0, so we use fit-content to ensure that the body adjusts its width to the width
53
+ * of its children. */
54
+ exportDoc.body.style.width = 'fit-content';
57
55
  const rootCandidate = element.getRootNode();
58
56
  const root = rootCandidate.constructor.name === 'ShadowRoot' ? rootCandidate : doc;
59
57
  if (copyStyles) {
@@ -65,6 +63,15 @@ async function exportImage(element, params) {
65
63
  await iframeLoadPromise;
66
64
  await onBeforeExport(iframe);
67
65
  const drawDocument = await drawDocumentPromise;
66
+
67
+ /* Use the size from the export body in case `onBeforeExport` adds some elements that should be in the export. */
68
+ const exportDocBodySize = iframe.contentDocument.body.getBoundingClientRect();
69
+ const canvas = document.createElement('canvas');
70
+ const ratio = window.devicePixelRatio || 1;
71
+ canvas.width = exportDocBodySize.width * ratio;
72
+ canvas.height = exportDocBodySize.height * ratio;
73
+ canvas.style.width = `${exportDocBodySize.width}px`;
74
+ canvas.style.height = `${exportDocBodySize.height}px`;
68
75
  try {
69
76
  await drawDocument(iframe.contentDocument, canvas, {
70
77
  // Handle retina displays: https://github.com/cburgmer/rasterizeHTML.js/blob/262b3404d1c469ce4a7750a2976dec09b8ae2d6c/examples/retina.html#L71
@@ -77,9 +84,9 @@ async function exportImage(element, params) {
77
84
  const blobPromise = new Promise(res => {
78
85
  resolveBlobPromise = res;
79
86
  });
80
- canvas.toBlob(blob => resolveBlobPromise(blob), type, quality);
81
87
  let blob;
82
88
  try {
89
+ canvas.toBlob(b => resolveBlobPromise(b), type, quality);
83
90
  blob = await blobPromise;
84
91
  } catch (error) {
85
92
  throw new Error('MUI X Charts: Failed to create blob from canvas.', {
@@ -88,7 +95,6 @@ async function exportImage(element, params) {
88
95
  }
89
96
  if (!blob) {
90
97
  throw new Error('MUI X Charts: Failed to create blob from canvas.');
91
- return;
92
98
  }
93
99
  const url = URL.createObjectURL(blob);
94
100
  triggerDownload(url, fileName || document.title);
@@ -19,9 +19,8 @@ function printChart(element, {
19
19
  printWindow.onload = async () => {
20
20
  const printDoc = printWindow.contentDocument;
21
21
  const elementClone = element.cloneNode(true);
22
- const container = document.createElement('div');
23
- container.appendChild(elementClone);
24
- printDoc.body.innerHTML = container.innerHTML;
22
+ printDoc.body.replaceChildren(elementClone);
23
+ printDoc.body.style.margin = '0px';
25
24
  const rootCandidate = element.getRootNode();
26
25
  const root = rootCandidate.constructor.name === 'ShadowRoot' ? rootCandidate : doc;
27
26
  if (copyStyles) {
@@ -20,6 +20,7 @@ function waitForAnimationFrame() {
20
20
  }
21
21
  const useChartProExport = ({
22
22
  chartRootRef,
23
+ svgRef,
23
24
  instance
24
25
  }) => {
25
26
  const exportAsPrint = async options => {
@@ -39,12 +40,13 @@ const useChartProExport = ({
39
40
  };
40
41
  const exportAsImage = async options => {
41
42
  const chartRoot = chartRootRef.current;
42
- if (chartRoot) {
43
+ const svg = svgRef.current;
44
+ if (chartRoot && svg) {
43
45
  const enableAnimation = instance.disableAnimation();
44
46
  try {
45
47
  // Wait for animation frame to ensure the animation finished
46
48
  await waitForAnimationFrame();
47
- await (0, _exportImage.exportImage)(chartRoot, options);
49
+ await (0, _exportImage.exportImage)(chartRoot, svg, options);
48
50
  } catch (error) {
49
51
  console.error('MUI X Charts: Error exporting chart as image:', error);
50
52
  } finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/x-charts-pro",
3
- "version": "8.11.2",
3
+ "version": "8.11.3",
4
4
  "author": "MUI Team",
5
5
  "description": "The Pro plan edition of the MUI X Charts components.",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -31,11 +31,11 @@
31
31
  "@mui/utils": "^7.3.2",
32
32
  "clsx": "^2.1.1",
33
33
  "prop-types": "^15.8.1",
34
- "@mui/x-charts-vendor": "8.11.0",
35
- "@mui/x-internal-gestures": "0.2.5",
36
- "@mui/x-internals": "8.11.2",
37
- "@mui/x-charts": "8.11.2",
38
- "@mui/x-license": "8.11.2"
34
+ "@mui/x-charts": "8.11.3",
35
+ "@mui/x-internal-gestures": "0.2.6",
36
+ "@mui/x-charts-vendor": "8.11.3",
37
+ "@mui/x-internals": "8.11.3",
38
+ "@mui/x-license": "8.11.3"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@emotion/react": "^11.9.0",