@mui/x-charts 9.11.1 → 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 (124) hide show
  1. package/BarChart/BarChart.js +8 -1
  2. package/BarChart/BarChart.mjs +8 -1
  3. package/CHANGELOG.md +278 -0
  4. package/ChartsContainer/ChartsContainer.js +8 -1
  5. package/ChartsContainer/ChartsContainer.mjs +8 -1
  6. package/ChartsContainer/useChartsContainerProps.js +3 -1
  7. package/ChartsContainer/useChartsContainerProps.mjs +3 -1
  8. package/ChartsTooltip/ChartsAxisTooltipContent.js +2 -9
  9. package/ChartsTooltip/ChartsAxisTooltipContent.mjs +2 -9
  10. package/ChartsTooltip/ChartsItemTooltipContent.js +2 -2
  11. package/ChartsTooltip/ChartsItemTooltipContent.mjs +2 -2
  12. package/ChartsTooltip/ChartsTooltipContainer.js +6 -2
  13. package/ChartsTooltip/ChartsTooltipContainer.mjs +6 -2
  14. package/ChartsXAxis/useAxisTicksProps.js +2 -1
  15. package/ChartsXAxis/useAxisTicksProps.mjs +2 -1
  16. package/ChartsYAxis/shortenLabels.js +16 -26
  17. package/ChartsYAxis/shortenLabels.mjs +17 -27
  18. package/ChartsYAxis/useAxisTicksProps.js +2 -1
  19. package/ChartsYAxis/useAxisTicksProps.mjs +2 -1
  20. package/LineChart/CircleMarkElement.js +0 -4
  21. package/LineChart/CircleMarkElement.mjs +0 -4
  22. package/LineChart/LineChart.js +8 -1
  23. package/LineChart/LineChart.mjs +8 -1
  24. package/LineChart/MarkElement.js +13 -6
  25. package/LineChart/MarkElement.mjs +13 -6
  26. package/PieChart/PieChart.js +7 -0
  27. package/PieChart/PieChart.mjs +7 -0
  28. package/RadarChart/RadarChart.js +8 -1
  29. package/RadarChart/RadarChart.mjs +8 -1
  30. package/RadarChart/RadarSeriesPlot/RadarSeriesMarks.js +6 -2
  31. package/RadarChart/RadarSeriesPlot/RadarSeriesMarks.mjs +6 -2
  32. package/RadarChart/RadarSeriesPlot/RadarSeriesPlot.js +2 -1
  33. package/RadarChart/RadarSeriesPlot/RadarSeriesPlot.mjs +2 -1
  34. package/RadarChart/useRadarChartProps.js +3 -1
  35. package/RadarChart/useRadarChartProps.mjs +3 -1
  36. package/ScatterChart/ScatterChart.js +8 -1
  37. package/ScatterChart/ScatterChart.mjs +8 -1
  38. package/SparkLineChart/SparkLineChart.js +8 -1
  39. package/SparkLineChart/SparkLineChart.mjs +8 -1
  40. package/constants/index.d.mts +3 -1
  41. package/constants/index.d.ts +3 -1
  42. package/constants/index.js +5 -2
  43. package/constants/index.mjs +4 -1
  44. package/hooks/animation/index.d.mts +1 -0
  45. package/hooks/animation/index.d.ts +1 -0
  46. package/hooks/animation/index.js +11 -0
  47. package/hooks/animation/index.mjs +1 -0
  48. package/hooks/animation/useAnimateMark.d.mts +25 -0
  49. package/hooks/animation/useAnimateMark.d.ts +25 -0
  50. package/hooks/animation/useAnimateMark.js +45 -0
  51. package/hooks/animation/useAnimateMark.mjs +39 -0
  52. package/hooks/useInteractionItemProps.js +4 -0
  53. package/hooks/useInteractionItemProps.mjs +4 -0
  54. package/index.js +1 -1
  55. package/index.mjs +1 -1
  56. package/internals/components/ChartsAccessibilityProxy/ChartsAccessibilityProxy.js +13 -3
  57. package/internals/components/ChartsAccessibilityProxy/ChartsAccessibilityProxy.mjs +12 -3
  58. package/internals/components/ChartsAccessibilityProxy/focusAccessibilityProxy.d.mts +8 -0
  59. package/internals/components/ChartsAccessibilityProxy/focusAccessibilityProxy.d.ts +8 -0
  60. package/internals/components/ChartsAccessibilityProxy/focusAccessibilityProxy.js +25 -0
  61. package/internals/components/ChartsAccessibilityProxy/focusAccessibilityProxy.mjs +19 -0
  62. package/internals/components/ChartsAccessibilityProxy/index.d.mts +2 -1
  63. package/internals/components/ChartsAccessibilityProxy/index.d.ts +2 -1
  64. package/internals/components/ChartsAccessibilityProxy/index.js +11 -0
  65. package/internals/components/ChartsAccessibilityProxy/index.mjs +2 -1
  66. package/internals/domUtils.js +17 -16
  67. package/internals/domUtils.mjs +17 -15
  68. package/internals/ellipsize.d.mts +30 -0
  69. package/internals/ellipsize.d.ts +30 -0
  70. package/internals/ellipsize.js +60 -0
  71. package/internals/ellipsize.mjs +59 -0
  72. package/internals/index.d.mts +1 -0
  73. package/internals/index.d.ts +1 -0
  74. package/internals/index.js +8 -0
  75. package/internals/index.mjs +1 -0
  76. package/internals/plugins/corePlugins/useChartElementRef/useChartElementRef.js +3 -1
  77. package/internals/plugins/corePlugins/useChartElementRef/useChartElementRef.mjs +3 -1
  78. package/internals/plugins/corePlugins/useChartElementRef/useChartElementRef.types.d.mts +5 -0
  79. package/internals/plugins/corePlugins/useChartElementRef/useChartElementRef.types.d.ts +5 -0
  80. package/internals/plugins/featurePlugins/shared/useRegisterPointerInteractions.js +10 -0
  81. package/internals/plugins/featurePlugins/shared/useRegisterPointerInteractions.mjs +10 -0
  82. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.d.mts +3 -0
  83. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.d.ts +3 -0
  84. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.js +9 -5
  85. package/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisAutoSize.mjs +9 -5
  86. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartAxisAutoSize.selectors.js +9 -4
  87. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartAxisAutoSize.selectors.mjs +9 -4
  88. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.js +75 -3
  89. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.mjs +76 -3
  90. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.types.d.mts +6 -2
  91. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.types.d.ts +6 -2
  92. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisLayout.selectors.d.mts +1 -0
  93. package/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisLayout.selectors.d.ts +1 -0
  94. package/internals/plugins/featurePlugins/useChartClosestPoint/useChartClosestPoint.js +22 -0
  95. package/internals/plugins/featurePlugins/useChartClosestPoint/useChartClosestPoint.mjs +22 -0
  96. package/internals/plugins/featurePlugins/useChartInteraction/useChartInteraction.js +27 -1
  97. package/internals/plugins/featurePlugins/useChartInteraction/useChartInteraction.mjs +27 -1
  98. package/internals/plugins/featurePlugins/useChartInteraction/useChartInteraction.types.d.mts +20 -0
  99. package/internals/plugins/featurePlugins/useChartInteraction/useChartInteraction.types.d.ts +20 -0
  100. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.js +242 -35
  101. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.mjs +244 -36
  102. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.selectors.d.mts +3 -0
  103. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.selectors.d.ts +3 -0
  104. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.selectors.js +12 -5
  105. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.selectors.mjs +11 -4
  106. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.types.d.mts +29 -0
  107. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/useChartKeyboardNavigation.types.d.ts +29 -0
  108. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtAxisPosition.d.mts +28 -0
  109. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtAxisPosition.d.ts +28 -0
  110. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtAxisPosition.js +81 -0
  111. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtAxisPosition.mjs +76 -0
  112. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.d.mts +18 -0
  113. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.d.ts +18 -0
  114. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.js +65 -0
  115. package/internals/plugins/featurePlugins/useChartKeyboardNavigation/utils/getItemAtRotationIndex.mjs +60 -0
  116. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.js +43 -1
  117. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.mjs +43 -1
  118. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.types.d.mts +3 -2
  119. package/internals/plugins/featurePlugins/useChartPolarAxis/useChartPolarAxis.types.d.ts +3 -2
  120. package/internals/useDefaultTickLabelStyle.d.mts +7 -0
  121. package/internals/useDefaultTickLabelStyle.d.ts +7 -0
  122. package/internals/useDefaultTickLabelStyle.js +34 -0
  123. package/internals/useDefaultTickLabelStyle.mjs +28 -0
  124. package/package.json +6 -6
