@mui/x-charts-pro 9.3.0 → 9.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/BarChartPro/BarChartPro.js +32 -2
  2. package/BarChartPro/BarChartPro.mjs +32 -2
  3. package/CHANGELOG.md +196 -0
  4. package/ChartsDataProviderPro/ChartsDataProviderPro.js +2 -2
  5. package/ChartsDataProviderPro/ChartsDataProviderPro.mjs +2 -2
  6. package/ChartsToolbarPro/ChartsToolbarImageExportTrigger.js +1 -0
  7. package/ChartsToolbarPro/ChartsToolbarImageExportTrigger.mjs +1 -0
  8. package/ChartsToolbarPro/ChartsToolbarPro.d.mts +1 -1
  9. package/ChartsToolbarPro/ChartsToolbarPro.d.ts +1 -1
  10. package/ChartsToolbarPro/ChartsToolbarRangeButtonTrigger.d.mts +1 -1
  11. package/ChartsToolbarPro/ChartsToolbarRangeButtonTrigger.d.ts +1 -1
  12. package/ChartsToolbarPro/ChartsToolbarRangeButtonTrigger.js +35 -38
  13. package/ChartsToolbarPro/ChartsToolbarRangeButtonTrigger.mjs +37 -40
  14. package/ChartsToolbarPro/Toolbar.types.d.mts +3 -2
  15. package/ChartsToolbarPro/Toolbar.types.d.ts +3 -2
  16. package/ChartsToolbarPro/rangeButtonValueToZoom.d.mts +18 -2
  17. package/ChartsToolbarPro/rangeButtonValueToZoom.d.ts +18 -2
  18. package/ChartsToolbarPro/rangeButtonValueToZoom.js +73 -10
  19. package/ChartsToolbarPro/rangeButtonValueToZoom.mjs +72 -10
  20. package/ChartsZoomSlider/internals/chartsAxisZoomSliderThumbClasses.js +9 -2
  21. package/ChartsZoomSlider/internals/chartsAxisZoomSliderThumbClasses.mjs +9 -2
  22. package/ChartsZoomSlider/internals/previews/ScatterPreviewPlot.js +2 -1
  23. package/ChartsZoomSlider/internals/previews/ScatterPreviewPlot.mjs +2 -1
  24. package/FunnelChart/funnelPlotSlots.types.d.mts +5 -4
  25. package/FunnelChart/funnelPlotSlots.types.d.ts +5 -4
  26. package/Heatmap/Heatmap.d.mts +3 -2
  27. package/Heatmap/Heatmap.d.ts +3 -2
  28. package/Heatmap/Heatmap.js +32 -2
  29. package/Heatmap/Heatmap.mjs +32 -2
  30. package/Heatmap/HeatmapItem.d.mts +3 -2
  31. package/Heatmap/HeatmapItem.d.ts +3 -2
  32. package/Heatmap/HeatmapItem.js +2 -0
  33. package/Heatmap/HeatmapItem.mjs +2 -0
  34. package/Heatmap/HeatmapTooltip/HeatmapTooltip.types.d.mts +3 -2
  35. package/Heatmap/HeatmapTooltip/HeatmapTooltip.types.d.ts +3 -2
  36. package/LineChartPro/LineChartPro.js +32 -2
  37. package/LineChartPro/LineChartPro.mjs +32 -2
  38. package/ScatterChartPro/ScatterChartPro.d.mts +2 -1
  39. package/ScatterChartPro/ScatterChartPro.d.ts +2 -1
  40. package/ScatterChartPro/ScatterChartPro.js +32 -2
  41. package/ScatterChartPro/ScatterChartPro.mjs +32 -2
  42. package/index.js +1 -1
  43. package/index.mjs +1 -1
  44. package/internals/plugins/useChartProExport/exportImage.js +8 -2
  45. package/internals/plugins/useChartProExport/exportImage.mjs +8 -2
  46. package/internals/plugins/useChartProExport/print.js +1 -0
  47. package/internals/plugins/useChartProExport/print.mjs +1 -0
  48. package/internals/plugins/useChartProExport/useChartProExport.types.d.mts +6 -0
  49. package/internals/plugins/useChartProExport/useChartProExport.types.d.ts +6 -0
  50. package/internals/plugins/useChartProZoom/useChartProZoom.js +77 -14
  51. package/internals/plugins/useChartProZoom/useChartProZoom.mjs +79 -15
  52. package/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.mts +0 -3
  53. package/internals/plugins/useChartProZoom/useChartProZoom.selectors.d.ts +0 -3
  54. package/internals/plugins/useChartProZoom/useChartProZoom.selectors.js +1 -2
  55. package/internals/plugins/useChartProZoom/useChartProZoom.selectors.mjs +0 -1
  56. package/internals/plugins/useChartProZoom/useChartProZoom.types.d.mts +28 -11
  57. package/internals/plugins/useChartProZoom/useChartProZoom.types.d.ts +28 -11
  58. package/internals/slots/chartsBaseSlots.d.mts +6 -5
  59. package/internals/slots/chartsBaseSlots.d.ts +6 -5
  60. package/internals/slots/chartsIconSlots.d.mts +4 -3
  61. package/internals/slots/chartsIconSlots.d.ts +4 -3
  62. package/models/chartsSlotsComponentsPropsPro.d.mts +11 -0
  63. package/models/chartsSlotsComponentsPropsPro.d.ts +11 -0
  64. package/models/chartsSlotsComponentsPropsPro.js +5 -0
  65. package/models/chartsSlotsComponentsPropsPro.mjs +1 -0
  66. package/models/index.d.mts +1 -0
  67. package/models/index.d.ts +1 -0
  68. package/models/index.js +12 -0
  69. package/models/index.mjs +1 -0
  70. package/package.json +6 -6
