@mui/x-charts 9.12.0 → 9.13.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 (78) hide show
  1. package/BarChart/BarChart.js +1 -1
  2. package/BarChart/BarChart.mjs +1 -1
  3. package/CHANGELOG.md +152 -0
  4. package/ChartsContainer/ChartsContainer.js +1 -1
  5. package/ChartsContainer/ChartsContainer.mjs +1 -1
  6. package/ChartsXAxis/useAxisTicksProps.js +2 -1
  7. package/ChartsXAxis/useAxisTicksProps.mjs +2 -1
  8. package/ChartsYAxis/shortenLabels.js +16 -26
  9. package/ChartsYAxis/shortenLabels.mjs +17 -27
  10. package/ChartsYAxis/useAxisTicksProps.js +2 -1
  11. package/ChartsYAxis/useAxisTicksProps.mjs +2 -1
  12. package/LineChart/LineChart.js +1 -1
  13. package/LineChart/LineChart.mjs +1 -1
  14. package/LineChart/MarkElement.js +13 -6
  15. package/LineChart/MarkElement.mjs +13 -6
  16. package/RadarChart/RadarAxis/RadarAxis.utils.d.mts +1 -1
  17. package/RadarChart/RadarAxis/RadarAxis.utils.d.ts +1 -1
  18. package/RadarChart/RadarChart.js +1 -1
  19. package/RadarChart/RadarChart.mjs +1 -1
  20. package/RadarChart/RadarSeriesPlot/RadarSeriesMarks.js +6 -2
  21. package/RadarChart/RadarSeriesPlot/RadarSeriesMarks.mjs +6 -2
  22. package/RadarChart/RadarSeriesPlot/RadarSeriesPlot.js +2 -1
  23. package/RadarChart/RadarSeriesPlot/RadarSeriesPlot.mjs +2 -1
  24. package/ScatterChart/ScatterChart.js +1 -1
  25. package/ScatterChart/ScatterChart.mjs +1 -1
  26. package/SparkLineChart/SparkLineChart.js +1 -1
  27. package/SparkLineChart/SparkLineChart.mjs +1 -1
  28. package/constants/index.d.mts +3 -1
  29. package/constants/index.d.ts +3 -1
  30. package/constants/index.js +5 -2
  31. package/constants/index.mjs +4 -1
  32. package/hooks/animation/index.d.mts +1 -0
  33. package/hooks/animation/index.d.ts +1 -0
  34. package/hooks/animation/index.js +11 -0
  35. package/hooks/animation/index.mjs +1 -0
  36. package/hooks/animation/useAnimateMark.d.mts +25 -0
  37. package/hooks/animation/useAnimateMark.d.ts +25 -0
  38. package/hooks/animation/useAnimateMark.js +45 -0
  39. package/hooks/animation/useAnimateMark.mjs +39 -0
  40. package/index.js +1 -1
  41. package/index.mjs +1 -1
  42. package/internals/domUtils.js +17 -16
  43. package/internals/domUtils.mjs +17 -15
  44. package/internals/ellipsize.d.mts +30 -0
  45. package/internals/ellipsize.d.ts +30 -0
  46. package/internals/ellipsize.js +60 -0
  47. package/internals/ellipsize.mjs +59 -0
  48. package/internals/index.d.mts +1 -0
  49. package/internals/index.d.ts +1 -0
  50. package/internals/index.js +8 -0
  51. package/internals/index.mjs +1 -0
  52. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.d.mts +3 -0
  53. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.d.ts +3 -0
  54. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.js +9 -5
  55. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.mjs +9 -5
  56. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartAxisAutoSize.selectors.js +9 -4
  57. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartAxisAutoSize.selectors.mjs +9 -4
  58. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.js +75 -3
  59. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.mjs +76 -3
  60. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.types.d.mts +6 -2
  61. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.types.d.ts +6 -2
  62. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisLayout.selectors.d.mts +1 -0
  63. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisLayout.selectors.d.ts +1 -0
  64. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.js +44 -11
  65. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.mjs +44 -11
  66. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.d.mts +18 -0
  67. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.d.ts +18 -0
  68. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.js +65 -0
  69. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.mjs +60 -0
  70. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.js +43 -1
  71. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.mjs +43 -1
  72. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.types.d.mts +3 -2
  73. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.types.d.ts +3 -2
  74. package/internals/useDefaultTickLabelStyle.d.mts +7 -0
  75. package/internals/useDefaultTickLabelStyle.d.ts +7 -0
  76. package/internals/useDefaultTickLabelStyle.js +34 -0
  77. package/internals/useDefaultTickLabelStyle.mjs +28 -0
  78. package/package.json +6 -6
@@ -275,7 +275,7 @@ process.env.NODE_ENV !== "production" ? BarChart.propTypes /* remove-proptypes *
275
275
  /**
276
276
  * The function called for onClick events.
277
277
  * The second argument contains information about all line/bar elements at the current mouse position.
278
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
278
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
279
279
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
280
280
  */
281
281
  onAxisClick: _propTypes.default.func,
@@ -268,7 +268,7 @@ process.env.NODE_ENV !== "production" ? BarChart.propTypes /* remove-proptypes *
268
268
  /**
269
269
  * The function called for onClick events.
270
270
  * The second argument contains information about all line/bar elements at the current mouse position.
271
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
271
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
272
272
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
273
273
  */