@@ -3,18 +3,187 @@
3
3
  import _extends from "@babel/runtime/helpers/esm/extends";
4
4
  import * as React from 'react';
5
5
  import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
6
+ import useEventCallback from '@mui/utils/useEventCallback';
7
+ import { fastObjectShallowCompare } from '@mui/x-internals/fastObjectShallowCompare';
6
8
  import { selectorChartDefaultizedSeries } from "../../corePlugins/useChartSeries/useChartSeries.selectors.mjs";
7
9
  import { selectorChartSeriesConfig } from "../../corePlugins/useChartSeriesConfig/index.mjs";
10
+ import { cleanIdentifier } from "../../corePlugins/useChartSeriesConfig/utils/cleanIdentifier.mjs";
11
+ import { focusAccessibilityProxy } from "../../../components/ChartsAccessibilityProxy/focusAccessibilityProxy.mjs";
12
+ import { selectorChartSeriesProcessed } from "../../corePlugins/useChartSeries/index.mjs";
13
+ import { selectorChartXAxis, selectorChartYAxis } from "../useChartCartesianAxis/useChartCartesianAxisRendering.selectors.mjs";
14
+ import { getChartPoint } from "../../../getChartPoint.mjs";
15
+ import { getItemAtAxisPosition } from "./utils/getItemAtAxisPosition.mjs";
16
+ import { getItemAtRotationIndex } from "./utils/getItemAtRotationIndex.mjs";
17
+ import { selectorChartRotationAxis } from "../useChartPolarAxis/useChartPolarAxis.selectors.mjs";
18
+ import { selectorChartsInteractionRotationAxisIndex } from "../useChartPolarAxis/useChartPolarInteraction.selectors.mjs";
8
19
  import { findItemActivationHandler, isItemActivationKey } from "./itemActivation.mjs";
