From 942fcb5a319f2e2f876dbccc7c67ea049a0b9519 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 28 May 2026 13:42:27 +0200 Subject: [PATCH 01/10] [charts] Add `responsiveTickAdjustment` experimental feature Add an opt-in experimental feature that automatically reduces the number of ticks/tick labels on cartesian axes based on the chart's rendered drawing area, so labels don't pile up on narrow charts. When enabled, ordinal axes (`band` / `point` scales) receive a default `tickSpacing` of 50px derived from the drawing area. Continuous axes are left untouched (their default `tickNumber` is already size-aware via `getDefaultTickNumber`). The feature never overrides explicit `tickNumber`, `tickSpacing`, or `tickInterval` values set by the consumer. Also refactor `selectorChartExperimentalFeaturesState` to accept the feature key as an argument and return that feature's value, instead of returning the whole experimental-features object. --- .../axis-ticks/ResponsiveTickAdjustment.js | 181 ++++++++++++++++++ .../axis-ticks/ResponsiveTickAdjustment.tsx | 181 ++++++++++++++++++ .../ResponsiveTickAdjustment.tsx.preview | 9 + docs/data/charts/axis-ticks/axis-ticks.md | 22 +++ .../x-charts/src/LineChart/AreaElement.tsx | 3 +- .../src/LineChart/CircleMarkElement.tsx | 3 +- .../x-charts/src/LineChart/LineElement.tsx | 3 +- .../x-charts/src/LineChart/MarkElement.tsx | 3 +- .../useChartExperimentalFeature.selectors.ts | 25 ++- .../useChartExperimentalFeature.types.ts | 18 +- .../useChartCartesianAxis/computeAxisValue.ts | 25 +++ .../useChartCartesianAxis.test.tsx | 58 +++++- ...seChartCartesianAxisRendering.selectors.ts | 13 ++ 13 files changed, 533 insertions(+), 11 deletions(-) create mode 100644 docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js create mode 100644 docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx create mode 100644 docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js new file mode 100644 index 0000000000000..f4f7fc7e8d218 --- /dev/null +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js @@ -0,0 +1,181 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Slider from '@mui/material/Slider'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Switch from '@mui/material/Switch'; +import Typography from '@mui/material/Typography'; +import { Chance } from 'chance'; +import { BarChart } from '@mui/x-charts/BarChart'; + +const chance = new Chance(42); + +const produce = [ + 'Apple', + 'Apricot', + 'Artichoke', + 'Arugula', + 'Asparagus', + 'Avocado', + 'Banana', + 'Beet', + 'Bell pepper', + 'Blackberry', + 'Blueberry', + 'Bok choy', + 'Broccoli', + 'Brussels sprout', + 'Cabbage', + 'Cantaloupe', + 'Carrot', + 'Cauliflower', + 'Celery', + 'Cherry', + 'Chickpea', + 'Chili pepper', + 'Clementine', + 'Coconut', + 'Collard greens', + 'Corn', + 'Cranberry', + 'Cucumber', + 'Currant', + 'Date', + 'Dragonfruit', + 'Durian', + 'Edamame', + 'Eggplant', + 'Elderberry', + 'Endive', + 'Fennel', + 'Fig', + 'Garlic', + 'Ginger', + 'Gooseberry', + 'Grape', + 'Grapefruit', + 'Green bean', + 'Guava', + 'Honeydew', + 'Jackfruit', + 'Jalapeño', + 'Jicama', + 'Kale', + 'Kiwi', + 'Kohlrabi', + 'Kumquat', + 'Leek', + 'Lemon', + 'Lentil', + 'Lettuce', + 'Lime', + 'Lychee', + 'Mandarin', + 'Mango', + 'Mulberry', + 'Mushroom', + 'Mustard greens', + 'Nectarine', + 'Okra', + 'Olive', + 'Onion', + 'Orange', + 'Papaya', + 'Parsnip', + 'Passionfruit', + 'Pea', + 'Peach', + 'Pear', + 'Persimmon', + 'Pineapple', + 'Plantain', + 'Plum', + 'Pomegranate', + 'Pomelo', + 'Potato', + 'Pumpkin', + 'Quince', + 'Radicchio', + 'Radish', + 'Raisin', + 'Rambutan', + 'Raspberry', + 'Redcurrant', + 'Rhubarb', + 'Rutabaga', + 'Salak', + 'Scallion', + 'Shallot', + 'Snow pea', + 'Soursop', + 'Spinach', + 'Squash', + 'Starfruit', + 'Strawberry', + 'Sweet potato', + 'Swiss chard', + 'Tamarind', + 'Tangerine', + 'Taro', + 'Tomato', + 'Turnip', + 'Ugli', + 'Watercress', + 'Watermelon', + 'Yam', + 'Yuzu', + 'Zucchini', + 'Mizuna', + 'Daikon', + 'Endive (red)', + 'Persian lime', + 'Tatsoi', + 'Salsify', +]; + +const dataset = produce.map((name) => ({ + item: name, + sales: chance.integer({ min: 100, max: 1000 }), +})); + +export default function ResponsiveTickAdjustment() { + const [widthPct, setWidthPct] = React.useState(40); + const [enabled, setEnabled] = React.useState(true); + + return ( + + + + Chart width: {widthPct}% + + setWidthPct(value)} + valueLabelDisplay="auto" + min={20} + max={100} + step={5} + aria-labelledby="chart-width" + /> + setEnabled(event.target.checked)} + /> + } + label="experimentalFeatures.responsiveTickAdjustment" + /> + + + + + + ); +} diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx new file mode 100644 index 0000000000000..12df04da0de9f --- /dev/null +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx @@ -0,0 +1,181 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Slider from '@mui/material/Slider'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Switch from '@mui/material/Switch'; +import Typography from '@mui/material/Typography'; +import { Chance } from 'chance'; +import { BarChart } from '@mui/x-charts/BarChart'; + +const chance = new Chance(42); + +const produce = [ + 'Apple', + 'Apricot', + 'Artichoke', + 'Arugula', + 'Asparagus', + 'Avocado', + 'Banana', + 'Beet', + 'Bell pepper', + 'Blackberry', + 'Blueberry', + 'Bok choy', + 'Broccoli', + 'Brussels sprout', + 'Cabbage', + 'Cantaloupe', + 'Carrot', + 'Cauliflower', + 'Celery', + 'Cherry', + 'Chickpea', + 'Chili pepper', + 'Clementine', + 'Coconut', + 'Collard greens', + 'Corn', + 'Cranberry', + 'Cucumber', + 'Currant', + 'Daikon', + 'Date', + 'Dragonfruit', + 'Durian', + 'Edamame', + 'Eggplant', + 'Elderberry', + 'Endive (red)', + 'Endive', + 'Fennel', + 'Fig', + 'Garlic', + 'Ginger', + 'Gooseberry', + 'Grape', + 'Grapefruit', + 'Green bean', + 'Guava', + 'Honeydew', + 'Jackfruit', + 'Jalapeño', + 'Jicama', + 'Kale', + 'Kiwi', + 'Kohlrabi', + 'Kumquat', + 'Leek', + 'Lemon', + 'Lentil', + 'Lettuce', + 'Lime', + 'Lychee', + 'Mandarin', + 'Mango', + 'Mizuna', + 'Mulberry', + 'Mushroom', + 'Mustard greens', + 'Nectarine', + 'Okra', + 'Olive', + 'Onion', + 'Orange', + 'Papaya', + 'Parsnip', + 'Passionfruit', + 'Pea', + 'Peach', + 'Pear', + 'Persian lime', + 'Persimmon', + 'Pineapple', + 'Plantain', + 'Plum', + 'Pomegranate', + 'Pomelo', + 'Potato', + 'Pumpkin', + 'Quince', + 'Radicchio', + 'Radish', + 'Raisin', + 'Rambutan', + 'Raspberry', + 'Redcurrant', + 'Rhubarb', + 'Rutabaga', + 'Salak', + 'Salsify', + 'Scallion', + 'Shallot', + 'Snow pea', + 'Soursop', + 'Spinach', + 'Squash', + 'Starfruit', + 'Strawberry', + 'Sweet potato', + 'Swiss chard', + 'Tamarind', + 'Tangerine', + 'Taro', + 'Tatsoi', + 'Tomato', + 'Turnip', + 'Ugli', + 'Watercress', + 'Watermelon', + 'Yam', + 'Yuzu', + 'Zucchini', +]; + +const dataset = produce.map((name) => ({ + item: name, + sales: chance.integer({ min: 100, max: 1000 }), +})); + +export default function ResponsiveTickAdjustment() { + const [widthPct, setWidthPct] = React.useState(40); + const [enabled, setEnabled] = React.useState(true); + + return ( + + + + Chart width: {widthPct}% + + setWidthPct(value as number)} + valueLabelDisplay="auto" + min={20} + max={100} + step={5} + aria-labelledby="chart-width" + /> + setEnabled(event.target.checked)} + /> + } + label="experimentalFeatures.responsiveTickAdjustment" + /> + + + + + + ); +} diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview new file mode 100644 index 0000000000000..d1c445f9e07b2 --- /dev/null +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview @@ -0,0 +1,9 @@ + + + diff --git a/docs/data/charts/axis-ticks/axis-ticks.md b/docs/data/charts/axis-ticks/axis-ticks.md index 33be43d833fc5..d24531c10c62e 100644 --- a/docs/data/charts/axis-ticks/axis-ticks.md +++ b/docs/data/charts/axis-ticks/axis-ticks.md @@ -56,6 +56,28 @@ This property defaults to 0 and is only available for ordinal axes, that is, axe {{"demo": "TickSpacing.js"}} +### Responsive tick adjustment + +:::warning +This feature is experimental and may change in a future release. Opt in via the `experimentalFeatures.responsiveTickAdjustment` prop on any cartesian chart. +::: + +Enable `responsiveTickAdjustment` to let ordinal axes (`band` and `point` scales) thin out ticks automatically based on the chart's rendered size, so labels don't pile up on narrow charts. + +The feature applies a 50-pixel default `tickSpacing` derived from the drawing area. It never overrides an explicit `tickSpacing`, `tickNumber`, or `tickInterval` set by your code—continuous axes are already size-aware through their default `tickNumber`. + +```jsx + +``` + +Drag the slider in the demo below to shrink the chart and toggle the feature to see ticks adapt. + +{{"demo": "ResponsiveTickAdjustment.js"}} + ### Fixed tick position If you want more control over the tick position, you can use the `tickInterval` property. diff --git a/packages/x-charts/src/LineChart/AreaElement.tsx b/packages/x-charts/src/LineChart/AreaElement.tsx index 91f9e185b5965..534889f8c40e7 100644 --- a/packages/x-charts/src/LineChart/AreaElement.tsx +++ b/packages/x-charts/src/LineChart/AreaElement.tsx @@ -76,7 +76,8 @@ function AreaElement(props: AreaElementProps) { const store = useStore(); const enablePositionBasedPointerInteraction = store.use( selectorChartExperimentalFeaturesState, - )?.enablePositionBasedPointerInteraction; + 'enablePositionBasedPointerInteraction', + ); const identifier = React.useMemo(() => ({ type: 'line' as const, seriesId }), [seriesId]); const interactionProps = useInteractionItemProps(identifier); const highlightState = useItemHighlightState(identifier); diff --git a/packages/x-charts/src/LineChart/CircleMarkElement.tsx b/packages/x-charts/src/LineChart/CircleMarkElement.tsx index 327e41353c2a8..880652211851b 100644 --- a/packages/x-charts/src/LineChart/CircleMarkElement.tsx +++ b/packages/x-charts/src/LineChart/CircleMarkElement.tsx @@ -84,7 +84,8 @@ function CircleMarkElement(props: CircleMarkElementProps) { const store = useStore(); const enablePositionBasedPointerInteraction = store.use( selectorChartExperimentalFeaturesState, - )?.enablePositionBasedPointerInteraction; + 'enablePositionBasedPointerInteraction', + ); const interactionProps = useInteractionItemProps({ type: 'line', seriesId, dataIndex }); const theme = useTheme(); diff --git a/packages/x-charts/src/LineChart/LineElement.tsx b/packages/x-charts/src/LineChart/LineElement.tsx index e1d6e7c01e663..bbed68f473f86 100644 --- a/packages/x-charts/src/LineChart/LineElement.tsx +++ b/packages/x-charts/src/LineChart/LineElement.tsx @@ -81,7 +81,8 @@ function LineElement(props: LineElementProps) { const store = useStore(); const enablePositionBasedPointerInteraction = store.use( selectorChartExperimentalFeaturesState, - )?.enablePositionBasedPointerInteraction; + 'enablePositionBasedPointerInteraction', + ); const identifier = React.useMemo(() => ({ type: 'line' as const, seriesId }), [seriesId]); const interactionProps = useInteractionItemProps(identifier); diff --git a/packages/x-charts/src/LineChart/MarkElement.tsx b/packages/x-charts/src/LineChart/MarkElement.tsx index 5419c9bf75d51..7751df50ac19f 100644 --- a/packages/x-charts/src/LineChart/MarkElement.tsx +++ b/packages/x-charts/src/LineChart/MarkElement.tsx @@ -89,7 +89,8 @@ function MarkElement(props: MarkElementProps) { const store = useStore(); const enablePositionBasedPointerInteraction = store.use( selectorChartExperimentalFeaturesState, - )?.enablePositionBasedPointerInteraction; + 'enablePositionBasedPointerInteraction', + ); const interactionProps = useInteractionItemProps({ type: 'line', seriesId, dataIndex }); const ownerState = { diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts index 268d38f8e8ae3..80f8d2366475c 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts @@ -1,7 +1,22 @@ import type { ChartSeriesType } from '../../../../models/seriesType/config'; -import { type ChartRootSelector } from '../../utils/selectors'; -import type { UseChartExperimentalFeaturesSignature } from './useChartExperimentalFeature.types'; +import { type ChartState } from '../../models/chart'; +import type { + ChartExperimentalFeatures, + UseChartExperimentalFeaturesSignature, +} from './useChartExperimentalFeature.types'; -export const selectorChartExperimentalFeaturesState: ChartRootSelector< - UseChartExperimentalFeaturesSignature -> = (state) => state.experimentalFeatures; +/** + * Reads the value of a single experimental feature flag from the store. + * + * @example + * const enabled = store.use( + * selectorChartExperimentalFeaturesState, + * 'responsiveTickAdjustment', + * ); + */ +export const selectorChartExperimentalFeaturesState = < + K extends keyof ChartExperimentalFeatures, +>( + state: ChartState<[UseChartExperimentalFeaturesSignature]>, + featureName: K, +): ChartExperimentalFeatures[K] | undefined => state.experimentalFeatures?.[featureName]; diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts index a60a39fb73b1d..fc4ab6afdd6dc 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts @@ -15,8 +15,24 @@ interface LineExperimentalFeatures { enablePositionBasedPointerInteraction?: boolean; } +interface CommonExperimentalFeatures { + /** + * Automatically reduces the number of ticks and tick labels on cartesian + * axes based on the rendered drawing area size. + * + * When enabled, ordinal axes (`band` / `point` scales) receive a default + * `tickSpacing` derived from the chart width/height, so a 12-month band + * axis on a 300px wide chart no longer renders 12 overlapping ticks. + * + * Continuous axes already pick a size-aware default `tickNumber`; this + * feature does not override explicit `tickNumber`, `tickSpacing`, or + * `tickInterval` values set by the consumer. + */ + responsiveTickAdjustment?: boolean; +} + export type ChartExperimentalFeatures = - 'line' extends SeriesType ? LineExperimentalFeatures : {}; + CommonExperimentalFeatures & ('line' extends SeriesType ? LineExperimentalFeatures : {}); export interface UseChartExperimentalFeaturesParameters< SeriesType extends ChartSeriesType = ChartSeriesType, diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts index a5999e6335fc4..9ae228d295079 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts @@ -81,6 +81,14 @@ export function resolveAxisSize( const DEFAULT_CATEGORY_GAP_RATIO = 0.2; const DEFAULT_BAR_GAP_RATIO = 0.1; +/** + * Default tick spacing (in pixels) applied to ordinal axes when the + * `responsiveTickAdjustment` experimental feature is enabled and the + * consumer hasn't set `tickSpacing` explicitly. Matches the 50px per tick + * heuristic used by `getDefaultTickNumber` for continuous axes. + */ +const RESPONSIVE_ORDINAL_TICK_SPACING = 50; + export type ComputeResult = { axis: ComputedAxisConfig; axisIds: AxisId[]; @@ -101,6 +109,13 @@ type ComputeCommonParams = >; autoSizes?: Record; axesGap?: number; + /** + * When true, ordinal axes (band/point) without an explicit `tickSpacing` + * receive a size-aware default so labels don't pile up on small charts. + * Continuous axes are left untouched (their default `tickNumber` is + * already size-aware via `getDefaultTickNumber`). + */ + responsiveTickAdjustment?: boolean; }; /** @@ -166,6 +181,7 @@ export function computeAxisValue({ domains, autoSizes, axesGap = 0, + responsiveTickAdjustment = false, }: ComputeCommonParams & { axis?: DefaultedAxis[]; axisDirection: 'x' | 'y'; @@ -206,6 +222,13 @@ export function computeAxisValue({ if (isOrdinalScale(scale)) { const scaleRange = axisDirection === 'y' ? [range[1], range[0]] : range; + /* Responsive feature: for ordinal axes, default `tickSpacing` to a + * pixel-based value so labels/ticks thin out on small charts. Only + * applies when the consumer hasn't set `tickSpacing` themselves. */ + const effectiveTickSpacing = + axis.tickSpacing ?? + (responsiveTickAdjustment ? RESPONSIVE_ORDINAL_TICK_SPACING : undefined); + if (isBandScale(scale) && isBandScaleConfig(axis)) { const desiredCategoryGapRatio = axis.categoryGapRatio ?? DEFAULT_CATEGORY_GAP_RATIO; const ignoreGapRatios = shouldIgnoreGapRatios(scale, desiredCategoryGapRatio); @@ -227,6 +250,7 @@ export function computeAxisValue({ * discrepancy will hopefully not be noticeable. */ scale: ignoreGapRatios ? scale.copy().padding(0) : scale, tickNumber, + tickSpacing: effectiveTickSpacing, colorScale: axis.colorMap && (axis.colorMap.type === 'ordinal' @@ -244,6 +268,7 @@ export function computeAxisValue({ data, scale, tickNumber, + tickSpacing: effectiveTickSpacing, colorScale: axis.colorMap && (axis.colorMap.type === 'ordinal' diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx index 4c0955e5a2710..583c5daea798a 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx @@ -1,9 +1,65 @@ -import { createRenderer } from '@mui/internal-test-utils'; +import { createRenderer, screen } from '@mui/internal-test-utils'; import { BarChart } from '@mui/x-charts/BarChart'; describe('useChartCartesianAxis', () => { const { render } = createRenderer(); + describe('experimentalFeatures.responsiveTickAdjustment', () => { + const manyCategories = Array.from({ length: 20 }, (_, i) => `cat-${i}`); + const data = manyCategories.map((_, i) => i); + + it('should render one tick per band when the feature is disabled', () => { + render( + , + ); + + const tickLabels = screen.getAllByTestId('ChartsXAxisTickLabel'); + expect(tickLabels).toHaveLength(manyCategories.length); + }); + + it('should thin ticks on a band axis based on the drawing area width when the feature is enabled', () => { + render( + , + ); + + const tickLabels = screen.getAllByTestId('ChartsXAxisTickLabel'); + // With ~280px of drawing area and a 50px default spacing, we expect + // roughly width / 50 ticks instead of one per band. + expect(tickLabels.length).toBeLessThan(manyCategories.length); + expect(tickLabels.length).toBeGreaterThan(0); + }); + + it('should not override an explicit tickSpacing when the feature is enabled', () => { + render( + , + ); + + // tickSpacing of 10px on a ~280px area should keep every band's tick. + const tickLabels = screen.getAllByTestId('ChartsXAxisTickLabel'); + expect(tickLabels).toHaveLength(manyCategories.length); + }); + }); + it('should throw an error when axis have duplicate ids', () => { const expectedError = [ 'MUI X Charts: The following axis ids are duplicated: qwerty.', diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts index d6a65b0cffef2..7e2762dd3fb4b 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts @@ -51,6 +51,13 @@ import { selectorChartXAxisExtrema, selectorChartYAxisExtrema, } from './useChartAxisExtrema.selectors'; +import { selectorChartExperimentalFeaturesState } from '../../corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors'; + +/* `selectorChartExperimentalFeaturesState` takes a feature name as a + * second argument, but `createSelectorMemoized` inputs are pure state + * selectors. Wrap it to bind the feature name we care about. */ +const selectorResponsiveTickAdjustment = (state: Parameters[0]) => + selectorChartExperimentalFeaturesState(state, 'responsiveTickAdjustment'); export const createZoomMap = (zoom: readonly ZoomData[]) => { const zoomItemMap = new Map(); @@ -433,6 +440,7 @@ export const selectorChartXAxis = createSelectorMemoized( selectorChartXScales, selectorChartXAxisAutoSizes, selectorChartCartesianAxesGap, + selectorResponsiveTickAdjustment, function selectorChartXAxis( drawingArea, @@ -443,6 +451,7 @@ export const selectorChartXAxis = createSelectorMemoized( scales, autoSizes, axesGap, + responsiveTickAdjustment, ) { return computeAxisValue({ scales, @@ -455,6 +464,7 @@ export const selectorChartXAxis = createSelectorMemoized( domains, autoSizes, axesGap, + responsiveTickAdjustment: responsiveTickAdjustment ?? false, }); }, ); @@ -468,6 +478,7 @@ export const selectorChartYAxis = createSelectorMemoized( selectorChartYScales, selectorChartYAxisAutoSizes, selectorChartCartesianAxesGap, + selectorResponsiveTickAdjustment, function selectorChartYAxis( drawingArea, @@ -478,6 +489,7 @@ export const selectorChartYAxis = createSelectorMemoized( scales, autoSizes, axesGap, + responsiveTickAdjustment, ) { return computeAxisValue({ scales, @@ -490,6 +502,7 @@ export const selectorChartYAxis = createSelectorMemoized( domains, autoSizes, axesGap, + responsiveTickAdjustment: responsiveTickAdjustment ?? false, }); }, ); From 4fc7935ff45394e18c5523aaa99ce2150681debe Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 28 May 2026 13:51:53 +0200 Subject: [PATCH 02/10] [charts] Restrict `responsiveTickAdjustment` to bar-like charts Limit the experimental feature to charts whose `SeriesType` includes `bar` or `rangeBar` (BarChart, BarChartPro, BarChartPremium, SparkLineChart with bar series, composition via ChartsContainer, etc.). - Move the `responsiveTickAdjustment` declaration out of the always-on `CommonExperimentalFeatures` block and into a new `BarExperimentalFeatures` interface gated by a `HasBarLikeSeries` conditional that fires for `'bar'` or `'rangeBar'` series types. - Add a runtime guard in `selectorChartXAxis` / `selectorChartYAxis`: even when the flag is enabled, the feature only applies if at least one bar or rangeBar series is present in `formattedSeries`. - Regenerate proptypes and API docs so `responsiveTickAdjustment` only appears on bar-capable charts. --- .../axis-ticks/ResponsiveTickAdjustment.js | 12 ++++++------ docs/pages/x/api/charts/bar-chart-premium.json | 4 +++- docs/pages/x/api/charts/bar-chart-pro.json | 4 +++- docs/pages/x/api/charts/bar-chart.json | 4 +++- docs/pages/x/api/charts/spark-line-chart.json | 5 ++++- .../src/BarChartPremium/BarChartPremium.tsx | 4 +++- .../src/BarChartPro/BarChartPro.tsx | 4 +++- packages/x-charts/src/BarChart/BarChart.tsx | 4 +++- .../src/SparkLineChart/SparkLineChart.tsx | 1 + .../useChartExperimentalFeature.selectors.ts | 4 +--- .../useChartExperimentalFeature.types.ts | 12 ++++++++++-- .../useChartCartesianAxisRendering.selectors.ts | 17 +++++++++++++---- 12 files changed, 53 insertions(+), 22 deletions(-) diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js index f4f7fc7e8d218..cca6b59d62811 100644 --- a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js @@ -40,12 +40,14 @@ const produce = [ 'Cranberry', 'Cucumber', 'Currant', + 'Daikon', 'Date', 'Dragonfruit', 'Durian', 'Edamame', 'Eggplant', 'Elderberry', + 'Endive (red)', 'Endive', 'Fennel', 'Fig', @@ -72,6 +74,7 @@ const produce = [ 'Lychee', 'Mandarin', 'Mango', + 'Mizuna', 'Mulberry', 'Mushroom', 'Mustard greens', @@ -86,6 +89,7 @@ const produce = [ 'Pea', 'Peach', 'Pear', + 'Persian lime', 'Persimmon', 'Pineapple', 'Plantain', @@ -104,6 +108,7 @@ const produce = [ 'Rhubarb', 'Rutabaga', 'Salak', + 'Salsify', 'Scallion', 'Shallot', 'Snow pea', @@ -117,6 +122,7 @@ const produce = [ 'Tamarind', 'Tangerine', 'Taro', + 'Tatsoi', 'Tomato', 'Turnip', 'Ugli', @@ -125,12 +131,6 @@ const produce = [ 'Yam', 'Yuzu', 'Zucchini', - 'Mizuna', - 'Daikon', - 'Endive (red)', - 'Persian lime', - 'Tatsoi', - 'Salsify', ]; const dataset = produce.map((name) => ({ diff --git a/docs/pages/x/api/charts/bar-chart-premium.json b/docs/pages/x/api/charts/bar-chart-premium.json index ed8a12dece749..002820dc003de 100644 --- a/docs/pages/x/api/charts/bar-chart-premium.json +++ b/docs/pages/x/api/charts/bar-chart-premium.json @@ -30,7 +30,9 @@ "desc": { "type": { "name": "string" } }, "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ responsiveTickAdjustment?: bool }" } + }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } }, diff --git a/docs/pages/x/api/charts/bar-chart-pro.json b/docs/pages/x/api/charts/bar-chart-pro.json index 0f6a9152ad63d..bb96e6f9832ae 100644 --- a/docs/pages/x/api/charts/bar-chart-pro.json +++ b/docs/pages/x/api/charts/bar-chart-pro.json @@ -30,7 +30,9 @@ "desc": { "type": { "name": "string" } }, "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ responsiveTickAdjustment?: bool }" } + }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } }, diff --git a/docs/pages/x/api/charts/bar-chart.json b/docs/pages/x/api/charts/bar-chart.json index de827ff2e1618..edebc1fe32960 100644 --- a/docs/pages/x/api/charts/bar-chart.json +++ b/docs/pages/x/api/charts/bar-chart.json @@ -30,7 +30,9 @@ "desc": { "type": { "name": "string" } }, "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ responsiveTickAdjustment?: bool }" } + }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } }, diff --git a/docs/pages/x/api/charts/spark-line-chart.json b/docs/pages/x/api/charts/spark-line-chart.json index 1c5167129c6e8..c295ac6d43526 100644 --- a/docs/pages/x/api/charts/spark-line-chart.json +++ b/docs/pages/x/api/charts/spark-line-chart.json @@ -36,7 +36,10 @@ "disableHitArea": { "type": { "name": "bool" } }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ enablePositionBasedPointerInteraction?: bool }" } + "type": { + "name": "shape", + "description": "{ enablePositionBasedPointerInteraction?: bool, responsiveTickAdjustment?: bool }" + } }, "height": { "type": { "name": "number" } }, "hiddenItems": { diff --git a/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx b/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx index 5b2ce6fdfcd9b..7ee7144462927 100644 --- a/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx +++ b/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx @@ -239,7 +239,9 @@ BarChartPremium.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + responsiveTickAdjustment: PropTypes.bool, + }), /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index c52d55aa5337d..851856bd1ee21 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -197,7 +197,9 @@ BarChartPro.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + responsiveTickAdjustment: PropTypes.bool, + }), /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 99d2274822558..2484a6ae2629d 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -224,7 +224,9 @@ BarChart.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + responsiveTickAdjustment: PropTypes.bool, + }), /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index 462d88924a492..272f0784a3caf 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -430,6 +430,7 @@ SparkLineChart.propTypes = { */ experimentalFeatures: PropTypes.shape({ enablePositionBasedPointerInteraction: PropTypes.bool, + responsiveTickAdjustment: PropTypes.bool, }), /** * The height of the chart in px. If not defined, it takes the height of the parent element. diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts index 80f8d2366475c..6bd7e19afa613 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts @@ -14,9 +14,7 @@ import type { * 'responsiveTickAdjustment', * ); */ -export const selectorChartExperimentalFeaturesState = < - K extends keyof ChartExperimentalFeatures, ->( +export const selectorChartExperimentalFeaturesState = ( state: ChartState<[UseChartExperimentalFeaturesSignature]>, featureName: K, ): ChartExperimentalFeatures[K] | undefined => state.experimentalFeatures?.[featureName]; diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts index fc4ab6afdd6dc..02106206a82e3 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts @@ -15,7 +15,7 @@ interface LineExperimentalFeatures { enablePositionBasedPointerInteraction?: boolean; } -interface CommonExperimentalFeatures { +interface BarExperimentalFeatures { /** * Automatically reduces the number of ticks and tick labels on cartesian * axes based on the rendered drawing area size. @@ -31,8 +31,16 @@ interface CommonExperimentalFeatures { responsiveTickAdjustment?: boolean; } +/* True if any bar-like series (`bar` or `rangeBar`) is in `SeriesType`. */ +type HasBarLikeSeries = 'bar' extends SeriesType + ? true + : 'rangeBar' extends SeriesType + ? true + : false; + export type ChartExperimentalFeatures = - CommonExperimentalFeatures & ('line' extends SeriesType ? LineExperimentalFeatures : {}); + ('line' extends SeriesType ? LineExperimentalFeatures : {}) & + (HasBarLikeSeries extends true ? BarExperimentalFeatures : {}); export interface UseChartExperimentalFeaturesParameters< SeriesType extends ChartSeriesType = ChartSeriesType, diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts index 7e2762dd3fb4b..b10c88897255e 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts @@ -56,8 +56,9 @@ import { selectorChartExperimentalFeaturesState } from '../../corePlugins/useCha /* `selectorChartExperimentalFeaturesState` takes a feature name as a * second argument, but `createSelectorMemoized` inputs are pure state * selectors. Wrap it to bind the feature name we care about. */ -const selectorResponsiveTickAdjustment = (state: Parameters[0]) => - selectorChartExperimentalFeaturesState(state, 'responsiveTickAdjustment'); +const selectorResponsiveTickAdjustment = ( + state: Parameters[0], +) => selectorChartExperimentalFeaturesState(state, 'responsiveTickAdjustment'); export const createZoomMap = (zoom: readonly ZoomData[]) => { const zoomItemMap = new Map(); @@ -464,7 +465,11 @@ export const selectorChartXAxis = createSelectorMemoized( domains, autoSizes, axesGap, - responsiveTickAdjustment: responsiveTickAdjustment ?? false, + /* Restrict the feature to bar-like charts: even when the flag is on, + * we only apply it if at least one bar or rangeBar series is present. */ + responsiveTickAdjustment: + (responsiveTickAdjustment ?? false) && + (formattedSeries.bar !== undefined || formattedSeries.rangeBar !== undefined), }); }, ); @@ -502,7 +507,11 @@ export const selectorChartYAxis = createSelectorMemoized( domains, autoSizes, axesGap, - responsiveTickAdjustment: responsiveTickAdjustment ?? false, + /* Restrict the feature to bar-like charts: even when the flag is on, + * we only apply it if at least one bar or rangeBar series is present. */ + responsiveTickAdjustment: + (responsiveTickAdjustment ?? false) && + (formattedSeries.bar !== undefined || formattedSeries.rangeBar !== undefined), }); }, ); From 5b7b33987362a9a69fad01f733ea8c3cb95c4504 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 28 May 2026 14:01:21 +0200 Subject: [PATCH 03/10] [charts] Fix CI: avoid `rangeBar` access on base `ProcessedSeries` `rangeBar` is added to `ChartsSeriesConfig` via module augmentation in `@mui/x-charts-premium`. The base `@mui/x-charts` typecheck doesn't see the key, so the previous `formattedSeries.rangeBar` access broke CI with TS2339. Use indexed access through an untyped record helper that stays compatible with both packages. --- .../useChartCartesianAxisRendering.selectors.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts index b10c88897255e..66dbb27245229 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts @@ -60,6 +60,17 @@ const selectorResponsiveTickAdjustment = ( state: Parameters[0], ) => selectorChartExperimentalFeaturesState(state, 'responsiveTickAdjustment'); +/** + * `rangeBar` is added to `ChartsSeriesConfig` via module augmentation in + * `@mui/x-charts-premium`, so the base `ProcessedSeries` type doesn't expose + * the key. Use indexed access through an untyped record to stay compatible + * with both packages. + */ +function hasBarLikeSeries(formattedSeries: object) { + const series = formattedSeries as Record; + return series.bar !== undefined || series.rangeBar !== undefined; +} + export const createZoomMap = (zoom: readonly ZoomData[]) => { const zoomItemMap = new Map(); zoom.forEach((zoomItem) => { @@ -468,8 +479,7 @@ export const selectorChartXAxis = createSelectorMemoized( /* Restrict the feature to bar-like charts: even when the flag is on, * we only apply it if at least one bar or rangeBar series is present. */ responsiveTickAdjustment: - (responsiveTickAdjustment ?? false) && - (formattedSeries.bar !== undefined || formattedSeries.rangeBar !== undefined), + (responsiveTickAdjustment ?? false) && hasBarLikeSeries(formattedSeries), }); }, ); @@ -510,8 +520,7 @@ export const selectorChartYAxis = createSelectorMemoized( /* Restrict the feature to bar-like charts: even when the flag is on, * we only apply it if at least one bar or rangeBar series is present. */ responsiveTickAdjustment: - (responsiveTickAdjustment ?? false) && - (formattedSeries.bar !== undefined || formattedSeries.rangeBar !== undefined), + (responsiveTickAdjustment ?? false) && hasBarLikeSeries(formattedSeries), }); }, ); From 8143f4fe259fdadc8c239bf65479b655b02388d3 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 28 May 2026 14:11:00 +0200 Subject: [PATCH 04/10] [charts][docs] Clarify `responsiveTickAdjustment` experimental status Rewrite the warning callout to explain that the feature is opt-in to avoid changing the look of existing charts, not because its behavior might still change. Note that it's expected to become the default in a future major. Also mention that the feature is restricted to bar-like charts and update the inline code sample to match the new fruits-and-vegetables demo dataset. --- docs/data/charts/axis-ticks/axis-ticks.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/data/charts/axis-ticks/axis-ticks.md b/docs/data/charts/axis-ticks/axis-ticks.md index d24531c10c62e..93c90f530273a 100644 --- a/docs/data/charts/axis-ticks/axis-ticks.md +++ b/docs/data/charts/axis-ticks/axis-ticks.md @@ -59,17 +59,17 @@ This property defaults to 0 and is only available for ordinal axes, that is, axe ### Responsive tick adjustment :::warning -This feature is experimental and may change in a future release. Opt in via the `experimentalFeatures.responsiveTickAdjustment` prop on any cartesian chart. +This feature is experimental—not because its behavior is unstable, but because enabling it by default would change the look of existing charts. It's opt-in for now and is expected to become the default in a future major release. ::: -Enable `responsiveTickAdjustment` to let ordinal axes (`band` and `point` scales) thin out ticks automatically based on the chart's rendered size, so labels don't pile up on narrow charts. +Enable `responsiveTickAdjustment` on bar-like charts (BarChart, BarChartPro, BarChartPremium, and any composition with `bar` or `rangeBar` series) to let ordinal axes (`band` and `point` scales) thin out ticks automatically based on the chart's rendered size, so labels don't pile up on narrow charts. The feature applies a 50-pixel default `tickSpacing` derived from the drawing area. It never overrides an explicit `tickSpacing`, `tickNumber`, or `tickInterval` set by your code—continuous axes are already size-aware through their default `tickNumber`. ```jsx ``` From dc2e90c35cc7e5c8a86087cb74e455c5ba68f30f Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 28 May 2026 14:19:35 +0200 Subject: [PATCH 05/10] [charts] Trim redundant comments Drop inline comments that restate the code (effective-tick-spacing `??` chain, the bar-like guard in the selectors) and tighten the JSDoc on the experimental flag down to what isn't already obvious from the code or from the docs section. Keep the "why" comments (`selectorResponsiveTickAdjustment` wrapper rationale, `hasBarLikeSeries` module-augmentation note). --- .../useChartExperimentalFeature.types.ts | 13 ++++--------- .../useChartCartesianAxis/computeAxisValue.ts | 17 ++--------------- .../useChartCartesianAxisRendering.selectors.ts | 4 ---- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts index 02106206a82e3..d95c66c311a7f 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts @@ -17,16 +17,11 @@ interface LineExperimentalFeatures { interface BarExperimentalFeatures { /** - * Automatically reduces the number of ticks and tick labels on cartesian - * axes based on the rendered drawing area size. + * Automatically reduces the number of ticks and tick labels on ordinal axes + * (`band` / `point` scales) based on the rendered drawing area size. * - * When enabled, ordinal axes (`band` / `point` scales) receive a default - * `tickSpacing` derived from the chart width/height, so a 12-month band - * axis on a 300px wide chart no longer renders 12 overlapping ticks. - * - * Continuous axes already pick a size-aware default `tickNumber`; this - * feature does not override explicit `tickNumber`, `tickSpacing`, or - * `tickInterval` values set by the consumer. + * Explicit `tickNumber`, `tickSpacing`, or `tickInterval` values set by the + * consumer are not overridden. */ responsiveTickAdjustment?: boolean; } diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts index 9ae228d295079..f41f1ee1a5604 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/computeAxisValue.ts @@ -81,12 +81,7 @@ export function resolveAxisSize( const DEFAULT_CATEGORY_GAP_RATIO = 0.2; const DEFAULT_BAR_GAP_RATIO = 0.1; -/** - * Default tick spacing (in pixels) applied to ordinal axes when the - * `responsiveTickAdjustment` experimental feature is enabled and the - * consumer hasn't set `tickSpacing` explicitly. Matches the 50px per tick - * heuristic used by `getDefaultTickNumber` for continuous axes. - */ +/* Matches the 50px-per-tick heuristic used by `getDefaultTickNumber` for continuous axes. */ const RESPONSIVE_ORDINAL_TICK_SPACING = 50; export type ComputeResult = { @@ -109,12 +104,7 @@ type ComputeCommonParams = >; autoSizes?: Record; axesGap?: number; - /** - * When true, ordinal axes (band/point) without an explicit `tickSpacing` - * receive a size-aware default so labels don't pile up on small charts. - * Continuous axes are left untouched (their default `tickNumber` is - * already size-aware via `getDefaultTickNumber`). - */ + /* When true, ordinal axes without an explicit `tickSpacing` get a size-aware default. */ responsiveTickAdjustment?: boolean; }; @@ -222,9 +212,6 @@ export function computeAxisValue({ if (isOrdinalScale(scale)) { const scaleRange = axisDirection === 'y' ? [range[1], range[0]] : range; - /* Responsive feature: for ordinal axes, default `tickSpacing` to a - * pixel-based value so labels/ticks thin out on small charts. Only - * applies when the consumer hasn't set `tickSpacing` themselves. */ const effectiveTickSpacing = axis.tickSpacing ?? (responsiveTickAdjustment ? RESPONSIVE_ORDINAL_TICK_SPACING : undefined); diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts index 66dbb27245229..bc13fbc3e981e 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts @@ -476,8 +476,6 @@ export const selectorChartXAxis = createSelectorMemoized( domains, autoSizes, axesGap, - /* Restrict the feature to bar-like charts: even when the flag is on, - * we only apply it if at least one bar or rangeBar series is present. */ responsiveTickAdjustment: (responsiveTickAdjustment ?? false) && hasBarLikeSeries(formattedSeries), }); @@ -517,8 +515,6 @@ export const selectorChartYAxis = createSelectorMemoized( domains, autoSizes, axesGap, - /* Restrict the feature to bar-like charts: even when the flag is on, - * we only apply it if at least one bar or rangeBar series is present. */ responsiveTickAdjustment: (responsiveTickAdjustment ?? false) && hasBarLikeSeries(formattedSeries), }); From ed56d57b4b36bd677bf49f4f1004893d0dd8bfd4 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 28 May 2026 15:51:52 +0200 Subject: [PATCH 06/10] [charts] Fix CI: skip jsdom-only assertions, register demo preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `useChartCartesianAxis.test.tsx`: the two tests that assert 20 tick labels render rely on `getVisibleLabels` not measuring real label widths. In the browser, label overlap filtering kicks in and fewer labels survive. Gate those two cases on `!isJSDOM` so they only run under jsdom. The middle assertion (feature on → fewer labels than the band count) holds in both environments and stays unrestricted. - `docs/scripts/formattedTSDemos.js`: the demo returns a control panel + chart that exceeds the 16-line default cap of `babel-plugin-jsx-preview`, so the auto-generated `.preview` file was being deleted on every transpile run and the `pnpm docs:typescript:formatted changes committed?` check failed. Add a `previewOverride` entry bumping `maxLines` to 40 for this demo so the preview is regenerated and stays consistent with the committed file. --- .../ResponsiveTickAdjustment.tsx.preview | 27 +++++++++++++++++-- docs/scripts/formattedTSDemos.js | 1 + .../useChartCartesianAxis.test.tsx | 8 ++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview index d1c445f9e07b2..81a78c912b966 100644 --- a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview @@ -1,4 +1,27 @@ - + + + Chart width: {widthPct}% + + setWidthPct(value as number)} + valueLabelDisplay="auto" + min={20} + max={100} + step={5} + aria-labelledby="chart-width" + /> + setEnabled(event.target.checked)} + /> + } + label="experimentalFeatures.responsiveTickAdjustment" + /> + + - + \ No newline at end of file diff --git a/docs/scripts/formattedTSDemos.js b/docs/scripts/formattedTSDemos.js index 0fec284db60b5..6591be38c1985 100644 --- a/docs/scripts/formattedTSDemos.js +++ b/docs/scripts/formattedTSDemos.js @@ -74,6 +74,7 @@ const previewOverride = { 'docs/data/charts/axis/GroupedAxesStyling.tsx': { maxLines: 30 }, 'docs/data/charts/axis/GroupedAxesTickSize.tsx': { maxLines: 30 }, 'docs/data/charts/axis/GroupedYAxes.tsx': { maxLines: 30 }, + 'docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx': { maxLines: 40 }, 'docs/data/charts/sankey/SankeyDetailedDataStructure.tsx': { maxLines: 30 }, }; diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx index 583c5daea798a..3de9dd339935c 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx @@ -1,5 +1,6 @@ import { createRenderer, screen } from '@mui/internal-test-utils'; import { BarChart } from '@mui/x-charts/BarChart'; +import { isJSDOM } from 'test/utils/skipIf'; describe('useChartCartesianAxis', () => { const { render } = createRenderer(); @@ -8,7 +9,10 @@ describe('useChartCartesianAxis', () => { const manyCategories = Array.from({ length: 20 }, (_, i) => `cat-${i}`); const data = manyCategories.map((_, i) => i); - it('should render one tick per band when the feature is disabled', () => { + // In the browser, `getVisibleLabels` measures real label widths and hides + // the overlapping ones, so the "all 20 labels render" assertion only holds + // in jsdom where measurements are bypassed. + it.skipIf(!isJSDOM)('should render one tick per band when the feature is disabled', () => { render( { expect(tickLabels.length).toBeGreaterThan(0); }); - it('should not override an explicit tickSpacing when the feature is enabled', () => { + it.skipIf(!isJSDOM)('should not override an explicit tickSpacing when the feature is enabled', () => { render( Date: Fri, 29 May 2026 12:55:44 +0200 Subject: [PATCH 07/10] [charts] Fix prettier formatting in test file --- .../ResponsiveTickAdjustment.tsx.preview | 32 ------------------ docs/scripts/formattedTSDemos.js | 1 - .../useChartCartesianAxis.test.tsx | 33 ++++++++++--------- 3 files changed, 18 insertions(+), 48 deletions(-) delete mode 100644 docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview deleted file mode 100644 index 81a78c912b966..0000000000000 --- a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx.preview +++ /dev/null @@ -1,32 +0,0 @@ - - - Chart width: {widthPct}% - - setWidthPct(value as number)} - valueLabelDisplay="auto" - min={20} - max={100} - step={5} - aria-labelledby="chart-width" - /> - setEnabled(event.target.checked)} - /> - } - label="experimentalFeatures.responsiveTickAdjustment" - /> - - - - \ No newline at end of file diff --git a/docs/scripts/formattedTSDemos.js b/docs/scripts/formattedTSDemos.js index 6591be38c1985..0fec284db60b5 100644 --- a/docs/scripts/formattedTSDemos.js +++ b/docs/scripts/formattedTSDemos.js @@ -74,7 +74,6 @@ const previewOverride = { 'docs/data/charts/axis/GroupedAxesStyling.tsx': { maxLines: 30 }, 'docs/data/charts/axis/GroupedAxesTickSize.tsx': { maxLines: 30 }, 'docs/data/charts/axis/GroupedYAxes.tsx': { maxLines: 30 }, - 'docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx': { maxLines: 40 }, 'docs/data/charts/sankey/SankeyDetailedDataStructure.tsx': { maxLines: 30 }, }; diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx index 3de9dd339935c..783881b048be6 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx @@ -46,22 +46,25 @@ describe('useChartCartesianAxis', () => { expect(tickLabels.length).toBeGreaterThan(0); }); - it.skipIf(!isJSDOM)('should not override an explicit tickSpacing when the feature is enabled', () => { - render( - , - ); + it.skipIf(!isJSDOM)( + 'should not override an explicit tickSpacing when the feature is enabled', + () => { + render( + , + ); - // tickSpacing of 10px on a ~280px area should keep every band's tick. - const tickLabels = screen.getAllByTestId('ChartsXAxisTickLabel'); - expect(tickLabels).toHaveLength(manyCategories.length); - }); + // tickSpacing of 10px on a ~280px area should keep every band's tick. + const tickLabels = screen.getAllByTestId('ChartsXAxisTickLabel'); + expect(tickLabels).toHaveLength(manyCategories.length); + }, + ); }); it('should throw an error when axis have duplicate ids', () => { From bd8147f9ff8845070d99dac81ec25bc6e72a82a6 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 9 Jun 2026 16:07:39 +0200 Subject: [PATCH 08/10] [charts] Enable responsive tick adjustment on all cartesian charts and rename prop Rename the experimental `responsiveTickAdjustment` flag to `useNewResponsiveTickAdjustment` and make it available on every chart that can have band/point scales instead of only bar-like charts. The type now exposes the flag for any cartesian series, and the rendering selector no longer gates the behavior behind a bar-series check, so ordinal axes on line, scatter, heatmap, funnel, and spark-line charts thin ticks too. --- .../axis-ticks/ResponsiveTickAdjustment.js | 4 ++-- .../axis-ticks/ResponsiveTickAdjustment.tsx | 4 ++-- docs/data/charts/axis-ticks/axis-ticks.md | 4 ++-- .../pages/x/api/charts/bar-chart-premium.json | 2 +- docs/pages/x/api/charts/bar-chart-pro.json | 2 +- docs/pages/x/api/charts/bar-chart.json | 2 +- docs/pages/x/api/charts/funnel-chart.json | 4 +++- docs/pages/x/api/charts/heatmap-premium.json | 4 +++- docs/pages/x/api/charts/heatmap.json | 4 +++- docs/pages/x/api/charts/line-chart-pro.json | 5 +++- docs/pages/x/api/charts/line-chart.json | 5 +++- .../x/api/charts/scatter-chart-premium.json | 4 +++- .../pages/x/api/charts/scatter-chart-pro.json | 4 +++- docs/pages/x/api/charts/scatter-chart.json | 4 +++- docs/pages/x/api/charts/spark-line-chart.json | 2 +- .../src/BarChartPremium/BarChartPremium.tsx | 2 +- .../src/HeatmapPremium/HeatmapPremium.tsx | 4 +++- .../ScatterChartPremium.tsx | 4 +++- .../src/BarChartPro/BarChartPro.tsx | 2 +- .../src/FunnelChart/FunnelChart.tsx | 4 +++- packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 4 +++- .../src/LineChartPro/LineChartPro.tsx | 1 + .../src/ScatterChartPro/ScatterChartPro.tsx | 4 +++- packages/x-charts/src/BarChart/BarChart.tsx | 2 +- packages/x-charts/src/LineChart/LineChart.tsx | 1 + .../src/ScatterChart/ScatterChart.tsx | 4 +++- .../src/SparkLineChart/SparkLineChart.tsx | 2 +- .../useChartExperimentalFeature.selectors.ts | 2 +- .../useChartExperimentalFeature.types.ts | 23 ++++++++++-------- .../useChartCartesianAxis.test.tsx | 24 ++++++++++++++++--- ...seChartCartesianAxisRendering.selectors.ts | 19 +++------------ 31 files changed, 98 insertions(+), 58 deletions(-) diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js index cca6b59d62811..e5e821d93e0b4 100644 --- a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js @@ -164,7 +164,7 @@ export default function ResponsiveTickAdjustment() { onChange={(event) => setEnabled(event.target.checked)} /> } - label="experimentalFeatures.responsiveTickAdjustment" + label="experimentalFeatures.useNewResponsiveTickAdjustment" /> @@ -173,7 +173,7 @@ export default function ResponsiveTickAdjustment() { xAxis={[{ dataKey: 'item', scaleType: 'band' }]} series={[{ dataKey: 'sales', label: 'Units sold' }]} height={300} - experimentalFeatures={{ responsiveTickAdjustment: enabled }} + experimentalFeatures={{ useNewResponsiveTickAdjustment: enabled }} /> diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx index 12df04da0de9f..c5a277b2ef14e 100644 --- a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx @@ -164,7 +164,7 @@ export default function ResponsiveTickAdjustment() { onChange={(event) => setEnabled(event.target.checked)} /> } - label="experimentalFeatures.responsiveTickAdjustment" + label="experimentalFeatures.useNewResponsiveTickAdjustment" /> @@ -173,7 +173,7 @@ export default function ResponsiveTickAdjustment() { xAxis={[{ dataKey: 'item', scaleType: 'band' }]} series={[{ dataKey: 'sales', label: 'Units sold' }]} height={300} - experimentalFeatures={{ responsiveTickAdjustment: enabled }} + experimentalFeatures={{ useNewResponsiveTickAdjustment: enabled }} /> diff --git a/docs/data/charts/axis-ticks/axis-ticks.md b/docs/data/charts/axis-ticks/axis-ticks.md index 93c90f530273a..5511980dbd004 100644 --- a/docs/data/charts/axis-ticks/axis-ticks.md +++ b/docs/data/charts/axis-ticks/axis-ticks.md @@ -62,7 +62,7 @@ This property defaults to 0 and is only available for ordinal axes, that is, axe This feature is experimental—not because its behavior is unstable, but because enabling it by default would change the look of existing charts. It's opt-in for now and is expected to become the default in a future major release. ::: -Enable `responsiveTickAdjustment` on bar-like charts (BarChart, BarChartPro, BarChartPremium, and any composition with `bar` or `rangeBar` series) to let ordinal axes (`band` and `point` scales) thin out ticks automatically based on the chart's rendered size, so labels don't pile up on narrow charts. +Enable `useNewResponsiveTickAdjustment` on any cartesian chart (BarChart, LineChart, ScatterChart, Heatmap, and their Pro/Premium variants) to let ordinal axes (`band` and `point` scales) thin out ticks automatically based on the chart's rendered size, so labels don't pile up on narrow charts. The feature applies a 50-pixel default `tickSpacing` derived from the drawing area. It never overrides an explicit `tickSpacing`, `tickNumber`, or `tickInterval` set by your code—continuous axes are already size-aware through their default `tickNumber`. @@ -70,7 +70,7 @@ The feature applies a 50-pixel default `tickSpacing` derived from the drawing ar ``` diff --git a/docs/pages/x/api/charts/bar-chart-premium.json b/docs/pages/x/api/charts/bar-chart-premium.json index 002820dc003de..9f00933d66a7e 100644 --- a/docs/pages/x/api/charts/bar-chart-premium.json +++ b/docs/pages/x/api/charts/bar-chart-premium.json @@ -31,7 +31,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ responsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/bar-chart-pro.json b/docs/pages/x/api/charts/bar-chart-pro.json index bb96e6f9832ae..ed43049ccc887 100644 --- a/docs/pages/x/api/charts/bar-chart-pro.json +++ b/docs/pages/x/api/charts/bar-chart-pro.json @@ -31,7 +31,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ responsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/bar-chart.json b/docs/pages/x/api/charts/bar-chart.json index edebc1fe32960..2100335ae88a5 100644 --- a/docs/pages/x/api/charts/bar-chart.json +++ b/docs/pages/x/api/charts/bar-chart.json @@ -31,7 +31,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ responsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/funnel-chart.json b/docs/pages/x/api/charts/funnel-chart.json index 829ed7f77fa26..8a0892477318a 100644 --- a/docs/pages/x/api/charts/funnel-chart.json +++ b/docs/pages/x/api/charts/funnel-chart.json @@ -28,7 +28,9 @@ "desc": { "type": { "name": "string" } }, "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + }, "gap": { "type": { "name": "number" }, "default": "0" }, "height": { "type": { "name": "number" } }, "hiddenItems": { diff --git a/docs/pages/x/api/charts/heatmap-premium.json b/docs/pages/x/api/charts/heatmap-premium.json index e8f139589a6f6..d2957e09e6e6f 100644 --- a/docs/pages/x/api/charts/heatmap-premium.json +++ b/docs/pages/x/api/charts/heatmap-premium.json @@ -27,7 +27,9 @@ "desc": { "type": { "name": "string" } }, "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + }, "height": { "type": { "name": "number" } }, "hideLegend": { "type": { "name": "bool" } }, "highlightedItem": { diff --git a/docs/pages/x/api/charts/heatmap.json b/docs/pages/x/api/charts/heatmap.json index 7ea6c7f6f6a6a..f03a24e388b3d 100644 --- a/docs/pages/x/api/charts/heatmap.json +++ b/docs/pages/x/api/charts/heatmap.json @@ -27,7 +27,9 @@ "desc": { "type": { "name": "string" } }, "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + }, "height": { "type": { "name": "number" } }, "hideLegend": { "type": { "name": "bool" } }, "highlightedItem": { diff --git a/docs/pages/x/api/charts/line-chart-pro.json b/docs/pages/x/api/charts/line-chart-pro.json index 0f16c5b68efc5..249b4e81c0bf0 100644 --- a/docs/pages/x/api/charts/line-chart-pro.json +++ b/docs/pages/x/api/charts/line-chart-pro.json @@ -32,7 +32,10 @@ "disableKeyboardNavigation": { "type": { "name": "bool" } }, "disableLineItemHighlight": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ enablePositionBasedPointerInteraction?: bool }" } + "type": { + "name": "shape", + "description": "{ enablePositionBasedPointerInteraction?: bool, useNewResponsiveTickAdjustment?: bool }" + } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/line-chart.json b/docs/pages/x/api/charts/line-chart.json index 7048ba59719da..23568ee759907 100644 --- a/docs/pages/x/api/charts/line-chart.json +++ b/docs/pages/x/api/charts/line-chart.json @@ -32,7 +32,10 @@ "disableKeyboardNavigation": { "type": { "name": "bool" } }, "disableLineItemHighlight": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ enablePositionBasedPointerInteraction?: bool }" } + "type": { + "name": "shape", + "description": "{ enablePositionBasedPointerInteraction?: bool, useNewResponsiveTickAdjustment?: bool }" + } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/scatter-chart-premium.json b/docs/pages/x/api/charts/scatter-chart-premium.json index 19bbbdaa9b2c4..bd26a48c81286 100644 --- a/docs/pages/x/api/charts/scatter-chart-premium.json +++ b/docs/pages/x/api/charts/scatter-chart-premium.json @@ -43,7 +43,9 @@ "deprecated": true, "deprecationInfo": "Use disableHitArea instead." }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } }, diff --git a/docs/pages/x/api/charts/scatter-chart-pro.json b/docs/pages/x/api/charts/scatter-chart-pro.json index c9a7e6b7b3b26..36570899d7a82 100644 --- a/docs/pages/x/api/charts/scatter-chart-pro.json +++ b/docs/pages/x/api/charts/scatter-chart-pro.json @@ -43,7 +43,9 @@ "deprecated": true, "deprecationInfo": "Use disableHitArea instead." }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } }, diff --git a/docs/pages/x/api/charts/scatter-chart.json b/docs/pages/x/api/charts/scatter-chart.json index a8119342a77dc..bb95a1466dcc0 100644 --- a/docs/pages/x/api/charts/scatter-chart.json +++ b/docs/pages/x/api/charts/scatter-chart.json @@ -43,7 +43,9 @@ "deprecated": true, "deprecationInfo": "Use disableHitArea instead." }, - "experimentalFeatures": { "type": { "name": "object" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } }, diff --git a/docs/pages/x/api/charts/spark-line-chart.json b/docs/pages/x/api/charts/spark-line-chart.json index c295ac6d43526..7e52587797ec2 100644 --- a/docs/pages/x/api/charts/spark-line-chart.json +++ b/docs/pages/x/api/charts/spark-line-chart.json @@ -38,7 +38,7 @@ "experimentalFeatures": { "type": { "name": "shape", - "description": "{ enablePositionBasedPointerInteraction?: bool, responsiveTickAdjustment?: bool }" + "description": "{ enablePositionBasedPointerInteraction?: bool, useNewResponsiveTickAdjustment?: bool }" } }, "height": { "type": { "name": "number" } }, diff --git a/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx b/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx index 7ee7144462927..4cb28d30be9af 100644 --- a/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx +++ b/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx @@ -240,7 +240,7 @@ BarChartPremium.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - responsiveTickAdjustment: PropTypes.bool, + useNewResponsiveTickAdjustment: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx b/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx index 585973b221a18..0a23c5ba1210b 100644 --- a/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx +++ b/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx @@ -144,7 +144,9 @@ HeatmapPremium.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + useNewResponsiveTickAdjustment: PropTypes.bool, + }), /** * The height of the chart in px. If not defined, it takes the height of the parent element. */ diff --git a/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx b/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx index ec9ad5093406f..042cab3156422 100644 --- a/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx +++ b/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx @@ -246,7 +246,9 @@ ScatterChartPremium.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + useNewResponsiveTickAdjustment: PropTypes.bool, + }), /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index 851856bd1ee21..0a852bce15366 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -198,7 +198,7 @@ BarChartPro.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - responsiveTickAdjustment: PropTypes.bool, + useNewResponsiveTickAdjustment: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx index cd05f95517236..2bef361009845 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx @@ -258,7 +258,9 @@ FunnelChart.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + useNewResponsiveTickAdjustment: PropTypes.bool, + }), /** * The gap, in pixels, between funnel sections. * @default 0 diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 2b8425f7b9b3a..251c7d7d1944a 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -239,7 +239,9 @@ Heatmap.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + useNewResponsiveTickAdjustment: PropTypes.bool, + }), /** * The height of the chart in px. If not defined, it takes the height of the parent element. */ diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index 09090141b8e96..ce6f0242fd2dc 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -208,6 +208,7 @@ LineChartPro.propTypes = { */ experimentalFeatures: PropTypes.shape({ enablePositionBasedPointerInteraction: PropTypes.bool, + useNewResponsiveTickAdjustment: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index 360f578f38393..e5fa64a5f639e 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -221,7 +221,9 @@ ScatterChartPro.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + useNewResponsiveTickAdjustment: PropTypes.bool, + }), /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 2484a6ae2629d..9c112ab5662c2 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -225,7 +225,7 @@ BarChart.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - responsiveTickAdjustment: PropTypes.bool, + useNewResponsiveTickAdjustment: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 3d69c78e5ffe2..822dbf5929277 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -273,6 +273,7 @@ LineChart.propTypes = { */ experimentalFeatures: PropTypes.shape({ enablePositionBasedPointerInteraction: PropTypes.bool, + useNewResponsiveTickAdjustment: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 72e066209d45a..77ba1f8b64930 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -265,7 +265,9 @@ ScatterChart.propTypes = { /** * Options to enable features planned for the next major. */ - experimentalFeatures: PropTypes.object, + experimentalFeatures: PropTypes.shape({ + useNewResponsiveTickAdjustment: PropTypes.bool, + }), /** * Option to display a cartesian grid in the background. */ diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index 272f0784a3caf..378226a69f691 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -430,7 +430,7 @@ SparkLineChart.propTypes = { */ experimentalFeatures: PropTypes.shape({ enablePositionBasedPointerInteraction: PropTypes.bool, - responsiveTickAdjustment: PropTypes.bool, + useNewResponsiveTickAdjustment: PropTypes.bool, }), /** * The height of the chart in px. If not defined, it takes the height of the parent element. diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts index 6bd7e19afa613..a14b7f300ee39 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts @@ -11,7 +11,7 @@ import type { * @example * const enabled = store.use( * selectorChartExperimentalFeaturesState, - * 'responsiveTickAdjustment', + * 'useNewResponsiveTickAdjustment', * ); */ export const selectorChartExperimentalFeaturesState = ( diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts index d95c66c311a7f..7338af50a2484 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts @@ -1,5 +1,8 @@ import { type ChartPluginSignature } from '../../models'; -import type { ChartSeriesType } from '../../../../models/seriesType/config'; +import type { + CartesianChartSeriesType, + ChartSeriesType, +} from '../../../../models/seriesType/config'; interface LineExperimentalFeatures { /** @@ -15,7 +18,7 @@ interface LineExperimentalFeatures { enablePositionBasedPointerInteraction?: boolean; } -interface BarExperimentalFeatures { +interface CartesianExperimentalFeatures { /** * Automatically reduces the number of ticks and tick labels on ordinal axes * (`band` / `point` scales) based on the rendered drawing area size. @@ -23,19 +26,19 @@ interface BarExperimentalFeatures { * Explicit `tickNumber`, `tickSpacing`, or `tickInterval` values set by the * consumer are not overridden. */ - responsiveTickAdjustment?: boolean; + useNewResponsiveTickAdjustment?: boolean; } -/* True if any bar-like series (`bar` or `rangeBar`) is in `SeriesType`. */ -type HasBarLikeSeries = 'bar' extends SeriesType - ? true - : 'rangeBar' extends SeriesType - ? true - : false; +/* True if any cartesian series (which can have `band` / `point` scales) is in `SeriesType`. */ +type HasCartesianSeries = [ + Extract, +] extends [never] + ? false + : true; export type ChartExperimentalFeatures = ('line' extends SeriesType ? LineExperimentalFeatures : {}) & - (HasBarLikeSeries extends true ? BarExperimentalFeatures : {}); + (HasCartesianSeries extends true ? CartesianExperimentalFeatures : {}); export interface UseChartExperimentalFeaturesParameters< SeriesType extends ChartSeriesType = ChartSeriesType, diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx index 783881b048be6..1a22a34f2afbb 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx @@ -1,11 +1,12 @@ import { createRenderer, screen } from '@mui/internal-test-utils'; import { BarChart } from '@mui/x-charts/BarChart'; +import { LineChart } from '@mui/x-charts/LineChart'; import { isJSDOM } from 'test/utils/skipIf'; describe('useChartCartesianAxis', () => { const { render } = createRenderer(); - describe('experimentalFeatures.responsiveTickAdjustment', () => { + describe('experimentalFeatures.useNewResponsiveTickAdjustment', () => { const manyCategories = Array.from({ length: 20 }, (_, i) => `cat-${i}`); const data = manyCategories.map((_, i) => i); @@ -35,7 +36,7 @@ describe('useChartCartesianAxis', () => { width={300} height={200} margin={0} - experimentalFeatures={{ responsiveTickAdjustment: true }} + experimentalFeatures={{ useNewResponsiveTickAdjustment: true }} />, ); @@ -56,7 +57,7 @@ describe('useChartCartesianAxis', () => { width={300} height={200} margin={0} - experimentalFeatures={{ responsiveTickAdjustment: true }} + experimentalFeatures={{ useNewResponsiveTickAdjustment: true }} />, ); @@ -65,6 +66,23 @@ describe('useChartCartesianAxis', () => { expect(tickLabels).toHaveLength(manyCategories.length); }, ); + + it('should thin ticks on a non-bar cartesian chart when the feature is enabled', () => { + render( + , + ); + + const tickLabels = screen.getAllByTestId('ChartsXAxisTickLabel'); + expect(tickLabels.length).toBeLessThan(manyCategories.length); + expect(tickLabels.length).toBeGreaterThan(0); + }); }); it('should throw an error when axis have duplicate ids', () => { diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts index bc13fbc3e981e..df6abc4794c5c 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts @@ -58,18 +58,7 @@ import { selectorChartExperimentalFeaturesState } from '../../corePlugins/useCha * selectors. Wrap it to bind the feature name we care about. */ const selectorResponsiveTickAdjustment = ( state: Parameters[0], -) => selectorChartExperimentalFeaturesState(state, 'responsiveTickAdjustment'); - -/** - * `rangeBar` is added to `ChartsSeriesConfig` via module augmentation in - * `@mui/x-charts-premium`, so the base `ProcessedSeries` type doesn't expose - * the key. Use indexed access through an untyped record to stay compatible - * with both packages. - */ -function hasBarLikeSeries(formattedSeries: object) { - const series = formattedSeries as Record; - return series.bar !== undefined || series.rangeBar !== undefined; -} +) => selectorChartExperimentalFeaturesState(state, 'useNewResponsiveTickAdjustment'); export const createZoomMap = (zoom: readonly ZoomData[]) => { const zoomItemMap = new Map(); @@ -476,8 +465,7 @@ export const selectorChartXAxis = createSelectorMemoized( domains, autoSizes, axesGap, - responsiveTickAdjustment: - (responsiveTickAdjustment ?? false) && hasBarLikeSeries(formattedSeries), + responsiveTickAdjustment: responsiveTickAdjustment ?? false, }); }, ); @@ -515,8 +503,7 @@ export const selectorChartYAxis = createSelectorMemoized( domains, autoSizes, axesGap, - responsiveTickAdjustment: - (responsiveTickAdjustment ?? false) && hasBarLikeSeries(formattedSeries), + responsiveTickAdjustment: responsiveTickAdjustment ?? false, }); }, ); From 7494d15905de3836ce2a9d54ab5e9e7d52de826d Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 9 Jun 2026 16:26:05 +0200 Subject: [PATCH 09/10] [charts] Rename experimental flag to useNewDefaultTickSpacing Rename the experimental `useNewResponsiveTickAdjustment` flag to `useNewDefaultTickSpacing` across types, selectors, proptypes, API docs, tests, and the docs demo. --- docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js | 4 ++-- docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx | 4 ++-- docs/data/charts/axis-ticks/axis-ticks.md | 4 ++-- docs/pages/x/api/charts/bar-chart-premium.json | 2 +- docs/pages/x/api/charts/bar-chart-pro.json | 2 +- docs/pages/x/api/charts/bar-chart.json | 2 +- docs/pages/x/api/charts/funnel-chart.json | 2 +- docs/pages/x/api/charts/heatmap-premium.json | 2 +- docs/pages/x/api/charts/heatmap.json | 2 +- docs/pages/x/api/charts/line-chart-pro.json | 2 +- docs/pages/x/api/charts/line-chart.json | 2 +- docs/pages/x/api/charts/scatter-chart-premium.json | 2 +- docs/pages/x/api/charts/scatter-chart-pro.json | 2 +- docs/pages/x/api/charts/scatter-chart.json | 2 +- docs/pages/x/api/charts/spark-line-chart.json | 2 +- .../src/BarChartPremium/BarChartPremium.tsx | 2 +- .../src/HeatmapPremium/HeatmapPremium.tsx | 2 +- .../src/ScatterChartPremium/ScatterChartPremium.tsx | 2 +- packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx | 2 +- packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx | 2 +- packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 2 +- packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx | 2 +- .../x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx | 2 +- packages/x-charts/src/BarChart/BarChart.tsx | 2 +- packages/x-charts/src/LineChart/LineChart.tsx | 2 +- packages/x-charts/src/ScatterChart/ScatterChart.tsx | 2 +- packages/x-charts/src/SparkLineChart/SparkLineChart.tsx | 2 +- .../useChartExperimentalFeature.selectors.ts | 2 +- .../useChartExperimentalFeature.types.ts | 2 +- .../useChartCartesianAxis/useChartCartesianAxis.test.tsx | 8 ++++---- .../useChartCartesianAxisRendering.selectors.ts | 2 +- 31 files changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js index e5e821d93e0b4..1fe5ac62c302f 100644 --- a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.js @@ -164,7 +164,7 @@ export default function ResponsiveTickAdjustment() { onChange={(event) => setEnabled(event.target.checked)} /> } - label="experimentalFeatures.useNewResponsiveTickAdjustment" + label="experimentalFeatures.useNewDefaultTickSpacing" /> @@ -173,7 +173,7 @@ export default function ResponsiveTickAdjustment() { xAxis={[{ dataKey: 'item', scaleType: 'band' }]} series={[{ dataKey: 'sales', label: 'Units sold' }]} height={300} - experimentalFeatures={{ useNewResponsiveTickAdjustment: enabled }} + experimentalFeatures={{ useNewDefaultTickSpacing: enabled }} /> diff --git a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx index c5a277b2ef14e..a96a6a832a315 100644 --- a/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx +++ b/docs/data/charts/axis-ticks/ResponsiveTickAdjustment.tsx @@ -164,7 +164,7 @@ export default function ResponsiveTickAdjustment() { onChange={(event) => setEnabled(event.target.checked)} /> } - label="experimentalFeatures.useNewResponsiveTickAdjustment" + label="experimentalFeatures.useNewDefaultTickSpacing" /> @@ -173,7 +173,7 @@ export default function ResponsiveTickAdjustment() { xAxis={[{ dataKey: 'item', scaleType: 'band' }]} series={[{ dataKey: 'sales', label: 'Units sold' }]} height={300} - experimentalFeatures={{ useNewResponsiveTickAdjustment: enabled }} + experimentalFeatures={{ useNewDefaultTickSpacing: enabled }} /> diff --git a/docs/data/charts/axis-ticks/axis-ticks.md b/docs/data/charts/axis-ticks/axis-ticks.md index 5511980dbd004..1ecedf3b39f86 100644 --- a/docs/data/charts/axis-ticks/axis-ticks.md +++ b/docs/data/charts/axis-ticks/axis-ticks.md @@ -62,7 +62,7 @@ This property defaults to 0 and is only available for ordinal axes, that is, axe This feature is experimental—not because its behavior is unstable, but because enabling it by default would change the look of existing charts. It's opt-in for now and is expected to become the default in a future major release. ::: -Enable `useNewResponsiveTickAdjustment` on any cartesian chart (BarChart, LineChart, ScatterChart, Heatmap, and their Pro/Premium variants) to let ordinal axes (`band` and `point` scales) thin out ticks automatically based on the chart's rendered size, so labels don't pile up on narrow charts. +Enable `useNewDefaultTickSpacing` on any cartesian chart (BarChart, LineChart, ScatterChart, Heatmap, and their Pro/Premium variants) to let ordinal axes (`band` and `point` scales) thin out ticks automatically based on the chart's rendered size, so labels don't pile up on narrow charts. The feature applies a 50-pixel default `tickSpacing` derived from the drawing area. It never overrides an explicit `tickSpacing`, `tickNumber`, or `tickInterval` set by your code—continuous axes are already size-aware through their default `tickNumber`. @@ -70,7 +70,7 @@ The feature applies a 50-pixel default `tickSpacing` derived from the drawing ar ``` diff --git a/docs/pages/x/api/charts/bar-chart-premium.json b/docs/pages/x/api/charts/bar-chart-premium.json index 9f00933d66a7e..3d54bfb84c1e6 100644 --- a/docs/pages/x/api/charts/bar-chart-premium.json +++ b/docs/pages/x/api/charts/bar-chart-premium.json @@ -31,7 +31,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/bar-chart-pro.json b/docs/pages/x/api/charts/bar-chart-pro.json index ed43049ccc887..f6336022ddf3f 100644 --- a/docs/pages/x/api/charts/bar-chart-pro.json +++ b/docs/pages/x/api/charts/bar-chart-pro.json @@ -31,7 +31,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/bar-chart.json b/docs/pages/x/api/charts/bar-chart.json index 2100335ae88a5..69ac53bddcbbb 100644 --- a/docs/pages/x/api/charts/bar-chart.json +++ b/docs/pages/x/api/charts/bar-chart.json @@ -31,7 +31,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/funnel-chart.json b/docs/pages/x/api/charts/funnel-chart.json index 8a0892477318a..4cc952fd4ac22 100644 --- a/docs/pages/x/api/charts/funnel-chart.json +++ b/docs/pages/x/api/charts/funnel-chart.json @@ -29,7 +29,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "gap": { "type": { "name": "number" }, "default": "0" }, "height": { "type": { "name": "number" } }, diff --git a/docs/pages/x/api/charts/heatmap-premium.json b/docs/pages/x/api/charts/heatmap-premium.json index d2957e09e6e6f..848b02e0ce225 100644 --- a/docs/pages/x/api/charts/heatmap-premium.json +++ b/docs/pages/x/api/charts/heatmap-premium.json @@ -28,7 +28,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "height": { "type": { "name": "number" } }, "hideLegend": { "type": { "name": "bool" } }, diff --git a/docs/pages/x/api/charts/heatmap.json b/docs/pages/x/api/charts/heatmap.json index f03a24e388b3d..33a6bc32918de 100644 --- a/docs/pages/x/api/charts/heatmap.json +++ b/docs/pages/x/api/charts/heatmap.json @@ -28,7 +28,7 @@ "disableAxisListener": { "type": { "name": "bool" }, "default": "false" }, "disableKeyboardNavigation": { "type": { "name": "bool" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "height": { "type": { "name": "number" } }, "hideLegend": { "type": { "name": "bool" } }, diff --git a/docs/pages/x/api/charts/line-chart-pro.json b/docs/pages/x/api/charts/line-chart-pro.json index 249b4e81c0bf0..2855bc3b25756 100644 --- a/docs/pages/x/api/charts/line-chart-pro.json +++ b/docs/pages/x/api/charts/line-chart-pro.json @@ -34,7 +34,7 @@ "experimentalFeatures": { "type": { "name": "shape", - "description": "{ enablePositionBasedPointerInteraction?: bool, useNewResponsiveTickAdjustment?: bool }" + "description": "{ enablePositionBasedPointerInteraction?: bool, useNewDefaultTickSpacing?: bool }" } }, "grid": { diff --git a/docs/pages/x/api/charts/line-chart.json b/docs/pages/x/api/charts/line-chart.json index 23568ee759907..04e41c163b83f 100644 --- a/docs/pages/x/api/charts/line-chart.json +++ b/docs/pages/x/api/charts/line-chart.json @@ -34,7 +34,7 @@ "experimentalFeatures": { "type": { "name": "shape", - "description": "{ enablePositionBasedPointerInteraction?: bool, useNewResponsiveTickAdjustment?: bool }" + "description": "{ enablePositionBasedPointerInteraction?: bool, useNewDefaultTickSpacing?: bool }" } }, "grid": { diff --git a/docs/pages/x/api/charts/scatter-chart-premium.json b/docs/pages/x/api/charts/scatter-chart-premium.json index bd26a48c81286..bd85bed145a37 100644 --- a/docs/pages/x/api/charts/scatter-chart-premium.json +++ b/docs/pages/x/api/charts/scatter-chart-premium.json @@ -44,7 +44,7 @@ "deprecationInfo": "Use disableHitArea instead." }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/scatter-chart-pro.json b/docs/pages/x/api/charts/scatter-chart-pro.json index 36570899d7a82..4497781bc38b5 100644 --- a/docs/pages/x/api/charts/scatter-chart-pro.json +++ b/docs/pages/x/api/charts/scatter-chart-pro.json @@ -44,7 +44,7 @@ "deprecationInfo": "Use disableHitArea instead." }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/scatter-chart.json b/docs/pages/x/api/charts/scatter-chart.json index bb95a1466dcc0..2152a0da13e95 100644 --- a/docs/pages/x/api/charts/scatter-chart.json +++ b/docs/pages/x/api/charts/scatter-chart.json @@ -44,7 +44,7 @@ "deprecationInfo": "Use disableHitArea instead." }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ useNewResponsiveTickAdjustment?: bool }" } + "type": { "name": "shape", "description": "{ useNewDefaultTickSpacing?: bool }" } }, "grid": { "type": { "name": "shape", "description": "{ horizontal?: bool, vertical?: bool }" } diff --git a/docs/pages/x/api/charts/spark-line-chart.json b/docs/pages/x/api/charts/spark-line-chart.json index 7e52587797ec2..83e6bec4e4ca3 100644 --- a/docs/pages/x/api/charts/spark-line-chart.json +++ b/docs/pages/x/api/charts/spark-line-chart.json @@ -38,7 +38,7 @@ "experimentalFeatures": { "type": { "name": "shape", - "description": "{ enablePositionBasedPointerInteraction?: bool, useNewResponsiveTickAdjustment?: bool }" + "description": "{ enablePositionBasedPointerInteraction?: bool, useNewDefaultTickSpacing?: bool }" } }, "height": { "type": { "name": "number" } }, diff --git a/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx b/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx index 4cb28d30be9af..265ca999844a4 100644 --- a/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx +++ b/packages/x-charts-premium/src/BarChartPremium/BarChartPremium.tsx @@ -240,7 +240,7 @@ BarChartPremium.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx b/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx index 0a23c5ba1210b..e57bc27763ef8 100644 --- a/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx +++ b/packages/x-charts-premium/src/HeatmapPremium/HeatmapPremium.tsx @@ -145,7 +145,7 @@ HeatmapPremium.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * The height of the chart in px. If not defined, it takes the height of the parent element. diff --git a/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx b/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx index 042cab3156422..139b4e3791c9d 100644 --- a/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx +++ b/packages/x-charts-premium/src/ScatterChartPremium/ScatterChartPremium.tsx @@ -247,7 +247,7 @@ ScatterChartPremium.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index 0a852bce15366..b0b6772ce8f8f 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -198,7 +198,7 @@ BarChartPro.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx index 2bef361009845..5ca3c44fba2d4 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelChart.tsx @@ -259,7 +259,7 @@ FunnelChart.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * The gap, in pixels, between funnel sections. diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 251c7d7d1944a..e20788e72424c 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -240,7 +240,7 @@ Heatmap.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * The height of the chart in px. If not defined, it takes the height of the parent element. diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index ce6f0242fd2dc..1ca57bfa78e5f 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -208,7 +208,7 @@ LineChartPro.propTypes = { */ experimentalFeatures: PropTypes.shape({ enablePositionBasedPointerInteraction: PropTypes.bool, - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index e5fa64a5f639e..6e35842b52333 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -222,7 +222,7 @@ ScatterChartPro.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 9c112ab5662c2..701a485b64e6a 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -225,7 +225,7 @@ BarChart.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 822dbf5929277..cb1542acfd812 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -273,7 +273,7 @@ LineChart.propTypes = { */ experimentalFeatures: PropTypes.shape({ enablePositionBasedPointerInteraction: PropTypes.bool, - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 77ba1f8b64930..672f55483b126 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -266,7 +266,7 @@ ScatterChart.propTypes = { * Options to enable features planned for the next major. */ experimentalFeatures: PropTypes.shape({ - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * Option to display a cartesian grid in the background. diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index 378226a69f691..8cb9e9a08e72c 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -430,7 +430,7 @@ SparkLineChart.propTypes = { */ experimentalFeatures: PropTypes.shape({ enablePositionBasedPointerInteraction: PropTypes.bool, - useNewResponsiveTickAdjustment: PropTypes.bool, + useNewDefaultTickSpacing: PropTypes.bool, }), /** * The height of the chart in px. If not defined, it takes the height of the parent element. diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts index a14b7f300ee39..139c67ca98752 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.selectors.ts @@ -11,7 +11,7 @@ import type { * @example * const enabled = store.use( * selectorChartExperimentalFeaturesState, - * 'useNewResponsiveTickAdjustment', + * 'useNewDefaultTickSpacing', * ); */ export const selectorChartExperimentalFeaturesState = ( diff --git a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts index 7338af50a2484..05a5fac7110cf 100644 --- a/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts +++ b/packages/x-charts/src/internals/plugins/corePlugins/useChartExperimentalFeature/useChartExperimentalFeature.types.ts @@ -26,7 +26,7 @@ interface CartesianExperimentalFeatures { * Explicit `tickNumber`, `tickSpacing`, or `tickInterval` values set by the * consumer are not overridden. */ - useNewResponsiveTickAdjustment?: boolean; + useNewDefaultTickSpacing?: boolean; } /* True if any cartesian series (which can have `band` / `point` scales) is in `SeriesType`. */ diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx index 1a22a34f2afbb..e0f6e33baabbc 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxis.test.tsx @@ -6,7 +6,7 @@ import { isJSDOM } from 'test/utils/skipIf'; describe('useChartCartesianAxis', () => { const { render } = createRenderer(); - describe('experimentalFeatures.useNewResponsiveTickAdjustment', () => { + describe('experimentalFeatures.useNewDefaultTickSpacing', () => { const manyCategories = Array.from({ length: 20 }, (_, i) => `cat-${i}`); const data = manyCategories.map((_, i) => i); @@ -36,7 +36,7 @@ describe('useChartCartesianAxis', () => { width={300} height={200} margin={0} - experimentalFeatures={{ useNewResponsiveTickAdjustment: true }} + experimentalFeatures={{ useNewDefaultTickSpacing: true }} />, ); @@ -57,7 +57,7 @@ describe('useChartCartesianAxis', () => { width={300} height={200} margin={0} - experimentalFeatures={{ useNewResponsiveTickAdjustment: true }} + experimentalFeatures={{ useNewDefaultTickSpacing: true }} />, ); @@ -75,7 +75,7 @@ describe('useChartCartesianAxis', () => { width={300} height={200} margin={0} - experimentalFeatures={{ useNewResponsiveTickAdjustment: true }} + experimentalFeatures={{ useNewDefaultTickSpacing: true }} />, ); diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts index df6abc4794c5c..23b7fa55cda30 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts @@ -58,7 +58,7 @@ import { selectorChartExperimentalFeaturesState } from '../../corePlugins/useCha * selectors. Wrap it to bind the feature name we care about. */ const selectorResponsiveTickAdjustment = ( state: Parameters[0], -) => selectorChartExperimentalFeaturesState(state, 'useNewResponsiveTickAdjustment'); +) => selectorChartExperimentalFeaturesState(state, 'useNewDefaultTickSpacing'); export const createZoomMap = (zoom: readonly ZoomData[]) => { const zoomItemMap = new Map(); From 5b3e212954e74def6f7a671ca95bdcaa547eae93 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 10 Jun 2026 16:03:26 +0200 Subject: [PATCH 10/10] test --- .../useChartCartesianAxisRendering.selectors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts index 9c7114b9c1a90..1e67ff563a56a 100644 --- a/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts +++ b/packages/x-charts/src/internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisRendering.selectors.ts @@ -62,7 +62,7 @@ import getMarkerSize, { * selectors. Wrap it to bind the feature name we care about. */ const selectorResponsiveTickAdjustment = ( state: Parameters[0], -) => selectorChartExperimentalFeaturesState(state, 'useNewDefaultTickSpacing'); +) => selectorChartExperimentalFeaturesState(state, 'useNewDefaultTickSpacing') || true; // Dumb modification to see the impact on the entire docs export const createZoomMap = (zoom: readonly ZoomData[]) => { const zoomItemMap = new Map();