From 15bb28247eab0aec791465f21ca5dbf4008fbf3c Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 29 May 2025 16:46:31 +0200 Subject: [PATCH 1/7] [charts-pro] Add correct classes to `FunnelSectionLabel` --- docs/data/charts/funnel/FunnelLabelStyling.js | 30 +++++++++ .../data/charts/funnel/FunnelLabelStyling.tsx | 30 +++++++++ .../funnel/FunnelLabelStyling.tsx.preview | 14 ++++ docs/data/charts/funnel/funnel.md | 6 ++ docs/pages/x/api/charts/funnel-chart.json | 13 +++- .../charts/funnel-chart/funnel-chart.json | 3 +- .../src/FunnelChart/FunnelPlot.tsx | 32 +++------ .../src/FunnelChart/FunnelSectionLabel.tsx | 66 +++++++++++++++++++ .../src/FunnelChart/funnelPlotSlots.types.ts | 11 ++++ .../src/FunnelChart/funnelSectionClasses.ts | 17 ++++- .../x-charts-pro/src/FunnelChart/index.ts | 2 + scripts/x-charts-pro.exports.json | 2 + 12 files changed, 198 insertions(+), 28 deletions(-) create mode 100644 docs/data/charts/funnel/FunnelLabelStyling.js create mode 100644 docs/data/charts/funnel/FunnelLabelStyling.tsx create mode 100644 docs/data/charts/funnel/FunnelLabelStyling.tsx.preview create mode 100644 packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx diff --git a/docs/data/charts/funnel/FunnelLabelStyling.js b/docs/data/charts/funnel/FunnelLabelStyling.js new file mode 100644 index 0000000000000..76fe7103abdbb --- /dev/null +++ b/docs/data/charts/funnel/FunnelLabelStyling.js @@ -0,0 +1,30 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import { Unstable_FunnelChart as FunnelChart } from '@mui/x-charts-pro/FunnelChart'; +import { funnelSectionClasses } from '@mui/x-charts-pro/FunnelChart'; + +export default function FunnelLabelStyling() { + return ( + + + + ); +} + +const funnelProps = { + height: 300, + hideLegend: true, +}; diff --git a/docs/data/charts/funnel/FunnelLabelStyling.tsx b/docs/data/charts/funnel/FunnelLabelStyling.tsx new file mode 100644 index 0000000000000..7ef758301bd0e --- /dev/null +++ b/docs/data/charts/funnel/FunnelLabelStyling.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import { Unstable_FunnelChart as FunnelChart } from '@mui/x-charts-pro/FunnelChart'; +import { funnelSectionClasses } from '@mui/x-charts-pro/FunnelChart'; + +export default function FunnelLabelStyling() { + return ( + + + + ); +} + +const funnelProps = { + height: 300, + hideLegend: true, +} as const; diff --git a/docs/data/charts/funnel/FunnelLabelStyling.tsx.preview b/docs/data/charts/funnel/FunnelLabelStyling.tsx.preview new file mode 100644 index 0000000000000..179187ce66741 --- /dev/null +++ b/docs/data/charts/funnel/FunnelLabelStyling.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/data/charts/funnel/funnel.md b/docs/data/charts/funnel/funnel.md index aca734428eb00..c392f8a302e65 100644 --- a/docs/data/charts/funnel/funnel.md +++ b/docs/data/charts/funnel/funnel.md @@ -45,6 +45,12 @@ To format the labels, a `valueFormatter` function can be provided. {{"demo": "FunnelLabels.js"}} +### Styling labels + +The labels can be styled by using the `funnelSectionClasses.label` helper. + +{{"demo": "FunnelLabelStyling.js"}} + ### Positioning labels The labels can be positioned relative to the section they represent. diff --git a/docs/pages/x/api/charts/funnel-chart.json b/docs/pages/x/api/charts/funnel-chart.json index 056f26e0bc1ae..1a0a227d43040 100644 --- a/docs/pages/x/api/charts/funnel-chart.json +++ b/docs/pages/x/api/charts/funnel-chart.json @@ -105,7 +105,18 @@ "class": null }, { "name": "baseIconButton", "description": "", "class": null }, - { "name": "funnelSection", "description": "", "class": null }, + { + "name": "funnelSection", + "description": "Custom component for funnel section.", + "default": "FunnelSection", + "class": null + }, + { + "name": "funnelSectionLabel", + "description": "Custom component for funnel section label.", + "default": "FunnelSectionLabel", + "class": null + }, { "name": "legend", "description": "Custom rendering of the legend.", diff --git a/docs/translations/api-docs/charts/funnel-chart/funnel-chart.json b/docs/translations/api-docs/charts/funnel-chart/funnel-chart.json index fb29dda584ceb..78e4ffea6beda 100644 --- a/docs/translations/api-docs/charts/funnel-chart/funnel-chart.json +++ b/docs/translations/api-docs/charts/funnel-chart/funnel-chart.json @@ -63,7 +63,8 @@ "axisTick": "Custom component for the axis tick.", "axisTickLabel": "Custom component for tick label.", "baseIconButton": "", - "funnelSection": "", + "funnelSection": "Custom component for funnel section.", + "funnelSectionLabel": "Custom component for funnel section label.", "legend": "Custom rendering of the legend.", "loadingOverlay": "Overlay component rendered when the chart is in a loading state.", "noDataOverlay": "Overlay component rendered when the chart has no data to display.", diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx index 5da13412e4dd0..a4fe05a9d7de0 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx @@ -4,13 +4,13 @@ import PropTypes from 'prop-types'; import { line as d3Line } from '@mui/x-charts-vendor/d3-shape'; import { ComputedAxis, cartesianSeriesTypes } from '@mui/x-charts/internals'; import { useXAxes, useYAxes } from '@mui/x-charts/hooks'; -import { useTheme } from '@mui/material/styles'; import { FunnelItemIdentifier, FunnelDataPoints } from './funnel.types'; import { FunnelSection } from './FunnelSection'; import { alignLabel, positionLabel } from './labelUtils'; import { FunnelPlotSlotExtension } from './funnelPlotSlots.types'; import { useFunnelSeriesContext } from '../hooks/useFunnelSeries'; import { getFunnelCurve } from './curves'; +import { FunnelSectionLabel } from './FunnelSectionLabel'; cartesianSeriesTypes.addType('funnel'); @@ -180,7 +180,6 @@ const useAggregatedData = (gap: number | undefined) => { function FunnelPlot(props: FunnelPlotProps) { const { onItemClick, gap, ...other } = props; - const theme = useTheme(); const data = useAggregatedData(gap); @@ -203,32 +202,19 @@ function FunnelPlot(props: FunnelPlotProps) { } /> ))} - {data.map(({ id, label }) => { - if (!label) { + {data.map(({ id, label, seriesId, dataIndex }) => { + if (!label || !label.value) { return null; } return ( - - {label.value} - + label={label} + dataIndex={dataIndex} + seriesId={seriesId} + {...other} + /> ); })} diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx new file mode 100644 index 0000000000000..fa00282efc7ab --- /dev/null +++ b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx @@ -0,0 +1,66 @@ +'use client'; +import * as React from 'react'; +import { consumeSlots, SeriesId } from '@mui/x-charts/internals'; +import { FunnelSectionClasses, useLabelUtilityClasses } from './funnelSectionClasses'; +import { useTheme } from '@mui/material/styles'; + +export interface FunnelSectionLabelConfig { + x: number; + y: number; + value: string | null; + textAnchor?: React.SVGProps['textAnchor']; + dominantBaseline?: React.SVGProps['dominantBaseline']; +} + +export interface FunnelSectionLabelProps + extends Omit, 'ref' | 'id'> { + classes?: Partial; + label: FunnelSectionLabelConfig; + seriesId: SeriesId; + dataIndex: number; +} + +/** + * @ignore - internal component. + */ +const FunnelSectionLabel = consumeSlots( + 'MuiFunnelSectionLabel', + 'funnelSectionLabel', + { + classesResolver: useLabelUtilityClasses, + }, + React.forwardRef(function FunnelSectionLabel( + props: FunnelSectionLabelProps, + ref: React.Ref, + ) { + const { classes, color, onClick, className, label, ...other } = props; + const theme = useTheme(); + + return ( + + {label.value} + + ); + }), +); + +export { FunnelSectionLabel }; diff --git a/packages/x-charts-pro/src/FunnelChart/funnelPlotSlots.types.ts b/packages/x-charts-pro/src/FunnelChart/funnelPlotSlots.types.ts index 45df9d80ec1f3..1ca7cda4f8f7e 100644 --- a/packages/x-charts-pro/src/FunnelChart/funnelPlotSlots.types.ts +++ b/packages/x-charts-pro/src/FunnelChart/funnelPlotSlots.types.ts @@ -1,12 +1,23 @@ import * as React from 'react'; import type { FunnelSectionProps } from './FunnelSection'; +import { FunnelSectionLabelProps } from './FunnelSectionLabel'; export interface FunnelPlotSlots { + /** + * Custom component for funnel section. + * @default FunnelSection + */ funnelSection?: React.ElementType; + /** + * Custom component for funnel section label. + * @default FunnelSectionLabel + */ + funnelSectionLabel?: React.ElementType; } export interface FunnelPlotSlotProps { funnelSection?: FunnelSectionProps; + funnelSectionLabel?: FunnelSectionLabelProps; } export interface FunnelPlotSlotExtension { diff --git a/packages/x-charts-pro/src/FunnelChart/funnelSectionClasses.ts b/packages/x-charts-pro/src/FunnelChart/funnelSectionClasses.ts index 5d971edf0fa22..ee16a3d4004e7 100644 --- a/packages/x-charts-pro/src/FunnelChart/funnelSectionClasses.ts +++ b/packages/x-charts-pro/src/FunnelChart/funnelSectionClasses.ts @@ -2,6 +2,7 @@ import generateUtilityClass from '@mui/utils/generateUtilityClass'; import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; import composeClasses from '@mui/utils/composeClasses'; import type { FunnelSectionProps } from './FunnelSection'; +import type { FunnelSectionLabelProps } from './FunnelSectionLabel'; export interface FunnelSectionClasses { /** Styles applied to the root element. */ @@ -28,10 +29,10 @@ function getFunnelSectionUtilityClass(slot: string) { } export const useUtilityClasses = (props: FunnelSectionProps) => { - const { classes, seriesId, variant } = props; + const { classes, seriesId, variant, dataIndex } = props; const slots = { - root: ['root', `series-${seriesId}`], + root: ['root', `series-${seriesId}`, `data-index-${dataIndex}`], highlighted: ['highlighted'], faded: ['faded'], outlined: variant === 'outlined' ? ['outlined'] : [], @@ -42,7 +43,17 @@ export const useUtilityClasses = (props: FunnelSectionProps) => { return composeClasses(slots, getFunnelSectionUtilityClass, classes); }; +export const useLabelUtilityClasses = (props: FunnelSectionLabelProps) => { + const { classes, seriesId, dataIndex } = props; + + const slots = { + label: ['label', `series-${seriesId}`, `data-index-${dataIndex}`], + }; + + return composeClasses(slots, getFunnelSectionUtilityClass, classes); +}; + export const funnelSectionClasses: FunnelSectionClasses = generateUtilityClasses( 'MuiFunnelSection', - ['root', 'highlighted', 'faded', 'filled', 'outlined', 'label', 'series'], + ['root', 'highlighted', 'faded', 'filled', 'outlined', 'label', 'series', 'data-index'], ); diff --git a/packages/x-charts-pro/src/FunnelChart/index.ts b/packages/x-charts-pro/src/FunnelChart/index.ts index dcec5fcbdac58..da965f4de6f97 100644 --- a/packages/x-charts-pro/src/FunnelChart/index.ts +++ b/packages/x-charts-pro/src/FunnelChart/index.ts @@ -7,3 +7,5 @@ export * from './funnelSlots.types'; export type { FunnelCurveType } from './curves'; export { funnelSectionClasses } from './funnelSectionClasses'; export type { FunnelSectionClasses } from './funnelSectionClasses'; +export { FunnelSection } from './FunnelSection'; +export { FunnelSectionLabel } from './FunnelSectionLabel'; diff --git a/scripts/x-charts-pro.exports.json b/scripts/x-charts-pro.exports.json index 69b3e70a3a972..684481ce635d3 100644 --- a/scripts/x-charts-pro.exports.json +++ b/scripts/x-charts-pro.exports.json @@ -191,8 +191,10 @@ { "name": "FunnelLabelOptions", "kind": "TypeAlias" }, { "name": "FunnelPlot", "kind": "Function" }, { "name": "FunnelPlotProps", "kind": "Interface" }, + { "name": "FunnelSection", "kind": "Variable" }, { "name": "funnelSectionClasses", "kind": "Variable" }, { "name": "FunnelSectionClasses", "kind": "Interface" }, + { "name": "FunnelSectionLabel", "kind": "Variable" }, { "name": "FunnelSeriesType", "kind": "Interface" }, { "name": "FunnelValueType", "kind": "TypeAlias" }, { "name": "Gauge", "kind": "Variable" }, From a85bf6f677aaad3f925f4b13d97ba4faa9382d52 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Fri, 30 May 2025 09:14:10 +0200 Subject: [PATCH 2/7] [charts-pro] Add data attributes to `FunnelChart` --- packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx | 4 ++++ packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx | 2 ++ 2 files changed, 6 insertions(+) diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx index 30ae2d74464a0..ea9a2f3cfbf8b 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx @@ -62,6 +62,10 @@ const FunnelSection = consumeSlots( strokeWidth={isOutlined ? 1.5 : 0} cursor={onClick ? 'pointer' : 'unset'} onClick={onClick} + data-series-id={seriesId} + data-data-index={dataIndex} + data-highlighted={isHighlighted} + data-faded={isFaded} className={clsx( classes?.root, isHighlighted && classes?.highlighted, diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx index fa00282efc7ab..6c24072c47ccf 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx @@ -54,6 +54,8 @@ const FunnelSectionLabel = consumeSlots( y={label.y} textAnchor={label.textAnchor ?? 'middle'} dominantBaseline={label.dominantBaseline ?? 'central'} + data-series-id={props.seriesId} + data-data-index={props.dataIndex} {...other} ref={ref} > From 1982400d8b6e96d091f54230a0d25ea01abe6790 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 17 Jun 2025 17:23:22 +0200 Subject: [PATCH 3/7] lockfile --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 908c4d13a0789..2f727675aa478 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1058,7 +1058,7 @@ importers: version: 7.1.1(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0) '@types/prop-types': specifier: 'catalog:' - version: 15.7.14 + version: 15.7.15 csstype: specifier: 'catalog:' version: 3.1.3 From 5ccbca0ef7cf5d15a4728a56394b42dec4f74893 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 17 Jun 2025 17:27:53 +0200 Subject: [PATCH 4/7] data --- packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx | 8 ++++---- .../x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx index ea9a2f3cfbf8b..e95068f5a092e 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx @@ -62,10 +62,10 @@ const FunnelSection = consumeSlots( strokeWidth={isOutlined ? 1.5 : 0} cursor={onClick ? 'pointer' : 'unset'} onClick={onClick} - data-series-id={seriesId} - data-data-index={dataIndex} - data-highlighted={isHighlighted} - data-faded={isFaded} + data-series={seriesId} + data-index={dataIndex} + data-highlighted={isHighlighted || undefined} + data-faded={isFaded || undefined} className={clsx( classes?.root, isHighlighted && classes?.highlighted, diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx index d516253ea825c..dcbb960e04c04 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx @@ -54,8 +54,8 @@ const FunnelSectionLabel = consumeSlots( y={label.y} textAnchor={label.textAnchor ?? 'middle'} dominantBaseline={label.dominantBaseline ?? 'central'} - data-series-id={props.seriesId} - data-data-index={props.dataIndex} + data-series={props.seriesId} + data-index={props.dataIndex} {...other} ref={ref} > From 2c7214680835dfb90aaae578222e72e70e61d8d2 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 17 Jun 2025 18:08:33 +0200 Subject: [PATCH 5/7] data-series --- .../src/FunnelChart/FunnelPlot.tsx | 72 +++++++++++-------- .../src/FunnelChart/FunnelSection.tsx | 2 - .../src/FunnelChart/FunnelSectionLabel.tsx | 2 - 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx index c3266ea4c1e85..2ee1d26c0f8ca 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx @@ -209,7 +209,7 @@ const useAggregatedData = () => { }); }); - return result.flat(); + return result; }, [seriesData, xAxis, xAxisIds, yAxis, yAxisIds, gap]); return allData; @@ -222,36 +222,48 @@ function FunnelPlot(props: FunnelPlotProps) { return ( - {data.map(({ d, color, id, seriesId, dataIndex, variant }) => ( - { - onItemClick(event, { type: 'funnel', seriesId, dataIndex }); - }) - } - /> - ))} - {data.map(({ id, label, seriesId, dataIndex }) => { - if (!label || !label.value) { - return null; - } - + {data.map((series) => { + return ( + + {series.map(({ d, color, id, seriesId, dataIndex, variant }) => ( + { + onItemClick(event, { type: 'funnel', seriesId, dataIndex }); + }) + } + /> + ))} + + ); + })} + {data.map((series) => { return ( - + + {series.map(({ id, label, seriesId, dataIndex }) => { + if (!label || !label.value) { + return null; + } + + return ( + + ); + })} + ); })} diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx index e95068f5a092e..31717ede51c92 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelSection.tsx @@ -62,8 +62,6 @@ const FunnelSection = consumeSlots( strokeWidth={isOutlined ? 1.5 : 0} cursor={onClick ? 'pointer' : 'unset'} onClick={onClick} - data-series={seriesId} - data-index={dataIndex} data-highlighted={isHighlighted || undefined} data-faded={isFaded || undefined} className={clsx( diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx index dcbb960e04c04..53bc5c73bd1da 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelSectionLabel.tsx @@ -54,8 +54,6 @@ const FunnelSectionLabel = consumeSlots( y={label.y} textAnchor={label.textAnchor ?? 'middle'} dominantBaseline={label.dominantBaseline ?? 'central'} - data-series={props.seriesId} - data-index={props.dataIndex} {...other} ref={ref} > From 526089331d6213452414d7209c64ebbf5033225d Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Tue, 17 Jun 2025 19:38:12 +0200 Subject: [PATCH 6/7] add docs --- .../charts/funnel/FunnelDataAttributes.js | 40 +++++++++++++++++++ .../charts/funnel/FunnelDataAttributes.tsx | 40 +++++++++++++++++++ .../funnel/FunnelDataAttributes.tsx.preview | 16 ++++++++ docs/data/charts/funnel/funnel.md | 10 +++++ 4 files changed, 106 insertions(+) create mode 100644 docs/data/charts/funnel/FunnelDataAttributes.js create mode 100644 docs/data/charts/funnel/FunnelDataAttributes.tsx create mode 100644 docs/data/charts/funnel/FunnelDataAttributes.tsx.preview diff --git a/docs/data/charts/funnel/FunnelDataAttributes.js b/docs/data/charts/funnel/FunnelDataAttributes.js new file mode 100644 index 0000000000000..33505c0af80c9 --- /dev/null +++ b/docs/data/charts/funnel/FunnelDataAttributes.js @@ -0,0 +1,40 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import { + Unstable_FunnelChart as FunnelChart, + funnelSectionClasses, +} from '@mui/x-charts-pro/FunnelChart'; + +export default function FunnelDataAttributes() { + return ( + + + + + + + + + + + + ); +} + +const funnelProps = { + height: 300, + hideLegend: true, + series: [ + { + id: 'main', + data: [{ value: 200 }, { value: 180 }, { value: 90 }, { value: 50 }], + }, + ], +}; diff --git a/docs/data/charts/funnel/FunnelDataAttributes.tsx b/docs/data/charts/funnel/FunnelDataAttributes.tsx new file mode 100644 index 0000000000000..4c9d77a94cf72 --- /dev/null +++ b/docs/data/charts/funnel/FunnelDataAttributes.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import { + Unstable_FunnelChart as FunnelChart, + funnelSectionClasses, +} from '@mui/x-charts-pro/FunnelChart'; + +export default function FunnelDataAttributes() { + return ( + + + + + + + + + + + + ); +} + +const funnelProps = { + height: 300, + hideLegend: true, + series: [ + { + id: 'main', + data: [{ value: 200 }, { value: 180 }, { value: 90 }, { value: 50 }], + }, + ], +} as const; diff --git a/docs/data/charts/funnel/FunnelDataAttributes.tsx.preview b/docs/data/charts/funnel/FunnelDataAttributes.tsx.preview new file mode 100644 index 0000000000000..846f54b1dadb8 --- /dev/null +++ b/docs/data/charts/funnel/FunnelDataAttributes.tsx.preview @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file diff --git a/docs/data/charts/funnel/funnel.md b/docs/data/charts/funnel/funnel.md index 6d1c173fadeab..2ff49cc937352 100644 --- a/docs/data/charts/funnel/funnel.md +++ b/docs/data/charts/funnel/funnel.md @@ -123,6 +123,16 @@ The funnel colors can be customized in two ways. {{"demo": "FunnelColor.js"}} +### CSS + +The funnel chart can be styled using CSS. + +Each section group has a `data-series` attribute that can be used to target specific series sections. + +In order to target specific sections, you can use the `:nth-child` or `:nth-child-of-type` selectors as shown in the example below. + +{{"demo": "FunnelDataAttributes.js"}} + ## Multiple funnels By default, multiple series are displayed on top of each other. From c247d6bb743f4487c734efac41d9156cad56d7e2 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Wed, 18 Jun 2025 12:51:40 +0200 Subject: [PATCH 7/7] fix empty series --- packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx b/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx index 2ee1d26c0f8ca..e173b0393d10c 100644 --- a/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx +++ b/packages/x-charts-pro/src/FunnelChart/FunnelPlot.tsx @@ -223,6 +223,10 @@ function FunnelPlot(props: FunnelPlotProps) { return ( {data.map((series) => { + if (series.length === 0) { + return null; + } + return ( {series.map(({ d, color, id, seriesId, dataIndex, variant }) => ( @@ -246,6 +250,10 @@ function FunnelPlot(props: FunnelPlotProps) { ); })} {data.map((series) => { + if (series.length === 0) { + return null; + } + return ( {series.map(({ id, label, seriesId, dataIndex }) => {