9
- import { selectorChartsIsKeyboardActivationEnabled } from "./useChartKeyboardNavigation.selectors.mjs";
20
+ import { selectorChartsIsFocusVisible, selectorChartsIsKeyboardActivationEnabled } from "./useChartKeyboardNavigation.selectors.mjs";
21
+
22
+ /**
23
+ * Identifier cleaners always emit every key their series type uses, leaving the missing ones
24
+ * `undefined`. A line or area path only knows its series, so it produces a `dataIndex`-less
25
+ * identifier that can not be focused.
26
+ */
27
+ function isCompleteFocusIdentifier(identifier) {
28
+ return Object.values(identifier).every(value => value !== undefined);
29
+ }
10
30
  export const useChartKeyboardNavigation = ({
11
31
  params,
12
32
  store,
13
33
  instance
14
34
  }) => {
15
35
  const {
16
- chartsLayerContainerRef
36
+ chartsLayerContainerRef,
37
+ chartsAccessibilityProxyRef
17
38
  } = instance;
39
+
40
+ /**
41
+ * Whether the next focus change should render the focus.
42
+ * Pointer interactions set it to `false` so that clicking an item sets the item keyboard
43
+ * navigation resumes from, without revealing the focus indicator.
44
+ */
45
+ const focusVisibleIntentRef = React.useRef(true);
46
+
47
+ /**
48
+ * Whether the last interaction came from the keyboard.
49
+ * Only then do the highlight and the tooltip follow the focused item: after a click the pointer
50
+ * is still on the chart, and they must keep following it.
51
+ */
52
+ const isKeyboardModalityRef = React.useRef(true);
53
+
54
+ /**
55
+ * The item a tap resolved, waiting for the click to focus it.
56
+ *
57
+ * The two steps cannot be merged. Touch clears the pointer item on `pointerleave`, right after
58
+ * the tap, so the item has to be read early. But touch also emits its compatibility `mousedown`
59
+ * after that, which moves the focus to the body, so the focus has to be taken late, on the click
60
+ * that closes the sequence.
61
+ */
62
+ const pendingFocusItemRef = React.useRef(null);
63
+
64
+ /**
65
+ * Writes the focus state, only switching the highlight and tooltip to keyboard when visible.
66
+ * An `undefined` item leaves the focused item untouched, `null` clears it.
67
+ *
68
+ * `isFocused` is read from the DOM rather than assumed: a composition may not render the
69
+ * accessibility proxy, and claiming a focus the chart does not hold would render an indicator
70
+ * that no blur can ever clear. The item is still stored, so it is restored on the next focus.
71
+ */
72
+ const updateFocus = useEventCallback((item, isFocusVisible) => {
73
+ const keyboardNavigation = store.state.keyboardNavigation;
74
+ const isFocused = chartsLayerContainerRef.current?.contains(document.activeElement) ?? false;
75
+ // Only the keyboard hands the highlight and the tooltip over to the focused item. A click
76
+ // moves the focus, but the pointer is still there and they must keep following it.
77
+ const followsFocus = isFocused && isFocusVisible && isKeyboardModalityRef.current;
78
+ store.update(_extends({}, followsFocus && store.state.highlight && {
79
+ highlight: _extends({}, store.state.highlight, {
80
+ lastUpdate: 'keyboard'
81
+ })
82
+ }, followsFocus && store.state.interaction && {
83
+ interaction: _extends({}, store.state.interaction, {
84
+ lastUpdate: 'keyboard'
85
+ })
86
+ }, {
87
+ keyboardNavigation: _extends({}, keyboardNavigation, item !== undefined && {
88
+ item
89
+ }, {
90
+ isFocused,
91
+ isFocusVisible: isFocused && isFocusVisible
92
+ })
93
+ }));
94
+ });
95
+
96
+ /**
97
+ * Moves the DOM focus into the chart and writes the focus state.
98
+ * An `undefined` item focuses the chart without changing the focused item.
99
+ * @returns `true` when the state changed.
100
+ */
101
+ const applyFocus = useEventCallback((item, options) => {
102
+ if (!store.state.keyboardNavigation.enabled) {
103
+ return false;
104
+ }
105
+ const isFocusVisible = options?.visible ?? focusVisibleIntentRef.current;
106
+ focusVisibleIntentRef.current = isFocusVisible;
107
+ const container = chartsLayerContainerRef.current;
108
+ if (!container?.contains(document.activeElement)) {
109
+ // Focusing fires `focusin` synchronously, which runs `restoreFocus` with the intent above.
110
+ focusAccessibilityProxy(chartsAccessibilityProxyRef.current);
111
+ }
112
+
113
+ // Read after focusing, `restoreFocus` already ran.
114
+ const keyboardNavigation = store.state.keyboardNavigation;
115
+ const isSameItem = item === undefined || keyboardNavigation.item != null && fastObjectShallowCompare(keyboardNavigation.item, item);
116
+ if (keyboardNavigation.isFocused && keyboardNavigation.isFocusVisible === isFocusVisible && isSameItem) {
117
+ // Nothing to do: two click paths can resolve the same item, a line mark over its line.
118
+ return false;
119
+ }
120
+ updateFocus(item, isFocusVisible);
121
+ return true;
122
+ });
123
+ const focusItem = useEventCallback((item, options) => {
124
+ const seriesConfig = selectorChartSeriesConfig(store.state);
125
+ if (!seriesConfig[item.type]?.keyboardFocusHandler) {
126
+ // The series type is not part of the keyboard navigation.
127
+ return false;
128
+ }
129
+ const cleanedItem = cleanIdentifier(seriesConfig, item);
130
+ if (!isCompleteFocusIdentifier(cleanedItem)) {
131
+ return false;
132
+ }
133
+ return applyFocus(cleanedItem, options);
134
+ });
135
+
136
+ /**
137
+ * The item a click landed on, read from the item the pointer is over. An area or line path only
138
+ * knows its series, and a radar reports no item at all, so an incomplete one falls back to the
139
+ * axis under the pointer.
140
+ *
141
+ * A click that resolves nothing is left alone rather than focusing the chart. The drawing area
142
+ * is a rectangle, but the data rarely fills it: taking the focus from a click next to a pie,
143
+ * outside its circle, reads as the chart grabbing clicks that were not meant for it.
144
+ */
145
+ const resolveItemAtPointer = useEventCallback(event => {
146
+ const seriesConfig = selectorChartSeriesConfig(store.state);
147
+ const hoveredItem = store.state.interaction?.hoveredItem;
148
+ // Cleaned before the check, because what a series stores is not always an identifier: the
149
+ // scatter reports its whole data point, whose optional `id` would read as an incomplete one.
150
+ const cleanedHoveredItem = hoveredItem == null ? null : cleanIdentifier(seriesConfig, hoveredItem);
151
+
152
+ // Series that report a complete item need no further wiring.
153
+ if (cleanedHoveredItem != null && isCompleteFocusIdentifier(cleanedHoveredItem)) {
154
+ return cleanedHoveredItem;
155
+ }
156
+ const element = chartsLayerContainerRef.current;
157
+ const point = element === null ? null : getChartPoint(element, event);
158
+ if (!point || !instance.isPointInside?.(point.x, point.y)) {
159
+ return null;
160
+ }
161
+ const processedSeries = selectorChartSeriesProcessed(store.state);
162
+ // An incomplete hovered item still names the series under the pointer, which is a better
163
+ // target than the focused one: a click on a series should stay on it.
164
+ const focusedItem = cleanedHoveredItem ?? store.state.keyboardNavigation.item;
165
+ const item = getItemAtAxisPosition({
166
+ point,
167
+ xAxis: selectorChartXAxis(store.state),
168
+ yAxis: selectorChartYAxis(store.state),
169
+ processedSeries,
170
+ focusedItem
171
+ });
172
+ if (item !== null) {
173
+ return item;
174
+ }
175
+
176
+ // A radar area only covers the polygon the data draws, so a click inside the chart but outside
177
+ // it resolves nothing above. Fall back to the rotation axis, the same one the highlight uses.
178
+ if (selectorChartRotationAxis(store.state).axisIds.length === 0) {
179
+ return null;
180
+ }
181
+ return getItemAtRotationIndex({
182
+ dataIndex: selectorChartsInteractionRotationAxisIndex(store.state),
183
+ processedSeries,
184
+ focusedItem
185
+ });
186
+ });
18
187
  const activationRegistrationsRef = React.useRef(new Map());
19
188
  const nextRegistrationIdRef = React.useRef(0);
20
189
  const registerItemActivationHandler = React.useCallback((scope, handler) => {
@@ -46,34 +215,43 @@ export const useChartKeyboardNavigation = ({
46
215
  }
47
216
  if (store.state.keyboardNavigation.isFocused) {
48
217
  store.set('keyboardNavigation', _extends({}, store.state.keyboardNavigation, {
49
- isFocused: false
218
+ isFocused: false,
219
+ isFocusVisible: false
50
220
  }));
51
221
  }
52
222
  }
223
+
224
+ // The focus already moved into the chart, so `applyFocus` only reconciles the state with the
225
+ // current intent: its own focusing step is a no-op here.
53
226
  function restoreFocus() {
54
- if (!store.state.keyboardNavigation.isFocused) {
55
- store.update(_extends({}, store.state.highlight && {
56
- highlight: _extends({}, store.state.highlight, {
57
- lastUpdate: 'keyboard'
58
- })
59
- }, store.state.interaction && {
60
- interaction: _extends({}, store.state.interaction, {
61
- lastUpdate: 'keyboard'
62
- })
63
- }, {
64
- keyboardNavigation: _extends({}, store.state.keyboardNavigation, {
65
- isFocused: true
66
- })
67
- }));
68
- }
227
+ applyFocus(undefined);
228
+ }
229
+
230
+ // A pointer interaction hides the focus, unless it is already visible or `focusItemOnClick`
231
+ // is set. Read on `pointerdown`, before the click can blur the proxy.
232
+ function trackPointerIntent() {
233
+ // A click keeps the focus visible only if it already was, or if the chart opts in.
234
+ focusVisibleIntentRef.current = params.focusItemOnClick === true || store.state.keyboardNavigation.isFocusVisible;
235
+ isKeyboardModalityRef.current = false;
236
+ pendingFocusItemRef.current = null;
237
+ }
238
+
239
+ // Any key press means the user switched to the keyboard, wherever the focus currently is.
240
+ // Listening on the document also covers tabbing in from outside the chart.
241
+ function trackKeyboardIntent() {
242
+ focusVisibleIntentRef.current = true;
243
+ isKeyboardModalityRef.current = true;
69
244
  }
70
245
  function activationHandler(event) {
71
246
  // Ignore the auto-repeat while the key is held: a pointer click does not repeat either.
72
247
  if (event.repeat || !isItemActivationKey(event) || !selectorChartsIsKeyboardActivationEnabled(store.state)) {
73
248
  return;
74
249
  }
250
+
251
+ // The focus has to be visible, not merely held: a click sets the item without revealing it,
252
+ // and activating an item the user cannot see would be a surprise.
75
253
  const focusedItem = store.state.keyboardNavigation.item;
76
- if (focusedItem === null || !store.state.keyboardNavigation.isFocused) {
254
+ if (focusedItem === null || !selectorChartsIsFocusVisible(store.state)) {
77
255
  return;
78
256
  }
79
257
  const handler = findItemActivationHandler(activationRegistrationsRef.current.values(), focusedItem);
@@ -84,6 +262,11 @@ export const useChartKeyboardNavigation = ({
84
262
  handler(event, focusedItem);
85
263
  }
86
264
  function keyboardHandler(event) {
265
+ // Item navigation only uses unmodified keys.
266
+ // Modified ones are left to the browser, and to chart interactions such as keyboard zoom and pan.
267
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
268
+ return;
269
+ }
87
270
  let newFocusedItem = store.state.keyboardNavigation.item;
88
271
  const seriesConfig = selectorChartSeriesConfig(store.state);
89
272
  let seriesType = newFocusedItem?.type;
@@ -98,34 +281,56 @@ export const useChartKeyboardNavigation = ({
98
281
  return;
99
282
  }
100
283
  newFocusedItem = calculateFocusedItem(newFocusedItem, store.state);
101
- if (newFocusedItem !== store.state.keyboardNavigation.item) {
102
- event.preventDefault();
103
- store.update(_extends({}, store.state.highlight && {
104
- highlight: _extends({}, store.state.highlight, {
105
- lastUpdate: 'keyboard'
106
- })
107
- }, store.state.interaction && {
108
- interaction: _extends({}, store.state.interaction, {
109
- lastUpdate: 'keyboard'
110
- })
111
- }, {
112
- keyboardNavigation: _extends({}, store.state.keyboardNavigation, {
113
- item: newFocusedItem
114
- })
115
- }));
284
+ const keyboardNavigation = store.state.keyboardNavigation;
285
+ // The item does not move at the edges of a series that does not cycle, but the key was still
286
+ // handled, so a focus set by a click must become visible.
287
+ if (newFocusedItem === keyboardNavigation.item && keyboardNavigation.isFocusVisible) {
288
+ return;
116
289
  }
290
+ event.preventDefault();
291
+ updateFocus(newFocusedItem, true);
117
292
  }
118
293
  element.addEventListener('keydown', activationHandler);
119
294
  element.addEventListener('keydown', keyboardHandler);
120
295
  element.addEventListener('focusout', removeFocus);
121
296
  element.addEventListener('focusin', restoreFocus);
297
+ element.addEventListener('pointerdown', trackPointerIntent, true);
298
+ document.addEventListener('keydown', trackKeyboardIntent, true);
122
299
  return () => {
123
300
  element.removeEventListener('keydown', activationHandler);
124
301
  element.removeEventListener('keydown', keyboardHandler);
125
302
  element.removeEventListener('focusout', removeFocus);
126
303
  element.removeEventListener('focusin', restoreFocus);
304
+ element.removeEventListener('pointerdown', trackPointerIntent, true);
305
+ document.removeEventListener('keydown', trackKeyboardIntent, true);
306
+ };
307
+ }, [chartsLayerContainerRef, params.disableKeyboardNavigation, store, updateFocus, applyFocus, params.focusItemOnClick]);
308
+ React.useEffect(() => {
309
+ if (params.disableKeyboardNavigation) {
310
+ return undefined;
311
+ }
312
+ const tapHandler = instance.addInteractionListener?.('tap', event => {
313
+ pendingFocusItemRef.current = resolveItemAtPointer(event.detail.srcEvent);
314
+ });
315
+ function focusPendingItem(event) {
316
+ const item = pendingFocusItemRef.current;
317
+ pendingFocusItemRef.current = null;
318
+
319
+ // A handler stopping the propagation keeps the click from reaching this listener, leaving
320
+ // the item pending. Checking the target stops it from landing on an unrelated later click.
321
+ if (item !== null && chartsLayerContainerRef.current?.contains(event.target)) {
322
+ focusItem(item);
323
+ }
324
+ }
325
+
326
+ // Listens on the document so it runs after the React handlers, which are attached to the
327
+ // React root above the chart container.
328
+ document.addEventListener('click', focusPendingItem);
329
+ return () => {
330
+ tapHandler?.cleanup();
331
+ document.removeEventListener('click', focusPendingItem);
127
332
  };
128
- }, [chartsLayerContainerRef, params.disableKeyboardNavigation, store]);
333
+ }, [instance, params.disableKeyboardNavigation, resolveItemAtPointer, focusItem, chartsLayerContainerRef]);
129
334
  useEnhancedEffect(() => {
130
335
  store.set('keyboardNavigation', _extends({}, store.state.keyboardNavigation, {
131
336
  enabled: !params.disableKeyboardNavigation
@@ -133,6 +338,7 @@ export const useChartKeyboardNavigation = ({
133
338
  }, [store, params.disableKeyboardNavigation]);
134
339
  return {
135
340
  instance: {
341
+ focusItem,
136
342
  registerItemActivationHandler
137
343
  }
138
344
  };
@@ -141,9 +347,11 @@ useChartKeyboardNavigation.getInitialState = params => ({
141
347
  keyboardNavigation: {
142
348
  item: null,
143
349
  isFocused: false,
350
+ isFocusVisible: false,
144
351
  enabled: !params.disableKeyboardNavigation
145
352
  }
146
353
  });
147
354
  useChartKeyboardNavigation.params = {
148
- disableKeyboardNavigation: true
355
+ disableKeyboardNavigation: true,
356
+ focusItemOnClick: true
149
357
  };
@@ -1,5 +1,8 @@
1
1
  import type { FocusedItemIdentifier } from "../../../../models/seriesType/index.mjs";
2
2
  import type { AxisItemIdentifier } from "../../../../models/axis.mjs";
3
+ export declare const selectorChartsIsFocusVisible: (args_0: import("../../corePlugins/useChartId/useChartId.types.mjs").UseChartIdState & import("../../corePlugins/useChartSeriesConfig/useChartSeriesConfig.types.mjs").UseChartSeriesConfigState<keyof import("../../../index.mjs").ChartsSeriesConfig> & import("../../corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.mjs").UseChartExperimentalFeaturesState & import("../../corePlugins/useChartDimensions/useChartDimensions.types.mjs").UseChartDimensionsState & import("../../corePlugins/useChartSeries/useChartSeries.types.mjs").UseChartSeriesState<keyof import("../../../index.mjs").ChartsSeriesConfig> & import("../../corePlugins/useChartAnimation/useChartAnimation.types.mjs").UseChartAnimationState & import("../../../index.mjs").UseChartInteractionListenerState & Partial<import("./useChartKeyboardNavigation.types.mjs").UseChartKeyboardNavigationState> & {
4
+ cacheKey: import("../../models/index.mjs").ChartStateCacheKey;
5
+ }) => boolean;
3
6
  export declare const selectorChartsItemIsFocused: (args_0: import("../../corePlugins/useChartId/useChartId.types.mjs").UseChartIdState & import("../../corePlugins/useChartSeriesConfig/useChartSeriesConfig.types.mjs").UseChartSeriesConfigState<keyof import("../../../index.mjs").ChartsSeriesConfig> & import("../../corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.mjs").UseChartExperimentalFeaturesState & import("../../corePlugins/useChartDimensions/useChartDimensions.types.mjs").UseChartDimensionsState & import("../../corePlugins/useChartSeries/useChartSeries.types.mjs").UseChartSeriesState<keyof import("../../../index.mjs").ChartsSeriesConfig> & import("../../corePlugins/useChartAnimation/useChartAnimation.types.mjs").UseChartAnimationState & import("../../../index.mjs").UseChartInteractionListenerState & Partial<import("./useChartKeyboardNavigation.types.mjs").UseChartKeyboardNavigationState> & {
4
7
  cacheKey: import("../../models/index.mjs").ChartStateCacheKey;
5
8
  }, item: FocusedItemIdentifier<keyof import("../../../index.mjs").ChartsSeriesConfig>) => boolean;
@@ -1,5 +1,8 @@
1
1
  import type { FocusedItemIdentifier } from "../../../../models/seriesType/index.js";
2
2
  import type { AxisItemIdentifier } from "../../../../models/axis.js";
3
+ export declare const selectorChartsIsFocusVisible: (args_0: import("../../corePlugins/useChartId/useChartId.types.js").UseChartIdState & import("../../corePlugins/useChartSeriesConfig/useChartSeriesConfig.types.js").UseChartSeriesConfigState<keyof import("../../../index.js").ChartsSeriesConfig> & import("../../corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.js").UseChartExperimentalFeaturesState & import("../../corePlugins/useChartDimensions/useChartDimensions.types.js").UseChartDimensionsState & import("../../corePlugins/useChartSeries/useChartSeries.types.js").UseChartSeriesState<keyof import("../../../index.js").ChartsSeriesConfig> & import("../../corePlugins/useChartAnimation/useChartAnimation.types.js").UseChartAnimationState & import("../../../index.js").UseChartInteractionListenerState & Partial<import("./useChartKeyboardNavigation.types.js").UseChartKeyboardNavigationState> & {
4
+ cacheKey: import("../../models/index.js").ChartStateCacheKey;
5
+ }) => boolean;
3
6
  export declare const selectorChartsItemIsFocused: (args_0: import("../../corePlugins/useChartId/useChartId.types.js").UseChartIdState & import("../../corePlugins/useChartSeriesConfig/useChartSeriesConfig.types.js").UseChartSeriesConfigState<keyof import("../../../index.js").ChartsSeriesConfig> & import("../../corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.js").UseChartExperimentalFeaturesState & import("../../corePlugins/useChartDimensions/useChartDimensions.types.js").UseChartDimensionsState & import("../../corePlugins/useChartSeries/useChartSeries.types.js").UseChartSeriesState<keyof import("../../../index.js").ChartsSeriesConfig> & import("../../corePlugins/useChartAnimation/useChartAnimation.types.js").UseChartAnimationState & import("../../../index.js").UseChartInteractionListenerState & Partial<import("./useChartKeyboardNavigation.types.js").UseChartKeyboardNavigationState> & {
4
7
  cacheKey: import("../../models/index.js").ChartStateCacheKey;
5
8
  }, item: FocusedItemIdentifier<keyof import("../../../index.js").ChartsSeriesConfig>) => boolean;
@@ -3,15 +3,22 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.selectorChartsKeyboardYAxisIndex = exports.selectorChartsKeyboardXAxisIndex = exports.selectorChartsKeyboardItem = exports.selectorChartsItemIsFocused = exports.selectorChartsIsKeyboardNavigationEnabled = exports.selectorChartsIsKeyboardActivationEnabled = exports.selectorChartsHasFocusedItem = exports.selectorChartsFocusedOrToFocusedItem = exports.selectorChartsFocusedItem = void 0;
6
+ exports.selectorChartsKeyboardYAxisIndex = exports.selectorChartsKeyboardXAxisIndex = exports.selectorChartsKeyboardItem = exports.selectorChartsItemIsFocused = exports.selectorChartsIsKeyboardNavigationEnabled = exports.selectorChartsIsKeyboardActivationEnabled = exports.selectorChartsIsFocusVisible = exports.selectorChartsHasFocusedItem = exports.selectorChartsFocusedOrToFocusedItem = exports.selectorChartsFocusedItem = void 0;
7
7
  var _store = require("@mui/x-internals/store");
8
8
  var _fastObjectShallowCompare = require("@mui/x-internals/fastObjectShallowCompare");
9
9
  var _useChartSeries = require("../../corePlugins/useChartSeries");
10
10
  var _useChartCartesianAxisRendering = require("../useChartCartesianAxis/useChartCartesianAxisRendering.selectors");
11
11
  const selectKeyboardNavigation = state => state.keyboardNavigation;
12
- const selectorChartsItemIsFocused = exports.selectorChartsItemIsFocused = (0, _store.createSelector)(selectKeyboardNavigation, (keyboardNavigationState, item) => keyboardNavigationState?.isFocused === true && keyboardNavigationState?.item != null && (0, _fastObjectShallowCompare.fastObjectShallowCompare)(keyboardNavigationState.item, item));
13
- const selectorChartsHasFocusedItem = exports.selectorChartsHasFocusedItem = (0, _store.createSelector)(selectKeyboardNavigation, keyboardNavigationState => keyboardNavigationState?.isFocused === true && keyboardNavigationState?.item != null);
14
- const selectorChartsFocusedItem = exports.selectorChartsFocusedItem = (0, _store.createSelector)(selectKeyboardNavigation, keyboardNavigationState => keyboardNavigationState?.isFocused === true ? keyboardNavigationState?.item ?? null : null);
12
+
13
+ /**
14
+ * The chart owns the DOM focus AND the focus should be rendered.
15
+ * A pointer-driven focus is `isFocused` without being visible.
16
+ */
17
+ const isFocusVisible = keyboardNavigationState => keyboardNavigationState?.isFocused === true && keyboardNavigationState.isFocusVisible === true;
18
+ const selectorChartsIsFocusVisible = exports.selectorChartsIsFocusVisible = (0, _store.createSelector)(selectKeyboardNavigation, isFocusVisible);
19
+ const selectorChartsItemIsFocused = exports.selectorChartsItemIsFocused = (0, _store.createSelector)(selectKeyboardNavigation, (keyboardNavigationState, item) => isFocusVisible(keyboardNavigationState) && keyboardNavigationState?.item != null && (0, _fastObjectShallowCompare.fastObjectShallowCompare)(keyboardNavigationState.item, item));
20
+ const selectorChartsHasFocusedItem = exports.selectorChartsHasFocusedItem = (0, _store.createSelector)(selectKeyboardNavigation, keyboardNavigationState => isFocusVisible(keyboardNavigationState) && keyboardNavigationState?.item != null);
21
+ const selectorChartsFocusedItem = exports.selectorChartsFocusedItem = (0, _store.createSelector)(selectKeyboardNavigation, keyboardNavigationState => isFocusVisible(keyboardNavigationState) ? keyboardNavigationState?.item ?? null : null);
15
22
 
16
23
  /**
17
24
  * The item that is either
@@ -47,7 +54,7 @@ const createSelectAxisHighlight = direction => (item, axis, series) => {
47
54
  const selectorChartsKeyboardXAxisIndex = exports.selectorChartsKeyboardXAxisIndex = (0, _store.createSelector)(selectorChartsFocusedItem, _useChartCartesianAxisRendering.selectorChartXAxis, _useChartSeries.selectorChartSeriesProcessed, createSelectAxisHighlight('x'));
48
55
  const selectorChartsKeyboardYAxisIndex = exports.selectorChartsKeyboardYAxisIndex = (0, _store.createSelector)(selectorChartsFocusedItem, _useChartCartesianAxisRendering.selectorChartYAxis, _useChartSeries.selectorChartSeriesProcessed, createSelectAxisHighlight('y'));
49
56
  const selectorChartsKeyboardItem = exports.selectorChartsKeyboardItem = (0, _store.createSelectorMemoized)(selectKeyboardNavigation, function selectorChartsKeyboardItem(keyboardState) {
50
- if (keyboardState?.isFocused !== true || keyboardState?.item == null) {
57
+ if (!isFocusVisible(keyboardState) || keyboardState?.item == null) {
51
58
  return null;
52
59
  }
53
60
  const {
@@ -3,9 +3,16 @@ import { fastObjectShallowCompare } from '@mui/x-internals/fastObjectShallowComp
3
3
  import { selectorChartSeriesProcessed } from "../../corePlugins/useChartSeries/index.mjs";
4
4
  import { selectorChartXAxis, selectorChartYAxis } from "../useChartCartesianAxis/useChartCartesianAxisRendering.selectors.mjs";
5
5
  const selectKeyboardNavigation = state => state.keyboardNavigation;
6
- export const selectorChartsItemIsFocused = createSelector(selectKeyboardNavigation, (keyboardNavigationState, item) => keyboardNavigationState?.isFocused === true && keyboardNavigationState?.item != null && fastObjectShallowCompare(keyboardNavigationState.item, item));
7
- export const selectorChartsHasFocusedItem = createSelector(selectKeyboardNavigation, keyboardNavigationState => keyboardNavigationState?.isFocused === true && keyboardNavigationState?.item != null);
8
- export const selectorChartsFocusedItem = createSelector(selectKeyboardNavigation, keyboardNavigationState => keyboardNavigationState?.isFocused === true ? keyboardNavigationState?.item ?? null : null);
6
+
7
+ /**
8
+ * The chart owns the DOM focus AND the focus should be rendered.
9
+ * A pointer-driven focus is `isFocused` without being visible.
10
+ */
11
+ const isFocusVisible = keyboardNavigationState => keyboardNavigationState?.isFocused === true && keyboardNavigationState.isFocusVisible === true;
12
+ export const selectorChartsIsFocusVisible = createSelector(selectKeyboardNavigation, isFocusVisible);
13
+ export const selectorChartsItemIsFocused = createSelector(selectKeyboardNavigation, (keyboardNavigationState, item) => isFocusVisible(keyboardNavigationState) && keyboardNavigationState?.item != null && fastObjectShallowCompare(keyboardNavigationState.item, item));
14
+ export const selectorChartsHasFocusedItem = createSelector(selectKeyboardNavigation, keyboardNavigationState => isFocusVisible(keyboardNavigationState) && keyboardNavigationState?.item != null);
15
+ export const selectorChartsFocusedItem = createSelector(selectKeyboardNavigation, keyboardNavigationState => isFocusVisible(keyboardNavigationState) ? keyboardNavigationState?.item ?? null : null);
9
16
 
10
17
  /**
11
18
  * The item that is either
@@ -41,7 +48,7 @@ const createSelectAxisHighlight = direction => (item, axis, series) => {
41
48
  export const selectorChartsKeyboardXAxisIndex = createSelector(selectorChartsFocusedItem, selectorChartXAxis, selectorChartSeriesProcessed, createSelectAxisHighlight('x'));
42
49
  export const selectorChartsKeyboardYAxisIndex = createSelector(selectorChartsFocusedItem, selectorChartYAxis, selectorChartSeriesProcessed, createSelectAxisHighlight('y'));
43
50
  export const selectorChartsKeyboardItem = createSelectorMemoized(selectKeyboardNavigation, function selectorChartsKeyboardItem(keyboardState) {
44
- if (keyboardState?.isFocused !== true || keyboardState?.item == null) {
51
+ if (!isFocusVisible(keyboardState) || keyboardState?.item == null) {
45
52
  return null;
46
53
  }
47
54
  const {
@@ -4,6 +4,13 @@ import type { UseChartCartesianAxisSignature } from "../useChartCartesianAxis/in
4
4
  import type { UseChartHighlightSignature } from "../useChartHighlight/index.mjs";
5
5
  import type { FocusedItemIdentifier, SeriesId } from "../../../../models/seriesType/index.mjs";
6
6
  import type { ChartSeriesType } from "../../../../models/seriesType/config.mjs";
7
+ export interface FocusItemOptions {
8
+ /**
9
+ * Whether the focus indicator should be rendered.
10
+ * Defaults to `focusItemOnClick || <the focus is already visible>`.
11
+ */
12
+ visible?: boolean;
13
+ }
7
14
  /**
8
15
  * Called when the focused item is activated with the keyboard.
9
16
  * @param {KeyboardEvent} event The keyboard event that triggered the activation.
@@ -32,6 +39,16 @@ export interface ItemActivationScope {
32
39
  canActivate?: (item: FocusedItemIdentifier<ChartSeriesType>) => boolean;
33
40
  }
34
41
  export interface UseChartKeyboardNavigationInstance {
42
+ /**
43
+ * Makes an item the one keyboard navigation starts from, moving the DOM focus into the chart
44
+ * when it is not already there.
45
+ * Does nothing when keyboard navigation is disabled, when the series type does not support it,
46
+ * or when the identifier is not complete enough to be focused.
47
+ * @param {FocusedItemIdentifier} item The item to focus.
48
+ * @param {FocusItemOptions} options Options to override the focus visibility.
49
+ * @returns {boolean} `true` when the focus state was updated.
50
+ */
51
+ focusItem: (item: FocusedItemIdentifier<ChartSeriesType>, options?: FocusItemOptions) => boolean;
35
52
  /**
36
53
  * Registers a handler triggered when the focused item is activated with the keyboard.
37
54
  * Only the handler with the most specific matching scope runs, so plots sharing a series
@@ -52,6 +69,11 @@ export interface UseChartKeyboardNavigationState {
52
69
  * If `false` the focus is ignored, but we keep the item in the state to be able to restore it when focus is active again.
53
70
  */
54
71
  isFocused: boolean;
72
+ /**
73
+ * If `false` the focused item is not rendered as focused, and does not drive the highlight and tooltip.
74
+ * Set when the focus was moved by a pointer instead of the keyboard. Implies `isFocused`.
75
+ */
76
+ isFocusVisible: boolean;
55
77
  /**
56
78
  * Indicates whether keyboard navigation is enabled or not.
57
79
  */
@@ -63,6 +85,13 @@ type UseChartKeyboardNavigationParameters = {
63
85
  * If `true`, disables keyboard navigation for the chart.
64
86
  */
65
87
  disableKeyboardNavigation?: boolean;
88
+ /**
89
+ * If `true`, clicking an item immediately shows the keyboard focus indicator on it.
90
+ * By default, clicking sets the item that keyboard navigation starts from, but the focus
91
+ * indicator stays hidden until the user presses a key.
92
+ * @default false
93
+ */
94
+ focusItemOnClick?: boolean;
66
95
  };
67
96
  export type UseChartKeyboardNavigationSignature = ChartPluginSignature<{
68
97
  params: UseChartKeyboardNavigationParameters;
@@ -4,6 +4,13 @@ import type { UseChartCartesianAxisSignature } from "../useChartCartesianAxis/in
4
4
  import type { UseChartHighlightSignature } from "../useChartHighlight/index.js";
5
5
  import type { FocusedItemIdentifier, SeriesId } from "../../../../models/seriesType/index.js";
6
6
  import type { ChartSeriesType } from "../../../../models/seriesType/config.js";
7
+ export interface FocusItemOptions {
8
+ /**
9
+ * Whether the focus indicator should be rendered.
10
+ * Defaults to `focusItemOnClick || <the focus is already visible>`.
11
+ */
12
+ visible?: boolean;
13
+ }
7
14
  /**
8
15
  * Called when the focused item is activated with the keyboard.
9
16
  * @param {KeyboardEvent} event The keyboard event that triggered the activation.
@@ -32,6 +39,16 @@ export interface ItemActivationScope {
32
39
  canActivate?: (item: FocusedItemIdentifier<ChartSeriesType>) => boolean;
33
40
  }
34
41
  export interface UseChartKeyboardNavigationInstance {
42
+ /**
43
+ * Makes an item the one keyboard navigation starts from, moving the DOM focus into the chart
44
+ * when it is not already there.
45
+ * Does nothing when keyboard navigation is disabled, when the series type does not support it,
46
+ * or when the identifier is not complete enough to be focused.
47
+ * @param {FocusedItemIdentifier} item The item to focus.
48
+ * @param {FocusItemOptions} options Options to override the focus visibility.
49
+ * @returns {boolean} `true` when the focus state was updated.
50
+ */
51
+ focusItem: (item: FocusedItemIdentifier<ChartSeriesType>, options?: FocusItemOptions) => boolean;
35
52
  /**
36
53
  * Registers a handler triggered when the focused item is activated with the keyboard.
37
54
  * Only the handler with the most specific matching scope runs, so plots sharing a series
@@ -52,6 +69,11 @@ export interface UseChartKeyboardNavigationState {
52
69
  * If `false` the focus is ignored, but we keep the item in the state to be able to restore it when focus is active again.
53
70
  */
54
71
  isFocused: boolean;
72
+ /**
73
+ * If `false` the focused item is not rendered as focused, and does not drive the highlight and tooltip.
74
+ * Set when the focus was moved by a pointer instead of the keyboard. Implies `isFocused`.
75
+ */
76
+ isFocusVisible: boolean;
55
77
  /**
56
78
  * Indicates whether keyboard navigation is enabled or not.
57
79
  */
@@ -63,6 +85,13 @@ type UseChartKeyboardNavigationParameters = {
63
85
  * If `true`, disables keyboard navigation for the chart.
64
86
  */
65
87
  disableKeyboardNavigation?: boolean;
88
+ /**
89
+ * If `true`, clicking an item immediately shows the keyboard focus indicator on it.
90
+ * By default, clicking sets the item that keyboard navigation starts from, but the focus
91
+ * indicator stays hidden until the user presses a key.
92
+ * @default false
93
+ */
94
+ focusItemOnClick?: boolean;
66
95
  };
67
96
  export type UseChartKeyboardNavigationSignature = ChartPluginSignature<{
68
97
  params: UseChartKeyboardNavigationParameters;
@@ -0,0 +1,28 @@
1
+ import type { ChartSeriesType } from "../../../../../models/seriesType/config.mjs";
2
+ import type { FocusedItemIdentifier } from "../../../../../models/seriesType/index.mjs";
3
+ import type { ProcessedSeries } from "../../../corePlugins/useChartSeries/useChartSeries.types.mjs";
4
+ import type { ComputeResult } from "../../useChartCartesianAxis/computeAxisValue.mjs";
5
+ import type { ChartsXAxisProps, ChartsYAxisProps } from "../../../../../models/axis.mjs";
6
+ /**
7
+ * Resolves the item a click falls on when it hit no item, by looking at the axis under the
8
+ * pointer. Keeps the focused series when there is one, so clicking the empty space above a bar
9
+ * moves along the series the user was already navigating.
10
+ *
11
+ * Returns `null` for charts without a cartesian axis, and when the axis resolves no index.
12
+ */
13
+ export declare function getItemAtAxisPosition({
14
+ point,
15
+ xAxis,
16
+ yAxis,
17
+ processedSeries,
18
+ focusedItem
19
+ }: {
20
+ point: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ xAxis: ComputeResult<ChartsXAxisProps> | undefined;
25
+ yAxis: ComputeResult<ChartsYAxisProps> | undefined;
26
+ processedSeries: ProcessedSeries<ChartSeriesType>;
27
+ focusedItem: FocusedItemIdentifier<ChartSeriesType> | null;
28
+ }): FocusedItemIdentifier<ChartSeriesType> | null;
@@ -0,0 +1,28 @@
1
+ import type { ChartSeriesType } from "../../../../../models/seriesType/config.js";
2
+ import type { FocusedItemIdentifier } from "../../../../../models/seriesType/index.js";
3
+ import type { ProcessedSeries } from "../../../corePlugins/useChartSeries/useChartSeries.types.js";
4
+ import type { ComputeResult } from "../../useChartCartesianAxis/computeAxisValue.js";
5
+ import type { ChartsXAxisProps, ChartsYAxisProps } from "../../../../../models/axis.js";
6
+ /**
7
+ * Resolves the item a click falls on when it hit no item, by looking at the axis under the
8
+ * pointer. Keeps the focused series when there is one, so clicking the empty space above a bar
9
+ * moves along the series the user was already navigating.
10
+ *
11
+ * Returns `null` for charts without a cartesian axis, and when the axis resolves no index.
12
+ */
13
+ export declare function getItemAtAxisPosition({
14
+ point,
15
+ xAxis,
16
+ yAxis,
17
+ processedSeries,
18
+ focusedItem
19
+ }: {
20
+ point: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ xAxis: ComputeResult<ChartsXAxisProps> | undefined;
25
+ yAxis: ComputeResult<ChartsYAxisProps> | undefined;
26
+ processedSeries: ProcessedSeries<ChartSeriesType>;
27
+ focusedItem: FocusedItemIdentifier<ChartSeriesType> | null;
28
+ }): FocusedItemIdentifier<ChartSeriesType> | null;