@@ -1,15 +1,16 @@
1
1
  import type * as React from 'react';
2
+ import type { ToolbarPropsOverrides } from '@mui/x-charts/models';
2
3
  import { type ChartsToolbarProProps } from "./ChartsToolbarPro.js";
3
4
  export interface ChartsToolbarProSlots {
4
5
  /**
5
6
  * Custom component for the toolbar.
6
7
  * @default ChartsToolbar
7
8
  */
8
- toolbar?: React.ElementType<ChartsToolbarProProps>;
9
+ toolbar?: React.ElementType<ChartsToolbarProProps & ToolbarPropsOverrides>;
9
10
  }
10
11
  export interface ChartsToolbarProSlotProps {
11
12
  /**
12
13
  * Props for the toolbar component.
13
14
  */
14
- toolbar?: Partial<ChartsToolbarProProps>;
15
+ toolbar?: Partial<ChartsToolbarProProps> & ToolbarPropsOverrides;
15
16
  }
@@ -31,6 +31,8 @@ export interface RangeButtonFunctionParams {
31
31
  * @example { unit: 'year' } // Last year (step defaults to 1)
32
32
  * - `[start, end]` — An absolute date range.
33
33
  * @example [new Date(2024, 0, 1), new Date(2024, 6, 1)] // Jan–Jul 2024
34
+ * - `[start, end]` of strings — A range between two axis values, for ordinal (band/point) axes.
35
+ * @example ['Feb', 'May'] // From the 'Feb' category to the 'May' category
34
36
  * - `(params) => { start, end }` — A function that receives axis context (`scaleType`, `data`, `domain`) and returns zoom percentages (0-100).
35
37
  * @example ({ domain }) => ({ start: 0, end: 50 }) // First half of data
36
38
  * @example ({ data }) => {
@@ -43,7 +45,7 @@ export interface RangeButtonFunctionParams {
43
45
  export type RangeButtonValue = {
44
46
  unit: RangeButtonIntervalUnit;
45
47
  step?: number;
46
- } | [Date, Date] | ((params: RangeButtonFunctionParams) => {
48
+ } | [Date, Date] | [string, string] | ((params: RangeButtonFunctionParams) => {
47
49
  start: number;
48
50
  end: number;
49
51
  }) | null;
@@ -63,4 +65,18 @@ export type RangeButtonValue = {
63
65
  export declare function rangeButtonValueToZoom(value: RangeButtonValue, params: RangeButtonFunctionParams): {
64
66
  start: number;
65
67
  end: number;
66
- };
68
+ };
69
+ /**
70
+ * Builds the {@link RangeButtonFunctionParams} for an axis from its computed domain.
71
+ *
72
+ * For ordinal (band/point) axes the domain is index-based; for continuous axes it
73
+ * uses the first and last domain values.
74
+ *
75
+ * @param axis The axis scale type and data.
76
+ * @param domain The computed domain values of the axis.
77
+ * @returns The params to pass to {@link rangeButtonValueToZoom}, or `undefined` if the domain is too small to zoom.
78
+ */
79
+ export declare function getRangeButtonDomainParams(axis: {
80
+ scaleType?: string;
81
+ data?: readonly unknown[];
82
+ }, domain: readonly unknown[] | undefined): RangeButtonFunctionParams | undefined;
@@ -31,6 +31,8 @@ export interface RangeButtonFunctionParams {
31
31
  * @example { unit: 'year' } // Last year (step defaults to 1)
32
32
  * - `[start, end]` — An absolute date range.
33
33
  * @example [new Date(2024, 0, 1), new Date(2024, 6, 1)] // Jan–Jul 2024
34
+ * - `[start, end]` of strings — A range between two axis values, for ordinal (band/point) axes.
35
+ * @example ['Feb', 'May'] // From the 'Feb' category to the 'May' category
34
36
  * - `(params) => { start, end }` — A function that receives axis context (`scaleType`, `data`, `domain`) and returns zoom percentages (0-100).
35
37
  * @example ({ domain }) => ({ start: 0, end: 50 }) // First half of data
36
38
  * @example ({ data }) => {
@@ -43,7 +45,7 @@ export interface RangeButtonFunctionParams {
43
45
  export type RangeButtonValue = {
44
46
  unit: RangeButtonIntervalUnit;
45
47
  step?: number;
46
- } | [Date, Date] | ((params: RangeButtonFunctionParams) => {
48
+ } | [Date, Date] | [string, string] | ((params: RangeButtonFunctionParams) => {
47
49
  start: number;
48
50
  end: number;
49
51
  }) | null;
@@ -63,4 +65,18 @@ export type RangeButtonValue = {
63
65
  export declare function rangeButtonValueToZoom(value: RangeButtonValue, params: RangeButtonFunctionParams): {
64
66
  start: number;
65
67
  end: number;
66
- };
68
+ };
69
+ /**
70
+ * Builds the {@link RangeButtonFunctionParams} for an axis from its computed domain.
71
+ *
72
+ * For ordinal (band/point) axes the domain is index-based; for continuous axes it
73
+ * uses the first and last domain values.
74
+ *
75
+ * @param axis The axis scale type and data.
76
+ * @param domain The computed domain values of the axis.
77
+ * @returns The params to pass to {@link rangeButtonValueToZoom}, or `undefined` if the domain is too small to zoom.
78
+ */
79
+ export declare function getRangeButtonDomainParams(axis: {
80
+ scaleType?: string;
81
+ data?: readonly unknown[];
82
+ }, domain: readonly unknown[] | undefined): RangeButtonFunctionParams | undefined;
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.getRangeButtonDomainParams = getRangeButtonDomainParams;
6
7
  exports.rangeButtonValueToZoom = rangeButtonValueToZoom;
7
8
  var _warning = require("@mui/x-internals/warning");
8
9
  /**
@@ -21,6 +22,8 @@ var _warning = require("@mui/x-internals/warning");
21
22
  * @example { unit: 'year' } // Last year (step defaults to 1)
22
23
  * - `[start, end]` — An absolute date range.
23
24
  * @example [new Date(2024, 0, 1), new Date(2024, 6, 1)] // Jan–Jul 2024
25
+ * - `[start, end]` of strings — A range between two axis values, for ordinal (band/point) axes.
26
+ * @example ['Feb', 'May'] // From the 'Feb' category to the 'May' category
24
27
  * - `(params) => { start, end }` — A function that receives axis context (`scaleType`, `data`, `domain`) and returns zoom percentages (0-100).
25
28
  * @example ({ domain }) => ({ start: 0, end: 50 }) // First half of data
26
29
  * @example ({ data }) => {
@@ -104,6 +107,7 @@ function rangeButtonValueToZoom(value, params) {
104
107
  };
105
108
  }
106
109
  const {
110
+ scaleType,
107
111
  domain: {
108
112
  min: domainMin,
109
113
  max: domainMax
@@ -111,13 +115,42 @@ function rangeButtonValueToZoom(value, params) {
111
115
  data: ordinalData
112
116
  } = params;
113
117
 
118
+ // Ordinal axis range — resolve each endpoint to its matching value on the axis.
119
+ // Band/point axes can carry strings, numbers, or dates, so the match is by strict equality.
120
+ if (Array.isArray(value) && ordinalData) {
121
+ const startIndex = ordinalData.findIndex(item => item === value[0]);
122
+ const endIndex = ordinalData.findIndex(item => item === value[1]);
123
+ if (startIndex !== -1 && endIndex !== -1) {
124
+ if (process.env.NODE_ENV !== 'production' && endIndex < startIndex) {
125
+ (0, _warning.warnOnce)(['MUI X Charts: Range button received a range whose end value comes before its start value.', 'This produces an empty zoom range.']);
126
+ }
127
+ // Band items span [i/L, (i+1)/L] along the axis; point items sit at i/(L-1).
128
+ // For band, the end index is inclusive, so the right edge of the band is `(endIndex + 1) / L`.
129
+ if (scaleType === 'band') {
130
+ return {
131
+ start: startIndex / ordinalData.length * 100,
132
+ end: (endIndex + 1) / ordinalData.length * 100
133
+ };
134
+ }
135
+ const maxIndex = ordinalData.length - 1;
136
+ return {
137
+ start: maxIndex === 0 ? 0 : startIndex / maxIndex * 100,
138
+ end: maxIndex === 0 ? 100 : endIndex / maxIndex * 100
139
+ };
140
+ }
141
+ // No match on the axis values — fall through in case they are date-like.
142
+ }
143
+
114
144
  // For ordinal axes with date-like data, resolve date ranges and intervals to matching indices.
115
145
  const timestamps = ordinalData ? toTimestampArray(ordinalData) : undefined;
116
146
  if (timestamps) {
147
+ const isBand = scaleType === 'band';
148
+ const denominator = isBand ? timestamps.length : timestamps.length - 1;
117
149
  const maxIndex = timestamps.length - 1;
150
+ const toPercent = (i, defaultPercent) => denominator === 0 ? defaultPercent : i / denominator * 100;
118
151
  if (Array.isArray(value)) {
119
- const startTarget = value[0].getTime();
120
- const endTarget = value[1].getTime();
152
+ const startTarget = toTimestamp(value[0]) ?? Number.NaN;
153
+ const endTarget = toTimestamp(value[1]) ?? Number.NaN;
121
154
  if (process.env.NODE_ENV !== 'production' && endTarget < startTarget) {
122
155
  (0, _warning.warnOnce)(['MUI X Charts: Range button received a date range whose end is before its start.', 'This produces an empty zoom range.']);
123
156
  }
@@ -126,8 +159,8 @@ function rangeButtonValueToZoom(value, params) {
126
159
  const startIndex = firstGte === -1 ? maxIndex : firstGte;
127
160
  const endIndex = lastLte === -1 ? 0 : lastLte;
128
161
  return {
129
- start: startIndex / maxIndex * 100,
130
- end: endIndex / maxIndex * 100
162
+ start: toPercent(startIndex, 0),
163
+ end: toPercent(endIndex + (isBand ? 1 : 0), 100)
131
164
  };
132
165
  }
133
166
 
@@ -138,12 +171,12 @@ function rangeButtonValueToZoom(value, params) {
138
171
  const firstGte = timestamps.findIndex(ts => !Number.isNaN(ts) && ts >= targetStartMs);
139
172
  const startIndex = firstGte === -1 ? maxIndex : firstGte;
140
173
  return {
141
- start: startIndex / maxIndex * 100,
174
+ start: toPercent(startIndex, 0),
142
175
  end: 100
143
176
  };
144
177
  }
145
178
  if (process.env.NODE_ENV !== 'production' && ordinalData !== undefined) {
146
- (0, _warning.warnOnce)(['MUI X Charts: Range button received a date value for an ordinal axis whose data could not be parsed as dates.', 'The zoom range may not match the intended selection. Provide date-like axis data or use a function value.']);
179
+ (0, _warning.warnOnce)(['MUI X Charts: Range button received a value for an ordinal axis whose data could not be matched.', 'The zoom range may not match the intended selection. Provide axis values that exist on the axis, date-like axis data, or use a function value.']);
147
180
  }
148
181
  const domainRange = domainMax - domainMin;
149
182
  if (domainRange <= 0) {
@@ -155,12 +188,13 @@ function rangeButtonValueToZoom(value, params) {
155
188
 
156
189
  // Absolute date range
157
190
  if (Array.isArray(value)) {
158
- const [rangeStart, rangeEnd] = value;
159
- if (process.env.NODE_ENV !== 'production' && rangeEnd.getTime() < rangeStart.getTime()) {
191
+ const rangeStart = toTimestamp(value[0]) ?? domainMin;
192
+ const rangeEnd = toTimestamp(value[1]) ?? domainMax;
193
+ if (process.env.NODE_ENV !== 'production' && rangeEnd < rangeStart) {
160
194
  (0, _warning.warnOnce)(['MUI X Charts: Range button received a date range whose end is before its start.', 'This produces an empty zoom range.']);
161
195
  }
162
- const startPercent = (rangeStart.getTime() - domainMin) / domainRange * 100;
163
- const endPercent = (rangeEnd.getTime() - domainMin) / domainRange * 100;
196
+ const startPercent = (rangeStart - domainMin) / domainRange * 100;
197
+ const endPercent = (rangeEnd - domainMin) / domainRange * 100;
164
198
  return {
165
199
  start: startPercent,
166
200
  end: endPercent
@@ -176,6 +210,35 @@ function rangeButtonValueToZoom(value, params) {
176
210
  };
177
211
  }
178
212
 
213
+ /**
214
+ * Builds the {@link RangeButtonFunctionParams} for an axis from its computed domain.
215
+ *
216
+ * For ordinal (band/point) axes the domain is index-based; for continuous axes it
217
+ * uses the first and last domain values.
218
+ *
219
+ * @param axis The axis scale type and data.
220
+ * @param domain The computed domain values of the axis.
221
+ * @returns The params to pass to {@link rangeButtonValueToZoom}, or `undefined` if the domain is too small to zoom.
222
+ */
223
+ function getRangeButtonDomainParams(axis, domain) {
224
+ if (!domain || domain.length < 2) {
225
+ return undefined;
226
+ }
227
+ const scaleType = axis.scaleType ?? 'linear';
228
+ const isOrdinal = scaleType === 'band' || scaleType === 'point';
229
+ return {
230
+ scaleType,
231
+ data: axis.data,
232
+ domain: isOrdinal ? {
233
+ min: 0,
234
+ max: domain.length - 1
235
+ } : {
236
+ min: Number(domain[0]),
237
+ max: Number(domain[domain.length - 1])
238
+ }
239
+ };
240
+ }
241
+
179
242
  /**
180
243
  * Computes the start timestamp for a calendar interval subtracted from a reference point.
181
244
  */
@@ -16,6 +16,8 @@ import { warnOnce } from '@mui/x-internals/warning';
16
16
  * @example { unit: 'year' } // Last year (step defaults to 1)
17
17
  * - `[start, end]` — An absolute date range.
18
18
  * @example [new Date(2024, 0, 1), new Date(2024, 6, 1)] // Jan–Jul 2024
19
+ * - `[start, end]` of strings — A range between two axis values, for ordinal (band/point) axes.
20
+ * @example ['Feb', 'May'] // From the 'Feb' category to the 'May' category
19
21
  * - `(params) => { start, end }` — A function that receives axis context (`scaleType`, `data`, `domain`) and returns zoom percentages (0-100).
20
22
  * @example ({ domain }) => ({ start: 0, end: 50 }) // First half of data
21
23
  * @example ({ data }) => {
@@ -99,6 +101,7 @@ export function rangeButtonValueToZoom(value, params) {
99
101
  };
100
102
  }
101
103
  const {
104
+ scaleType,
102
105
  domain: {
103
106
  min: domainMin,
104
107
  max: domainMax
@@ -106,13 +109,42 @@ export function rangeButtonValueToZoom(value, params) {
106
109
  data: ordinalData
107
110
  } = params;
108
111
 
112
+ // Ordinal axis range — resolve each endpoint to its matching value on the axis.
113
+ // Band/point axes can carry strings, numbers, or dates, so the match is by strict equality.
114
+ if (Array.isArray(value) && ordinalData) {
115
+ const startIndex = ordinalData.findIndex(item => item === value[0]);
116
+ const endIndex = ordinalData.findIndex(item => item === value[1]);
117
+ if (startIndex !== -1 && endIndex !== -1) {
118
+ if (process.env.NODE_ENV !== 'production' && endIndex < startIndex) {
119
+ warnOnce(['MUI X Charts: Range button received a range whose end value comes before its start value.', 'This produces an empty zoom range.']);
120
+ }
121
+ // Band items span [i/L, (i+1)/L] along the axis; point items sit at i/(L-1).
122
+ // For band, the end index is inclusive, so the right edge of the band is `(endIndex + 1) / L`.
123
+ if (scaleType === 'band') {
124
+ return {
125
+ start: startIndex / ordinalData.length * 100,
126
+ end: (endIndex + 1) / ordinalData.length * 100
127
+ };
128
+ }
129
+ const maxIndex = ordinalData.length - 1;
130
+ return {
131
+ start: maxIndex === 0 ? 0 : startIndex / maxIndex * 100,
132
+ end: maxIndex === 0 ? 100 : endIndex / maxIndex * 100
133
+ };
134
+ }
135
+ // No match on the axis values — fall through in case they are date-like.
136
+ }
137
+
109
138
  // For ordinal axes with date-like data, resolve date ranges and intervals to matching indices.
110
139
  const timestamps = ordinalData ? toTimestampArray(ordinalData) : undefined;
111
140
  if (timestamps) {
141
+ const isBand = scaleType === 'band';
142
+ const denominator = isBand ? timestamps.length : timestamps.length - 1;
112
143
  const maxIndex = timestamps.length - 1;
144
+ const toPercent = (i, defaultPercent) => denominator === 0 ? defaultPercent : i / denominator * 100;
113
145
  if (Array.isArray(value)) {
114
- const startTarget = value[0].getTime();
115
- const endTarget = value[1].getTime();
146
+ const startTarget = toTimestamp(value[0]) ?? Number.NaN;
147
+ const endTarget = toTimestamp(value[1]) ?? Number.NaN;
116
148
  if (process.env.NODE_ENV !== 'production' && endTarget < startTarget) {
117
149
  warnOnce(['MUI X Charts: Range button received a date range whose end is before its start.', 'This produces an empty zoom range.']);
118
150
  }
@@ -121,8 +153,8 @@ export function rangeButtonValueToZoom(value, params) {
121
153
  const startIndex = firstGte === -1 ? maxIndex : firstGte;
122
154
  const endIndex = lastLte === -1 ? 0 : lastLte;
123
155
  return {
124
- start: startIndex / maxIndex * 100,
125
- end: endIndex / maxIndex * 100
156
+ start: toPercent(startIndex, 0),
157
+ end: toPercent(endIndex + (isBand ? 1 : 0), 100)
126
158
  };
127
159
  }
128
160
 
@@ -133,12 +165,12 @@ export function rangeButtonValueToZoom(value, params) {
133
165
  const firstGte = timestamps.findIndex(ts => !Number.isNaN(ts) && ts >= targetStartMs);
134
166
  const startIndex = firstGte === -1 ? maxIndex : firstGte;
135
167
  return {
136
- start: startIndex / maxIndex * 100,
168
+ start: toPercent(startIndex, 0),
137
169
  end: 100
138
170
  };
139
171
  }
140
172
  if (process.env.NODE_ENV !== 'production' && ordinalData !== undefined) {
141
- warnOnce(['MUI X Charts: Range button received a date value for an ordinal axis whose data could not be parsed as dates.', 'The zoom range may not match the intended selection. Provide date-like axis data or use a function value.']);
173
+ warnOnce(['MUI X Charts: Range button received a value for an ordinal axis whose data could not be matched.', 'The zoom range may not match the intended selection. Provide axis values that exist on the axis, date-like axis data, or use a function value.']);
142
174
  }
143
175
  const domainRange = domainMax - domainMin;
144
176
  if (domainRange <= 0) {
@@ -150,12 +182,13 @@ export function rangeButtonValueToZoom(value, params) {
150
182
 
151
183
  // Absolute date range
152
184
  if (Array.isArray(value)) {
153
- const [rangeStart, rangeEnd] = value;
154
- if (process.env.NODE_ENV !== 'production' && rangeEnd.getTime() < rangeStart.getTime()) {
185
+ const rangeStart = toTimestamp(value[0]) ?? domainMin;
186
+ const rangeEnd = toTimestamp(value[1]) ?? domainMax;
187
+ if (process.env.NODE_ENV !== 'production' && rangeEnd < rangeStart) {
155
188
  warnOnce(['MUI X Charts: Range button received a date range whose end is before its start.', 'This produces an empty zoom range.']);
156
189
  }
157
- const startPercent = (rangeStart.getTime() - domainMin) / domainRange * 100;
158
- const endPercent = (rangeEnd.getTime() - domainMin) / domainRange * 100;
190
+ const startPercent = (rangeStart - domainMin) / domainRange * 100;
191
+ const endPercent = (rangeEnd - domainMin) / domainRange * 100;
159
192
  return {
160
193
  start: startPercent,
161
194
  end: endPercent
@@ -171,6 +204,35 @@ export function rangeButtonValueToZoom(value, params) {
171
204
  };
172
205
  }
173
206
 
207
+ /**
208
+ * Builds the {@link RangeButtonFunctionParams} for an axis from its computed domain.
209
+ *
210
+ * For ordinal (band/point) axes the domain is index-based; for continuous axes it
211
+ * uses the first and last domain values.
212
+ *
213
+ * @param axis The axis scale type and data.
214
+ * @param domain The computed domain values of the axis.
215
+ * @returns The params to pass to {@link rangeButtonValueToZoom}, or `undefined` if the domain is too small to zoom.
216
+ */
217
+ export function getRangeButtonDomainParams(axis, domain) {
218
+ if (!domain || domain.length < 2) {
219
+ return undefined;
220
+ }
221
+ const scaleType = axis.scaleType ?? 'linear';
222
+ const isOrdinal = scaleType === 'band' || scaleType === 'point';
223
+ return {
224
+ scaleType,
225
+ data: axis.data,
226
+ domain: isOrdinal ? {
227
+ min: 0,
228
+ max: domain.length - 1
229
+ } : {
230
+ min: Number(domain[0]),
231
+ max: Number(domain[domain.length - 1])
232
+ }
233
+ };
234
+ }
235
+
174
236
  /**
175
237
  * Computes the start timestamp for a calendar interval subtracted from a reference point.
176
238
  */
@@ -10,9 +10,16 @@ exports.useUtilityClasses = void 0;
10
10
  var _generateUtilityClasses = _interopRequireDefault(require("@mui/utils/generateUtilityClasses"));
11
11
  var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses"));
12
12
  var _generateUtilityClass = _interopRequireDefault(require("@mui/utils/generateUtilityClass"));
13
- const chartsAxisZoomSliderThumbClasses = exports.chartsAxisZoomSliderThumbClasses = (0, _generateUtilityClasses.default)('MuiChartAxisZoomSliderThumb', ['root', 'horizontal', 'vertical', 'start', 'end']);
13
+ const CORRECT_PREFIX = 'MuiChartsAxisZoomSliderThumb';
14
+ // TODO v10: remove `MuiChartAxisZoomSliderThumb`. Kept for backwards compatibility with
15
+ // users targeting the historically-incorrect prefix (missing the `s` in `Charts`).
16
+ const LEGACY_PREFIX = 'MuiChartAxisZoomSliderThumb';
17
+ const chartsAxisZoomSliderThumbClasses = exports.chartsAxisZoomSliderThumbClasses = (0, _generateUtilityClasses.default)(CORRECT_PREFIX, ['root', 'horizontal', 'vertical', 'start', 'end']);
18
+
19
+ // Returns both the correct and legacy class names so existing CSS targeting the legacy
20
+ // prefix continues to work.
14
21
  function getAxisZoomSliderThumbUtilityClass(slot) {
15
- return (0, _generateUtilityClass.default)('MuiChartAxisZoomSliderThumb', slot);
22
+ return `${(0, _generateUtilityClass.default)(CORRECT_PREFIX, slot)} ${(0, _generateUtilityClass.default)(LEGACY_PREFIX, slot)}`;
16
23
  }
17
24
  const useUtilityClasses = ownerState => {
18
25
  const {
@@ -1,9 +1,16 @@
1
1
  import generateUtilityClasses from '@mui/utils/generateUtilityClasses';
2
2
  import composeClasses from '@mui/utils/composeClasses';
3
3
  import generateUtilityClass from '@mui/utils/generateUtilityClass';
4
- export const chartsAxisZoomSliderThumbClasses = generateUtilityClasses('MuiChartAxisZoomSliderThumb', ['root', 'horizontal', 'vertical', 'start', 'end']);
4
+ const CORRECT_PREFIX = 'MuiChartsAxisZoomSliderThumb';
5
+ // TODO v10: remove `MuiChartAxisZoomSliderThumb`. Kept for backwards compatibility with
6
+ // users targeting the historically-incorrect prefix (missing the `s` in `Charts`).
7
+ const LEGACY_PREFIX = 'MuiChartAxisZoomSliderThumb';
8
+ export const chartsAxisZoomSliderThumbClasses = generateUtilityClasses(CORRECT_PREFIX, ['root', 'horizontal', 'vertical', 'start', 'end']);
9
+
10
+ // Returns both the correct and legacy class names so existing CSS targeting the legacy
11
+ // prefix continues to work.
5
12
  export function getAxisZoomSliderThumbUtilityClass(slot) {
6
- return generateUtilityClass('MuiChartAxisZoomSliderThumb', slot);
13
+ return `${generateUtilityClass(CORRECT_PREFIX, slot)} ${generateUtilityClass(LEGACY_PREFIX, slot)}`;
7
14
  }
8
15
  export const useUtilityClasses = ownerState => {
9
16
  const {
@@ -47,6 +47,7 @@ function ScatterPreviewPlot({
47
47
  id,
48
48
  xAxisId,
49
49
  yAxisId,
50
+ colorAxisId,
50
51
  zAxisId,
51
52
  color
52
53
  } = series[seriesId];
@@ -57,7 +58,7 @@ function ScatterPreviewPlot({
57
58
  if (xAxis?.id !== axisId && yAxis?.id !== axisId) {
58
59
  return null;
59
60
  }
60
- const colorGetter = _internals.scatterSeriesConfig.colorProcessor(series[seriesId], xAxis, yAxis, zAxes[zAxisId ?? defaultZAxisId]);
61
+ const colorGetter = _internals.scatterSeriesConfig.colorProcessor(series[seriesId], xAxis, yAxis, zAxes[colorAxisId ?? zAxisId ?? defaultZAxisId]);
61
62
  const xScale = xAxis.scale;
62
63
  const yScale = yAxis.scale;
63
64
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(ScatterPreviewItems, {
@@ -40,6 +40,7 @@ export function ScatterPreviewPlot({
40
40
  id,
41
41
  xAxisId,
42
42
  yAxisId,
43
+ colorAxisId,
43
44
  zAxisId,
44
45
  color
45
46
  } = series[seriesId];
@@ -50,7 +51,7 @@ export function ScatterPreviewPlot({
50
51
  if (xAxis?.id !== axisId && yAxis?.id !== axisId) {
51
52
  return null;
52
53
  }
53
- const colorGetter = scatterSeriesConfig.colorProcessor(series[seriesId], xAxis, yAxis, zAxes[zAxisId ?? defaultZAxisId]);
54
+ const colorGetter = scatterSeriesConfig.colorProcessor(series[seriesId], xAxis, yAxis, zAxes[colorAxisId ?? zAxisId ?? defaultZAxisId]);
54
55
  const xScale = xAxis.scale;
55
56
  const yScale = yAxis.scale;
56
57
  return /*#__PURE__*/_jsx(ScatterPreviewItems, {
@@ -1,21 +1,22 @@
1
1
  import type * as React from 'react';
2
2
  import type { FunnelSectionProps } from "./FunnelSection.mjs";
3
3
  import { type FunnelSectionLabelProps } from "./FunnelSectionLabel.mjs";
4
+ import type { FunnelSectionPropsOverrides, FunnelSectionLabelPropsOverrides } from "../models/chartsSlotsComponentsPropsPro.mjs";
4
5
  export interface FunnelPlotSlots {
5
6
  /**
6
7
  * Custom component for funnel section.
7
8
  * @default FunnelSection
8
9
  */
9
- funnelSection?: React.ElementType<FunnelSectionProps>;
10
+ funnelSection?: React.ElementType<FunnelSectionProps & FunnelSectionPropsOverrides>;
10
11
  /**
11
12
  * Custom component for funnel section label.
12
13
  * @default FunnelSectionLabel
13
14
  */
14
- funnelSectionLabel?: React.ElementType<FunnelSectionLabelProps>;
15
+ funnelSectionLabel?: React.ElementType<FunnelSectionLabelProps & FunnelSectionLabelPropsOverrides>;
15
16
  }
16
17
  export interface FunnelPlotSlotProps {
17
- funnelSection?: FunnelSectionProps;
18
- funnelSectionLabel?: FunnelSectionLabelProps;
18
+ funnelSection?: Partial<FunnelSectionProps> & FunnelSectionPropsOverrides;
19
+ funnelSectionLabel?: Partial<FunnelSectionLabelProps> & FunnelSectionLabelPropsOverrides;
19
20
  }
20
21
  export interface FunnelPlotSlotExtension {
21
22
  /**
@@ -1,21 +1,22 @@
1
1
  import type * as React from 'react';
2
2
  import type { FunnelSectionProps } from "./FunnelSection.js";
3
3
  import { type FunnelSectionLabelProps } from "./FunnelSectionLabel.js";
4
+ import type { FunnelSectionPropsOverrides, FunnelSectionLabelPropsOverrides } from "../models/chartsSlotsComponentsPropsPro.js";
4
5
  export interface FunnelPlotSlots {
5
6
  /**
6
7
  * Custom component for funnel section.
7
8
  * @default FunnelSection
8
9
  */
9
- funnelSection?: React.ElementType<FunnelSectionProps>;
10
+ funnelSection?: React.ElementType<FunnelSectionProps & FunnelSectionPropsOverrides>;
10
11
  /**
11
12
  * Custom component for funnel section label.
12
13
  * @default FunnelSectionLabel
13
14
  */
14
- funnelSectionLabel?: React.ElementType<FunnelSectionLabelProps>;
15
+ funnelSectionLabel?: React.ElementType<FunnelSectionLabelProps & FunnelSectionLabelPropsOverrides>;
15
16
  }
16
17
  export interface FunnelPlotSlotProps {
17
- funnelSection?: FunnelSectionProps;
18
- funnelSectionLabel?: FunnelSectionLabelProps;
18
+ funnelSection?: Partial<FunnelSectionProps> & FunnelSectionPropsOverrides;
19
+ funnelSectionLabel?: Partial<FunnelSectionLabelProps> & FunnelSectionLabelPropsOverrides;
19
20
  }
20
21
  export interface FunnelPlotSlotExtension {
21
22
  /**
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { type MakeOptional } from '@mui/x-internals/types';
3
3
  import { type ChartsTooltipProps } from '@mui/x-charts/ChartsTooltip';
4
4
  import { type ChartsAxisSlots, type ChartsAxisSlotProps, type XAxis, type YAxis } from '@mui/x-charts/internals';
5
+ import type { TooltipPropsOverrides } from '@mui/x-charts/models';
5
6
  import { type ChartsOverlayProps, type ChartsOverlaySlotProps, type ChartsOverlaySlots } from '@mui/x-charts/ChartsOverlay';
6
7
  import { type ChartsLegendSlotProps, type ChartsLegendSlots } from '@mui/x-charts/ChartsLegend';
7
8
  import { type ChartsSlotPropsPro, type ChartsSlotsPro } from "../internals/material/index.mjs";
@@ -16,7 +17,7 @@ export interface HeatmapSlots extends ChartsAxisSlots, ChartsOverlaySlots, Heatm
16
17
  * Custom component for the tooltip.
17
18
  * @default ChartsTooltipRoot
18
19
  */
19
- tooltip?: React.ElementType<HeatmapTooltipProps>;
20
+ tooltip?: React.ElementType<HeatmapTooltipProps & TooltipPropsOverrides>;
20
21
  /**
21
22
  * Custom component for the legend.
22
23
  * @default ContinuousColorLegendProps
@@ -24,7 +25,7 @@ export interface HeatmapSlots extends ChartsAxisSlots, ChartsOverlaySlots, Heatm
24
25
  legend?: ChartsLegendSlots['legend'];
25
26
  }
26
27
  export interface HeatmapSlotProps extends ChartsAxisSlotProps, ChartsOverlaySlotProps, HeatmapItemSlotProps, ChartsLegendSlotProps, ChartsToolbarProSlotProps, Partial<ChartsSlotPropsPro> {
27
- tooltip?: Partial<HeatmapTooltipProps>;
28
+ tooltip?: Partial<HeatmapTooltipProps> & TooltipPropsOverrides;
28
29
  }
29
30
  export type HeatmapSeries = MakeOptional<HeatmapSeriesType, 'type'>;
30
31
  export interface HeatmapProps extends Omit<ChartsContainerProProps<'heatmap', HeatmapPluginSignatures>, 'series' | 'plugins' | 'xAxis' | 'yAxis' | 'axesGap' | 'skipAnimation' | 'slots' | 'slotProps' | 'highlightedAxis' | 'onHighlightedAxisChange' | 'seriesConfig' | 'onAxisClick'>, Omit<ChartsOverlayProps, 'slots' | 'slotProps'> {
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { type MakeOptional } from '@mui/x-internals/types';
3
3
  import { type ChartsTooltipProps } from '@mui/x-charts/ChartsTooltip';
4
4
  import { type ChartsAxisSlots, type ChartsAxisSlotProps, type XAxis, type YAxis } from '@mui/x-charts/internals';
5
+ import type { TooltipPropsOverrides } from '@mui/x-charts/models';
5
6
  import { type ChartsOverlayProps, type ChartsOverlaySlotProps, type ChartsOverlaySlots } from '@mui/x-charts/ChartsOverlay';
6
7
  import { type ChartsLegendSlotProps, type ChartsLegendSlots } from '@mui/x-charts/ChartsLegend';
7
8
  import { type ChartsSlotPropsPro, type ChartsSlotsPro } from "../internals/material/index.js";
@@ -16,7 +17,7 @@ export interface HeatmapSlots extends ChartsAxisSlots, ChartsOverlaySlots, Heatm
16
17
  * Custom component for the tooltip.
17
18
  * @default ChartsTooltipRoot
18
19
  */
19
- tooltip?: React.ElementType<HeatmapTooltipProps>;
20
+ tooltip?: React.ElementType<HeatmapTooltipProps & TooltipPropsOverrides>;
20
21
  /**
21
22
  * Custom component for the legend.
22
23
  * @default ContinuousColorLegendProps
@@ -24,7 +25,7 @@ export interface HeatmapSlots extends ChartsAxisSlots, ChartsOverlaySlots, Heatm
24
25
  legend?: ChartsLegendSlots['legend'];
25
26
  }
26
27
  export interface HeatmapSlotProps extends ChartsAxisSlotProps, ChartsOverlaySlotProps, HeatmapItemSlotProps, ChartsLegendSlotProps, ChartsToolbarProSlotProps, Partial<ChartsSlotPropsPro> {
27
- tooltip?: Partial<HeatmapTooltipProps>;
28
+ tooltip?: Partial<HeatmapTooltipProps> & TooltipPropsOverrides;
28
29
  }
29
30
  export type HeatmapSeries = MakeOptional<HeatmapSeriesType, 'type'>;
30
31
  export interface HeatmapProps extends Omit<ChartsContainerProProps<'heatmap', HeatmapPluginSignatures>, 'series' | 'plugins' | 'xAxis' | 'yAxis' | 'axesGap' | 'skipAnimation' | 'slots' | 'slotProps' | 'highlightedAxis' | 'onHighlightedAxisChange' | 'seriesConfig' | 'onAxisClick'>, Omit<ChartsOverlayProps, 'slots' | 'slotProps'> {
@@ -151,12 +151,21 @@ process.env.NODE_ENV !== "production" ? Heatmap.propTypes = {
151
151
  /**
152
152
  * The list of zoom data related to each axis.
153
153
  * Used to initialize the zoom in a specific configuration without controlling it.
154
+ *
155
+ * Each entry is either explicit zoom percentages (`{ axisId, start, end }`) or a
156
+ * range value (`{ axisId, value }`) resolved against the axis domain.
154
157
  */
155
- initialZoom: _propTypes.default.arrayOf(_propTypes.default.shape({
158
+ initialZoom: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.shape({
156
159
  axisId: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
157
160
  end: _propTypes.default.number.isRequired,
158
161
  start: _propTypes.default.number.isRequired
159
- })),
162
+ }), _propTypes.default.shape({
163
+ axisId: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]).isRequired,
164
+ value: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.instanceOf(Date).isRequired), _propTypes.default.arrayOf(_propTypes.default.string.isRequired), _propTypes.default.func, _propTypes.default.shape({
165
+ step: _propTypes.default.number,
166
+ unit: _propTypes.default.oneOf(['day', 'hour', 'microsecond', 'millisecond', 'minute', 'month', 'second', 'week', 'year']).isRequired
167
+ })])
168
+ })]).isRequired),
160
169
  /**
161
170
  * If `true`, a loading overlay is displayed.
162
171
  * @default false
@@ -305,6 +314,27 @@ process.env.NODE_ENV !== "production" ? Heatmap.propTypes = {
305
314
  id: _propTypes.default.string,
306
315
  max: _propTypes.default.number,
307
316
  min: _propTypes.default.number,
317
+ sizeMap: _propTypes.default.oneOfType([_propTypes.default.shape({
318
+ interpolator: _propTypes.default.oneOf(['linear', 'log', 'sqrt']),
319
+ max: _propTypes.default.oneOfType([_propTypes.default.instanceOf(Date), _propTypes.default.number]),
320
+ min: _propTypes.default.oneOfType([_propTypes.default.instanceOf(Date), _propTypes.default.number]),
321
+ size: _propTypes.default.arrayOf(_propTypes.default.number.isRequired).isRequired,
322
+ type: _propTypes.default.oneOf(['continuous']).isRequired
323
+ }), _propTypes.default.shape({
324
+ max: _propTypes.default.oneOfType([_propTypes.default.instanceOf(Date), _propTypes.default.number]),
325
+ min: _propTypes.default.oneOfType([_propTypes.default.instanceOf(Date), _propTypes.default.number]),
326
+ size: _propTypes.default.func.isRequired,
327
+ type: _propTypes.default.oneOf(['continuous']).isRequired
328
+ }), _propTypes.default.shape({
329
+ sizes: _propTypes.default.arrayOf(_propTypes.default.number).isRequired,
330
+ thresholds: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.instanceOf(Date), _propTypes.default.number]).isRequired).isRequired,
331
+ type: _propTypes.default.oneOf(['piecewise']).isRequired
332
+ }), _propTypes.default.shape({
333
+ sizes: _propTypes.default.arrayOf(_propTypes.default.number).isRequired,
334
+ type: _propTypes.default.oneOf(['ordinal']).isRequired,
335
+ unknownSize: _propTypes.default.number,
336
+ values: _propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.instanceOf(Date), _propTypes.default.number, _propTypes.default.string]).isRequired)
337
+ })]),
308
338
  valueGetter: _propTypes.default.func
309
339
  })),
310
340
  /**