274
274
  onAxisClick: PropTypes.func,
package/CHANGELOG.md CHANGED
@@ -1,5 +1,157 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.13.0
4
+
5
+ <!-- generated comparing v9.12.0..master -->
6
+
7
+ _Sep 4, 2026_
8
+
9
+ We'd like to extend a big thank you to the 14 contributors who made this release possible. Here are some highlights ✨:
10
+
11
+ - 🦮 Improve keyboard navigation features of the Charts.
12
+ - 🎨 Improved customization of the edit event dialog in the `EventCalendar`
13
+ - 🐞 Bugfixes
14
+ - 📚 Documentation improvements
15
+
16
+ Special thanks go out to these community members for their valuable contributions:
17
+ @Anexus5919, @jvskriubakken, @mustafajw07, @roychan1
18
+
19
+ The following team members contributed to this release:
20
+ @brijeshb42, @flaviendelangle, @hasdfa, @Janpot, @JCQuintas, @LukasTy, @michelengelen, @noraleonte, @rita-codes, @silviuaavram
21
+
22
+ ### Data Grid
23
+
24
+ #### `@mui/x-data-grid@9.13.0`
25
+
26
+ - [DataGrid] Call `onValueChange` after `setEditCellValue` in edit cells (#23417) @michelengelen
27
+ - [DataGrid] Add support for replacing rows instead of merging updates (#23323) @jvskriubakken
28
+ - [DataGrid] Always render `rowHeader` in virtualized setups (#23386) @silviuaavram
29
+ - [DataGrid] Export `ToolbarRoot` (#23322) @JCQuintas
30
+ - [DataGrid] Fix `rowsPerPage` selector appearing when `autoPageSize` is enabled and `pageSize` is one of `pageSizeOptions` (#23401) @roychan1
31
+ - [DataGrid] Fix row tree reset when a data source grid becomes visible (#23288) @JCQuintas
32
+
33
+ #### `@mui/x-data-grid-pro@9.13.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
34
+
35
+ Same changes as in `@mui/x-data-grid@9.13.0`, plus:
36
+
37
+ - [DataGridPro] Remove rows deleted server-side on nested lazy loading revalidation (#23320) @JCQuintas
38
+ - [DataGridPro] Stop `disableDebounce` from reaching the DOM in multi select filter (#23445) @JCQuintas
39
+
40
+ #### `@mui/x-data-grid-premium@9.13.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
41
+
42
+ Same changes as in `@mui/x-data-grid-pro@9.13.0`, plus:
43
+
44
+ - [DataGridPremium] Refine cell selection and speed up clipboard copy (#23473) @michelengelen
45
+ - [DataGridPremium] Select all cells with Ctrl+A (#23415) @michelengelen
46
+
47
+ ### Date and Time Pickers
48
+
49
+ #### `@mui/x-date-pickers@9.13.0`
50
+
51
+ Internal changes.
52
+
53
+ #### `@mui/x-date-pickers-pro@9.13.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
54
+
55
+ Same changes as in `@mui/x-date-pickers@9.13.0`.
56
+
57
+ ### Charts
58
+
59
+ #### `@mui/x-charts@9.13.0`
60
+
61
+ - [charts] Activate the focused axis with Enter/Space (#23219) @JCQuintas
62
+ - [charts] Add keyboard zoom and pan (#23369) @JCQuintas
63
+ - [charts] Fix line mark position under browser zoom in Safari (#23387) @noraleonte
64
+ - [charts] Fix y axis tick labels shortened near the top of the chart (#23435) @JCQuintas
65
+ - [charts] Focus the clicked item on radar charts (#23287) @JCQuintas
66
+ - [charts] Stop text measurements leaking into each other (#23430) @JCQuintas
67
+
68
+ #### `@mui/x-charts-pro@9.13.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
69
+
70
+ Same changes as in `@mui/x-charts@9.13.0`.
71
+
72
+ #### `@mui/x-charts-premium@9.13.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
73
+
74
+ Same changes as in `@mui/x-charts-pro@9.13.0`.
75
+
76
+ ### Tree View
77
+
78
+ #### `@mui/x-tree-view@9.13.0`
79
+
80
+ - [tree view] Add `loading` prop and customizable loading UI (#22251) @michelengelen
81
+ - [tree view] Reduce selector bundle size (#23412) @flaviendelangle
82
+ - [tree view] Remove dead UI from community component (#23487) @noraleonte
83
+ - [tree view] Remove unused dependencies (#23488) @noraleonte
84
+ - [tree view] Use `useId` for the default tree id (#23341) @Anexus5919
85
+
86
+ #### `@mui/x-tree-view-pro@9.13.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
87
+
88
+ Same changes as in `@mui/x-tree-view@9.13.0`.
89
+
90
+ ### Scheduler
91
+
92
+ #### `@mui/x-scheduler@9.0.0-beta.11`
93
+
94
+ - [scheduler] Absorb un-acted `ResizeObserver` deliveries after rendering the timeline (#23444) @rita-codes
95
+ - [scheduler] Add `EventContextMenu` with Edit and Delete actions (#23379) @mustafajw07
96
+ - [scheduler] Add aria-hidden to collapsed side panel and refactor landmark structure (#23425) @mustafajw07
97
+ - [scheduler] Add the `eventDialogGeneralTab` slot (#23338) @rita-codes
98
+ - [scheduler] Fix the un-awaited act warning in the event dialog slot test (#23446) @JCQuintas
99
+ - [scheduler] Improve timeline event layout performance (#23364) @flaviendelangle
100
+ - [scheduler] Keep `aria-expanded` present when ViewSwitcher and PreferencesMenu menus are closed (#23427) @mustafajw07
101
+ - [scheduler] Make the event dialog General-tab building blocks public (#23398) @rita-codes
102
+ - [scheduler] Migrate to the pragmatic-drag-and-drop v3 entry points (#23442) @rita-codes
103
+ - [scheduler] Reduce selector bundle size (#23413) @flaviendelangle
104
+ - [scheduler] Reuse processed events between updates (#23363) @flaviendelangle
105
+ - [scheduler] Add `aria-expanded` and `aria-controls` to side panel toggle button (#23402) @mustafajw07
106
+
107
+ #### `@mui/x-scheduler-premium@9.0.0-beta.11` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
108
+
109
+ Same changes as in `@mui/x-scheduler@9.0.0-beta.11`, plus:
110
+
111
+ - [scheduler-premium] Dependencies - Keep event drags working over the arrow hit-areas (#23441) @rita-codes
112
+ - [scheduler-premium] Dependencies - Reject dependencies that would create a cycle (#23389) @rita-codes
113
+ - [scheduler-premium] Key recurring `exDates` on their data-timezone day (#23467) @rita-codes
114
+
115
+ ### Codemod
116
+
117
+ #### `@mui/x-codemod@9.13.0`
118
+
119
+ Internal changes.
120
+
121
+ ### Docs
122
+
123
+ - [docs] Add synchronized tooltip and crosshair demo to charts (#23368) @JCQuintas
124
+ - [docs] Add sticky headers recipe to `RichTreeView` customization (#22908) @michelengelen
125
+ - [docs] Pin the visible date of the scheduler preferences demos (#23432) @rita-codes
126
+ - [docs] Star-prefix bare :where() dark-mode selectors (#23419) @Janpot
127
+ - [docs] Consolidate demo data into shared dataset files (#23496) @michelengelen
128
+
129
+ ### Core
130
+
131
+ - [code-infra] Consume shared commands from code-infra orb (#23485) @brijeshb42
132
+ - [code-infra] Move the shared spy helpers off Sinon (#23466) @JCQuintas
133
+ - [code-infra] Point the support validator link at frontend-public (#23422) @Janpot
134
+ - [code-infra] Reduce per-page memory in the browser test suite (#23424) @Janpot
135
+ - [code-infra] Remove Sinon (#23476) @JCQuintas
136
+ - [code-infra] Remove the explicit `styled-components` dependency (#23479) @LukasTy
137
+ - [code-infra] Replace the mechanical sinon `spy()` usages with `vi.fn()` (#23443) @JCQuintas
138
+ - [code-infra] Replace the sinon `spy(fn)` usages with `vi.fn(fn)` (#23460) @JCQuintas
139
+ - [code-infra] Replace the sinon spy types with the Vitest ones (#23464) @JCQuintas
140
+ - [code-infra] Replace the sinon spy-on-object calls with `vi.spyOn` (#23474) @JCQuintas
141
+ - [code-infra] Replace the sinon stubs with Vitest mocks (#23472) @JCQuintas
142
+ - [code-infra] Run TypeScript 7 alongside the TS6 JS API (#23471) @brijeshb42
143
+ - [code-infra] Trim the shared browser test setup graph (#23426) @LukasTy
144
+ - [code-infra] Update CircleCI orb (#23418) @JCQuintas
145
+ - [code-infra] Use explicit vitest imports in test files (#23375) @michelengelen
146
+
147
+ ### Miscellaneous
148
+
149
+ - [chat] Enforce top-level type imports (#23037) @Janpot
150
+ - [chat] Fix global preload error from the `remend` import (#23263) @hasdfa
151
+ - [ci] Add Claude PR review via mui-public reusable workflow (#23423) @Janpot
152
+ - [telemetry] Fix get-context test leaking mock from sender test (#23447) @JCQuintas
153
+ - [test] Fail the regression run when a webfont does not load (#23376) @LukasTy
154
+
3
155
  ## 9.12.0
4
156
 
5
157
  _Aug 21, 2026_
@@ -231,7 +231,7 @@ process.env.NODE_ENV !== "production" ? ChartsContainer.propTypes /* remove-prop
231
231
  /**
232
232
  * The function called for onClick events.
233
233
  * The second argument contains information about all line/bar elements at the current mouse position.
234
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
234
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
235
235
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
236
236
  */
237
237
  onAxisClick: _propTypes.default.func,
@@ -224,7 +224,7 @@ process.env.NODE_ENV !== "production" ? ChartsContainer.propTypes /* remove-prop
224
224
  /**
225
225
  * The function called for onClick events.
226
226
  * The second argument contains information about all line/bar elements at the current mouse position.
227
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
227
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
228
228
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
229
229
  */
230
230
  onAxisClick: PropTypes.func,
@@ -16,6 +16,7 @@ var _useAxis = require("../hooks/useAxis");
16
16
  var _defaultTextPlacement = require("../ChartsText/defaultTextPlacement");
17
17
  var _invertTextAnchor = require("../internals/invertTextAnchor");
18
18
  var _utilities = require("./utilities");
19
+ var _constants = require("../constants");
19
20
  const _excluded = ["scale", "tickNumber", "reverse"];
20
21
  function useAxisTicksProps(inProps) {
21
22
  const {
@@ -57,7 +58,7 @@ function useAxisTicksProps(inProps) {
57
58
  // @ts-expect-error `useSlotProps` applies `WithCommonProps` with adds a `style: React.CSSProperties` prop automatically.
58
59
  additionalProps: {
59
60
  style: (0, _extends2.default)({}, theme.typography.caption, {
60
- fontSize: 12,
61
+ fontSize: _constants.DEFAULT_TICK_LABEL_FONT_SIZE,
61
62
  lineHeight: 1.25,
62
63
  textAnchor: isRtl ? (0, _invertTextAnchor.invertTextAnchor)(defaultTextAnchor) : defaultTextAnchor,
63
64
  dominantBaseline: defaultDominantBaseline
@@ -11,6 +11,7 @@ import { useXAxes } from "../hooks/useAxis.mjs";
11
11
  import { getDefaultBaseline, getDefaultTextAnchor } from "../ChartsText/defaultTextPlacement.mjs";
12
12
  import { invertTextAnchor } from "../internals/invertTextAnchor.mjs";
13
13
  import { defaultProps, useUtilityClasses } from "./utilities.mjs";
14
+ import { DEFAULT_TICK_LABEL_FONT_SIZE } from "../constants/index.mjs";
14
15
  export function useAxisTicksProps(inProps) {
15
16
  const {
16
17
  xAxis,
@@ -51,7 +52,7 @@ export function useAxisTicksProps(inProps) {
51
52
  // @ts-expect-error `useSlotProps` applies `WithCommonProps` with adds a `style: React.CSSProperties` prop automatically.
52
53
  additionalProps: {
53
54
  style: _extends({}, theme.typography.caption, {
54
- fontSize: 12,
55
+ fontSize: DEFAULT_TICK_LABEL_FONT_SIZE,
55
56
  lineHeight: 1.25,
56
57
  textAnchor: isRtl ? invertTextAnchor(defaultTextAnchor) : defaultTextAnchor,
57
58
  dominantBaseline: defaultDominantBaseline
@@ -11,34 +11,24 @@ var _domUtils = require("../internals/domUtils");
11
11
  function shortenLabels(visibleLabels, drawingArea, maxWidth, isRtl, tickLabelStyle) {
12
12
  const shortenedLabels = new Map();
13
13
  const angle = (0, _clampAngle.clampAngle)(tickLabelStyle?.angle ?? 0);
14
- let topBoundFactor = 1;
15
- let bottomBoundFactor = 1;
16
- if (tickLabelStyle?.textAnchor === 'start') {
17
- topBoundFactor = Infinity;
18
- bottomBoundFactor = 1;
19
- } else if (tickLabelStyle?.textAnchor === 'end') {
20
- topBoundFactor = 1;
21
- bottomBoundFactor = Infinity;
22
- } else {
23
- topBoundFactor = 2;
24
- bottomBoundFactor = 2;
25
- }
26
- if (angle > 180) {
27
- [topBoundFactor, bottomBoundFactor] = [bottomBoundFactor, topBoundFactor];
28
- }
29
- if (isRtl) {
30
- [topBoundFactor, bottomBoundFactor] = [bottomBoundFactor, topBoundFactor];
31
- }
14
+ const boundsConfig = {
15
+ angle,
16
+ textAnchor: tickLabelStyle?.textAnchor,
17
+ dominantBaseline: tickLabelStyle?.dominantBaseline,
18
+ isRtl
19
+ };
20
+ const svgHeight = drawingArea.top + drawingArea.height + drawingArea.bottom;
32
21
  for (const item of visibleLabels) {
33
22
  if (item.formattedValue) {
34
- // That maximum height of the tick depends on its proximity to the axis bounds.
35
- const height = Math.min((item.offset + item.labelOffset) * topBoundFactor, (drawingArea.top + drawingArea.height + drawingArea.bottom - item.offset - item.labelOffset) * bottomBoundFactor);
36
- const doesTextFit = text => (0, _ellipsize.doesTextFitInRect)(text, {
37
- width: maxWidth,
38
- height,
39
- angle,
40
- measureText: string => (0, _domUtils.getStringSize)(string, tickLabelStyle)
41
- });
23
+ // The label is anchored on the tick, so how far it can extend vertically depends on the
24
+ // proximity of the tick to the SVG bounds.
25
+ const anchor = item.offset + item.labelOffset;
26
+ const spaceAbove = anchor;
27
+ const spaceBelow = svgHeight - anchor;
28
+ const doesTextFit = text => {
29
+ const bounds = (0, _ellipsize.getRotatedTextBounds)((0, _domUtils.getStringSize)(text, tickLabelStyle), boundsConfig);
30
+ return bounds.width <= maxWidth && bounds.above <= spaceAbove && bounds.below <= spaceBelow;
31
+ };
42
32
  shortenedLabels.set(item, (0, _ellipsize.ellipsize)(item.formattedValue.toString(), doesTextFit));
43
33
  }
44
34
  }
@@ -1,39 +1,29 @@
1
1
  'use client';
2
2
 
3
3
  import { clampAngle } from "../internals/clampAngle.mjs";
4
- import { doesTextFitInRect, ellipsize } from "../internals/ellipsize.mjs";
4
+ import { ellipsize, getRotatedTextBounds } from "../internals/ellipsize.mjs";
5
5
  import { getStringSize } from "../internals/domUtils.mjs";
6
6
  export function shortenLabels(visibleLabels, drawingArea, maxWidth, isRtl, tickLabelStyle) {
7
7
  const shortenedLabels = new Map();
8
8
  const angle = clampAngle(tickLabelStyle?.angle ?? 0);
9
- let topBoundFactor = 1;
10
- let bottomBoundFactor = 1;
11
- if (tickLabelStyle?.textAnchor === 'start') {
12
- topBoundFactor = Infinity;
13
- bottomBoundFactor = 1;
14
- } else if (tickLabelStyle?.textAnchor === 'end') {
15
- topBoundFactor = 1;
16
- bottomBoundFactor = Infinity;
17
- } else {
18
- topBoundFactor = 2;
19
- bottomBoundFactor = 2;
20
- }
21
- if (angle > 180) {
22
- [topBoundFactor, bottomBoundFactor] = [bottomBoundFactor, topBoundFactor];
23
- }
24
- if (isRtl) {
25
- [topBoundFactor, bottomBoundFactor] = [bottomBoundFactor, topBoundFactor];
26
- }
9
+ const boundsConfig = {
10
+ angle,
11
+ textAnchor: tickLabelStyle?.textAnchor,
12
+ dominantBaseline: tickLabelStyle?.dominantBaseline,
13
+ isRtl
14
+ };
15
+ const svgHeight = drawingArea.top + drawingArea.height + drawingArea.bottom;
27
16
  for (const item of visibleLabels) {
28
17
  if (item.formattedValue) {
29
- // That maximum height of the tick depends on its proximity to the axis bounds.
30
- const height = Math.min((item.offset + item.labelOffset) * topBoundFactor, (drawingArea.top + drawingArea.height + drawingArea.bottom - item.offset - item.labelOffset) * bottomBoundFactor);
31
- const doesTextFit = text => doesTextFitInRect(text, {
32
- width: maxWidth,
33
- height,
34
- angle,
35
- measureText: string => getStringSize(string, tickLabelStyle)
36
- });
18
+ // The label is anchored on the tick, so how far it can extend vertically depends on the
19
+ // proximity of the tick to the SVG bounds.
20
+ const anchor = item.offset + item.labelOffset;
21
+ const spaceAbove = anchor;
22
+ const spaceBelow = svgHeight - anchor;
23
+ const doesTextFit = text => {
24
+ const bounds = getRotatedTextBounds(getStringSize(text, tickLabelStyle), boundsConfig);
25
+ return bounds.width <= maxWidth && bounds.above <= spaceAbove && bounds.below <= spaceBelow;
26
+ };
37
27
  shortenedLabels.set(item, ellipsize(item.formattedValue.toString(), doesTextFit));
38
28
  }
39
29
  }
@@ -16,6 +16,7 @@ var _useAxis = require("../hooks/useAxis");
16
16
  var _defaultTextPlacement = require("../ChartsText/defaultTextPlacement");
17
17
  var _invertTextAnchor = require("../internals/invertTextAnchor");
18
18
  var _utilities = require("./utilities");
19
+ var _constants = require("../constants");
19
20
  const _excluded = ["scale", "tickNumber", "reverse"];
20
21
  function useAxisTicksProps(inProps) {
21
22
  const {
@@ -45,7 +46,7 @@ function useAxisTicksProps(inProps) {
45
46
  const isRtl = (0, _RtlProvider.useRtl)();
46
47
  const classes = (0, _utilities.useUtilityClasses)(defaultizedProps);
47
48
  const positionSign = position === 'right' ? 1 : -1;
48
- const tickFontSize = typeof tickLabelStyle?.fontSize === 'number' ? tickLabelStyle.fontSize : 12;
49
+ const tickFontSize = typeof tickLabelStyle?.fontSize === 'number' ? tickLabelStyle.fontSize : _constants.DEFAULT_TICK_LABEL_FONT_SIZE;
49
50
  const Tick = slots?.axisTick ?? 'line';
50
51
  const TickLabel = slots?.axisTickLabel ?? _ChartsText.ChartsText;
51
52
  const defaultTextAnchor = (0, _defaultTextPlacement.getDefaultTextAnchor)((position === 'right' ? -90 : 90) - (tickLabelStyle?.angle ?? 0));
@@ -11,6 +11,7 @@ import { useYAxes } from "../hooks/useAxis.mjs";
11
11
  import { getDefaultBaseline, getDefaultTextAnchor } from "../ChartsText/defaultTextPlacement.mjs";
12
12
  import { invertTextAnchor } from "../internals/invertTextAnchor.mjs";
13
13
  import { defaultProps, useUtilityClasses } from "./utilities.mjs";
14
+ import { DEFAULT_TICK_LABEL_FONT_SIZE } from "../constants/index.mjs";
14
15
  export function useAxisTicksProps(inProps) {
15
16
  const {
16
17
  yAxis,
@@ -39,7 +40,7 @@ export function useAxisTicksProps(inProps) {
39
40
  const isRtl = useRtl();
40
41
  const classes = useUtilityClasses(defaultizedProps);
41
42
  const positionSign = position === 'right' ? 1 : -1;
42
- const tickFontSize = typeof tickLabelStyle?.fontSize === 'number' ? tickLabelStyle.fontSize : 12;
43
+ const tickFontSize = typeof tickLabelStyle?.fontSize === 'number' ? tickLabelStyle.fontSize : DEFAULT_TICK_LABEL_FONT_SIZE;
43
44
  const Tick = slots?.axisTick ?? 'line';
44
45
  const TickLabel = slots?.axisTickLabel ?? ChartsText;
45
46
  const defaultTextAnchor = getDefaultTextAnchor((position === 'right' ? -90 : 90) - (tickLabelStyle?.angle ?? 0));
@@ -282,7 +282,7 @@ process.env.NODE_ENV !== "production" ? LineChart.propTypes /* remove-proptypes
282
282
  /**
283
283
  * The function called for onClick events.
284
284
  * The second argument contains information about all line/bar elements at the current mouse position.
285
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
285
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
286
286
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
287
287
  */
288
288
  onAxisClick: _propTypes.default.func,
@@ -275,7 +275,7 @@ process.env.NODE_ENV !== "production" ? LineChart.propTypes /* remove-proptypes
275
275
  /**
276
276
  * The function called for onClick events.
277
277
  * The second argument contains information about all line/bar elements at the current mouse position.
278
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
278
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
279
279
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
280
280
  */
281
281
  onAxisClick: PropTypes.func,
@@ -18,6 +18,7 @@ var _useInteractionItemProps = require("../hooks/useInteractionItemProps");
18
18
  var _useChartExperimentalFeature = require("../internals/plugins/corePlugins/useChartExperimentalFeature");
19
19
  var _useStore = require("../internals/store/useStore");
20
20
  var _getSymbol = require("../internals/getSymbol");
21
+ var _useAnimateMark = require("../hooks/animation/useAnimateMark");
21
22
  var _lineClasses = require("./lineClasses");
22
23
  var _jsxRuntime = require("react/jsx-runtime");
23
24
  const _excluded = ["x", "y", "seriesId", "classes", "color", "shape", "dataIndex", "onClick", "skipAnimation", "isFaded", "isHighlighted", "hidden", "style"];
@@ -30,7 +31,8 @@ const MarkElementPath = (0, _styles.styled)('path', {
30
31
  fill: (theme.vars || theme).palette.background.paper,
31
32
  [`&.${_lineClasses.lineClasses.markAnimate}`]: {
32
33
  transitionDuration: `${_animation.ANIMATION_DURATION_MS}ms`,
33
- transitionProperty: 'transform, transform-origin, opacity',
34
+ // The position is animated in JS by `useAnimateMark`: Safari cannot transition the `transform` attribute.
35
+ transitionProperty: 'opacity',
34
36
  transitionTimingFunction: _animation.ANIMATION_TIMING_FUNCTION
35
37
  }
36
38
  }));
@@ -79,11 +81,16 @@ function MarkElement(props) {
79
81
  skipAnimation,
80
82
  classes: innerClasses
81
83
  });
82
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(MarkElementPath, (0, _extends2.default)({}, other, enablePositionBasedPointerInteraction ? {} : interactionProps, {
83
- style: (0, _extends2.default)({}, style, {
84
- transform: `translate(${x}px, ${y}px)`,
85
- transformOrigin: `${x}px ${y}px`
86
- }),
84
+
85
+ // Positions the mark with the `transform` attribute, in `viewBox` units. A CSS `px` transform lands in the wrong
86
+ // place in Safari under browser zoom, see https://github.com/mui/mui-x/issues/23377
87
+ const animatedProps = (0, _useAnimateMark.useAnimateMark)({
88
+ x: Number(x),
89
+ y: Number(y),
90
+ skipAnimation
91
+ });
92
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(MarkElementPath, (0, _extends2.default)({}, other, enablePositionBasedPointerInteraction ? {} : interactionProps, animatedProps, {
93
+ style: style,
87
94
  ownerState: ownerState,
88
95
  className: classes.mark,
89
96
  d: (0, _d3Shape.symbol)(_d3Shape.symbolsFill[(0, _getSymbol.getSymbol)(shape)])(),
@@ -12,6 +12,7 @@ import { useInteractionItemProps } from "../hooks/useInteractionItemProps.mjs";
12
12
  import { selectorChartExperimentalFeaturesState } from "../internals/plugins/corePlugins/useChartExperimentalFeature/index.mjs";
13
13
  import { useStore } from "../internals/store/useStore.mjs";
14
14
  import { getSymbol } from "../internals/getSymbol.mjs";
15
+ import { useAnimateMark } from "../hooks/animation/useAnimateMark.mjs";
15
16
  import { lineClasses, useUtilityClasses as useLineUtilityClasses } from "./lineClasses.mjs";
16
17
  import { jsx as _jsx } from "react/jsx-runtime";
17
18
  const MarkElementPath = styled('path', {
@@ -23,7 +24,8 @@ const MarkElementPath = styled('path', {
23
24
  fill: (theme.vars || theme).palette.background.paper,
24
25
  [`&.${lineClasses.markAnimate}`]: {
25
26
  transitionDuration: `${ANIMATION_DURATION_MS}ms`,
26
- transitionProperty: 'transform, transform-origin, opacity',
27
+ // The position is animated in JS by `useAnimateMark`: Safari cannot transition the `transform` attribute.
28
+ transitionProperty: 'opacity',
27
29
  transitionTimingFunction: ANIMATION_TIMING_FUNCTION
28
30
  }
29
31
  }));
@@ -72,11 +74,16 @@ function MarkElement(props) {
72
74
  skipAnimation,
73
75
  classes: innerClasses
74
76
  });
75
- return /*#__PURE__*/_jsx(MarkElementPath, _extends({}, other, enablePositionBasedPointerInteraction ? {} : interactionProps, {
76
- style: _extends({}, style, {
77
- transform: `translate(${x}px, ${y}px)`,
78
- transformOrigin: `${x}px ${y}px`
79
- }),
77
+
78
+ // Positions the mark with the `transform` attribute, in `viewBox` units. A CSS `px` transform lands in the wrong
79
+ // place in Safari under browser zoom, see https://github.com/mui/mui-x/issues/23377
80
+ const animatedProps = useAnimateMark({
81
+ x: Number(x),
82
+ y: Number(y),
83
+ skipAnimation
84
+ });
85
+ return /*#__PURE__*/_jsx(MarkElementPath, _extends({}, other, enablePositionBasedPointerInteraction ? {} : interactionProps, animatedProps, {
86
+ style: style,
80
87
  ownerState: ownerState,
81
88
  className: classes.mark,
82
89
  d: d3Symbol(d3SymbolsFill[getSymbol(shape)])(),
@@ -5,11 +5,11 @@ interface GetLabelAttributesParams extends Required<Pick<RadarAxisProps, 'labelO
5
5
  angle: number;
6
6
  }
7
7
  export declare function getLabelAttributes(params: GetLabelAttributesParams): {
8
+ transform?: undefined;
8
9
  x: number;
9
10
  y: number;
10
11
  textAnchor: "end" | "inherit" | "middle" | "start" | undefined;
11
12
  dominantBaseline: "alphabetic" | "auto" | "central" | "hanging" | "ideographic" | "inherit" | "mathematical" | "middle" | "no-change" | "reset-size" | "text-after-edge" | "text-before-edge" | "use-script" | undefined;
12
- transform?: undefined;
13
13
  } | {
14
14
  x: number;
15
15
  y: number;
@@ -5,11 +5,11 @@ interface GetLabelAttributesParams extends Required<Pick<RadarAxisProps, 'labelO
5
5
  angle: number;
6
6
  }
7
7
  export declare function getLabelAttributes(params: GetLabelAttributesParams): {
8
+ transform?: undefined;
8
9
  x: number;
9
10
  y: number;
10
11
  textAnchor: "end" | "inherit" | "middle" | "start" | undefined;
11
12
  dominantBaseline: "alphabetic" | "auto" | "central" | "hanging" | "ideographic" | "inherit" | "mathematical" | "middle" | "no-change" | "reset-size" | "text-after-edge" | "text-before-edge" | "use-script" | undefined;
12
- transform?: undefined;
13
13
  } | {
14
14
  x: number;
15
15
  y: number;
@@ -231,7 +231,7 @@ process.env.NODE_ENV !== "production" ? RadarChart.propTypes /* remove-proptypes
231
231
  /**
232
232
  * The function called for onClick events.
233
233
  * The second argument contains information about all line/bar elements at the current mouse position.
234
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
234
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
235
235
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
236
236
  */
237
237
  onAxisClick: _propTypes.default.func,
@@ -224,7 +224,7 @@ process.env.NODE_ENV !== "production" ? RadarChart.propTypes /* remove-proptypes
224
224
  /**
225
225
  * The function called for onClick events.
226
226
  * The second argument contains information about all line/bar elements at the current mouse position.
227
- * @param {MouseEvent} event The mouse event recorded on the `<svg/>` element.
227
+ * @param {ChartsActivationEvent} event The event recorded on the `<svg/>` element.
228
228
  * @param {null | ChartsAxisData} data The data about the clicked axis and items associated with it.
229
229
  */
230
230
  onAxisClick: PropTypes.func,
@@ -14,6 +14,7 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
14
14
  var _useRadarSeriesData = require("./useRadarSeriesData");
15
15
  var _radarClasses = require("../radarClasses");
16
16
  var _useItemHighlightStateGetter = require("../../hooks/useItemHighlightStateGetter");
17
+ var _useInteractionAllItemProps = require("./useInteractionAllItemProps");
17
18
  var _useRegisterRadarItemActivation = require("./useRegisterRadarItemActivation");
18
19
  var _jsxRuntime = require("react/jsx-runtime");
19
20
  const _excluded = ["seriesId", "onItemClick", "classes"];
@@ -54,6 +55,9 @@ function RadarSeriesMarks(props) {
54
55
  const seriesCoordinates = (0, _useRadarSeriesData.useRadarSeriesData)(props.seriesId);
55
56
  const classes = (0, _radarClasses.useUtilityClasses)(inClasses);
56
57
  const getHighlightState = (0, _useItemHighlightStateGetter.useItemHighlightStateGetter)();
58
+ // Clickable marks cover the area, so they report the series the same way it does. The index
59
+ // still comes from the rotation axis, which is why the identifier stays series-level.
60
+ const interactionProps = (0, _useInteractionAllItemProps.useInteractionAllItemProps)(seriesCoordinates);
57
61
  (0, _useRegisterRadarItemActivation.useRegisterRadarItemActivation)(seriesId, onItemClick, _useRegisterRadarItemActivation.RADAR_ACTIVATION_PRIORITY.mark);
58
62
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(React.Fragment, {
59
63
  children: seriesCoordinates?.map(({
@@ -62,7 +66,7 @@ function RadarSeriesMarks(props) {
62
66
  hideMark,
63
67
  fillArea,
64
68
  hidden
65
- }) => {
69
+ }, seriesIndex) => {
66
70
  if (hideMark || hidden) {
67
71
  return null;
68
72
  }
@@ -83,7 +87,7 @@ function RadarSeriesMarks(props) {
83
87
  dataIndex: index
84
88
  }),
85
89
  cursor: onItemClick ? 'pointer' : 'unset'
86
- }, other), index))
90
+ }, interactionProps[seriesIndex], other), index))
87
91
  }, id);
88
92
  })
89
93
  });
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
6
6
  import { useRadarSeriesData } from "./useRadarSeriesData.mjs";
7
7
  import { useUtilityClasses } from "../radarClasses.mjs";
8
8
  import { useItemHighlightStateGetter } from "../../hooks/useItemHighlightStateGetter.mjs";
9
+ import { useInteractionAllItemProps } from "./useInteractionAllItemProps.mjs";
9
10
  import { RADAR_ACTIVATION_PRIORITY, useRegisterRadarItemActivation } from "./useRegisterRadarItemActivation.mjs";
10
11
  import { jsx as _jsx } from "react/jsx-runtime";
11
12
  export function getCircleProps(params) {
@@ -45,6 +46,9 @@ function RadarSeriesMarks(props) {
45
46
  const seriesCoordinates = useRadarSeriesData(props.seriesId);
46
47
  const classes = useUtilityClasses(inClasses);
47
48
  const getHighlightState = useItemHighlightStateGetter();
49
+ // Clickable marks cover the area, so they report the series the same way it does. The index
50
+ // still comes from the rotation axis, which is why the identifier stays series-level.
51
+ const interactionProps = useInteractionAllItemProps(seriesCoordinates);
48
52
  useRegisterRadarItemActivation(seriesId, onItemClick, RADAR_ACTIVATION_PRIORITY.mark);
49
53
  return /*#__PURE__*/_jsx(React.Fragment, {
50
54
  children: seriesCoordinates?.map(({
@@ -53,7 +57,7 @@ function RadarSeriesMarks(props) {
53
57
  hideMark,
54
58
  fillArea,
55
59
  hidden
56
- }) => {
60
+ }, seriesIndex) => {
57
61
  if (hideMark || hidden) {
58
62
  return null;
59
63
  }
@@ -74,7 +78,7 @@ function RadarSeriesMarks(props) {
74
78
  dataIndex: index
75
79
  }),
76
80
  cursor: onItemClick ? 'pointer' : 'unset'
77
- }, other), index))
81
+ }, interactionProps[seriesIndex], other), index))
78
82
  }, id);
79
83
  })
80
84
  });
@@ -66,13 +66,14 @@ function RadarSeriesPlot(props) {
66
66
  getHighlightState,
67
67
  classes
68
68
  }), {
69
+ pointerEvents: onMarkClick ? undefined : 'none',
69
70
  onClick: event => onMarkClick?.(event, {
70
71
  type: 'radar',
71
72
  seriesId,
72
73
  dataIndex: index
73
74
  }),
74
75
  cursor: onMarkClick ? 'pointer' : 'unset'
75
- }), index))]
76
+ }, interactionProps[seriesIndex]), index))]
76
77
  }, seriesId);
77
78
  })
78
79
  });
@@ -59,13 +59,14 @@ function RadarSeriesPlot(props) {
59
59
  getHighlightState,
60
60
  classes
61
61
  }), {
62
+ pointerEvents: onMarkClick ? undefined : 'none',
62
63
  onClick: event => onMarkClick?.(event, {
63
64
  type: 'radar',
64
65
  seriesId,
65
66
  dataIndex: index
66
67
  }),
67
68
  cursor: onMarkClick ? 'pointer' : 'unset'
68
- }), index))]
69
+ }, interactionProps[seriesIndex]), index))]
69
70
  }, seriesId);
70
71
  })
71
72
  });