diff --git a/docs/data/charts/tooltip/CustomAxisTooltip.js b/docs/data/charts/tooltip/CustomAxisTooltip.js index b65f7d3df4b2..0d0693111c49 100644 --- a/docs/data/charts/tooltip/CustomAxisTooltip.js +++ b/docs/data/charts/tooltip/CustomAxisTooltip.js @@ -1,184 +1,82 @@ import * as React from 'react'; -import NoSsr from '@mui/material/NoSsr'; -import Popper from '@mui/material/Popper'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; -import { useAxisTooltip } from '@mui/x-charts/ChartsTooltip'; -import { useSvgRef } from '@mui/x-charts/hooks'; - -function usePointer() { - const svgRef = useSvgRef(); - const popperRef = React.useRef(null); - const positionRef = React.useRef({ x: 0, y: 0 }); - - // Use a ref to avoid rerendering on every mousemove event. - const [pointer, setPointer] = React.useState({ - isActive: false, - isMousePointer: false, - pointerHeight: 0, - }); - - React.useEffect(() => { - const element = svgRef.current; - if (element === null) { - return () => {}; - } - - const handleOut = (event) => { - if (event.pointerType !== 'mouse') { - setPointer((prev) => ({ - ...prev, - isActive: false, - })); - } - }; - - const handleEnter = (event) => { - setPointer({ - isActive: true, - isMousePointer: event.pointerType === 'mouse', - pointerHeight: event.height, - }); - }; - - const handleMove = (event) => { - positionRef.current = { - x: event.clientX, - y: event.clientY, - }; - popperRef.current?.update(); - }; - - element.addEventListener('pointerenter', handleEnter); - element.addEventListener('pointerup', handleOut); - element.addEventListener('pointermove', handleMove); - - return () => { - element.removeEventListener('pointerenter', handleEnter); - element.removeEventListener('pointerup', handleOut); - element.removeEventListener('pointermove', handleMove); - }; - }, [svgRef]); - - return { - ...pointer, - popperRef, - anchorEl: { - getBoundingClientRect: () => ({ - x: positionRef.current.x, - y: positionRef.current.y, - top: positionRef.current.y, - left: positionRef.current.x, - right: positionRef.current.x, - bottom: positionRef.current.y, - width: 0, - height: 0, - toJSON: () => '', - }), - }, - }; -} +import { ChartsTooltipContainer, useAxisTooltip } from '@mui/x-charts/ChartsTooltip'; export function CustomAxisTooltip() { const tooltipData = useAxisTooltip(); - const { isActive, isMousePointer, pointerHeight, popperRef, anchorEl } = - usePointer(); - if (!tooltipData || !isActive) { + if (!tooltipData) { // No data to display return null; } - - // The pointer type can be used to have different behavior based on pointer type. - // Adapt the tooltip offset to the size of the pointer. - const yOffset = isMousePointer ? 0 : 40 - pointerHeight; - return ( - - + theme.zIndex.modal, - }} - open - placement={isMousePointer ? 'top-end' : 'top'} - anchorEl={anchorEl} - popperRef={popperRef} - modifiers={[ - { - name: 'offset', - options: { - offset: [0, yOffset], + m: 1, + border: 'solid', + borderWidth: 2, + borderColor: 'divider', + table: { borderSpacing: 0 }, + thead: { + td: { + px: 1.5, + py: 0.75, + borderBottom: 'solid', + borderWidth: 2, + borderColor: 'divider', }, }, - ]} - > - - - - -
- {tooltipData.axisFormattedValue} + }, + }} + > + + + + + + + + {tooltipData.seriesItems.map((seriesItem) => ( + + + + - - - {tooltipData.seriesItems.map((seriesItem) => ( - - - - - - ))} - -
+ {tooltipData.axisFormattedValue} +
+
+
+ + {seriesItem.formattedLabel} + + + {seriesItem.formattedValue}
-
-
- - {seriesItem.formattedLabel} - - - {seriesItem.formattedValue} -
- - - + ))} + +
+
+ ); } diff --git a/docs/data/charts/tooltip/CustomAxisTooltip.tsx b/docs/data/charts/tooltip/CustomAxisTooltip.tsx index 010af780809f..0d0693111c49 100644 --- a/docs/data/charts/tooltip/CustomAxisTooltip.tsx +++ b/docs/data/charts/tooltip/CustomAxisTooltip.tsx @@ -1,190 +1,82 @@ import * as React from 'react'; -import NoSsr from '@mui/material/NoSsr'; -import Popper, { PopperProps } from '@mui/material/Popper'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; -import { useAxisTooltip } from '@mui/x-charts/ChartsTooltip'; -import { useSvgRef } from '@mui/x-charts/hooks'; - -type PointerState = { - isActive: boolean; - isMousePointer: boolean; - pointerHeight: number; -}; - -function usePointer(): PointerState & Pick { - const svgRef = useSvgRef(); - const popperRef: PopperProps['popperRef'] = React.useRef(null); - const positionRef = React.useRef({ x: 0, y: 0 }); - - // Use a ref to avoid rerendering on every mousemove event. - const [pointer, setPointer] = React.useState({ - isActive: false, - isMousePointer: false, - pointerHeight: 0, - }); - - React.useEffect(() => { - const element = svgRef.current; - if (element === null) { - return () => {}; - } - - const handleOut = (event: PointerEvent) => { - if (event.pointerType !== 'mouse') { - setPointer((prev) => ({ - ...prev, - isActive: false, - })); - } - }; - - const handleEnter = (event: PointerEvent) => { - setPointer({ - isActive: true, - isMousePointer: event.pointerType === 'mouse', - pointerHeight: event.height, - }); - }; - - const handleMove = (event: PointerEvent) => { - positionRef.current = { - x: event.clientX, - y: event.clientY, - }; - popperRef.current?.update(); - }; - - element.addEventListener('pointerenter', handleEnter); - element.addEventListener('pointerup', handleOut); - element.addEventListener('pointermove', handleMove); - - return () => { - element.removeEventListener('pointerenter', handleEnter); - element.removeEventListener('pointerup', handleOut); - element.removeEventListener('pointermove', handleMove); - }; - }, [svgRef]); - - return { - ...pointer, - popperRef, - anchorEl: { - getBoundingClientRect: () => ({ - x: positionRef.current.x, - y: positionRef.current.y, - top: positionRef.current.y, - left: positionRef.current.x, - right: positionRef.current.x, - bottom: positionRef.current.y, - width: 0, - height: 0, - toJSON: () => '', - }), - }, - }; -} +import { ChartsTooltipContainer, useAxisTooltip } from '@mui/x-charts/ChartsTooltip'; export function CustomAxisTooltip() { const tooltipData = useAxisTooltip(); - const { isActive, isMousePointer, pointerHeight, popperRef, anchorEl } = - usePointer(); - if (!tooltipData || !isActive) { + if (!tooltipData) { // No data to display return null; } - - // The pointer type can be used to have different behavior based on pointer type. - // Adapt the tooltip offset to the size of the pointer. - const yOffset = isMousePointer ? 0 : 40 - pointerHeight; - return ( - - + theme.zIndex.modal, - }} - open - placement={isMousePointer ? 'top-end' : 'top'} - anchorEl={anchorEl} - popperRef={popperRef} - modifiers={[ - { - name: 'offset', - options: { - offset: [0, yOffset], + m: 1, + border: 'solid', + borderWidth: 2, + borderColor: 'divider', + table: { borderSpacing: 0 }, + thead: { + td: { + px: 1.5, + py: 0.75, + borderBottom: 'solid', + borderWidth: 2, + borderColor: 'divider', }, }, - ]} - > - - - - -
- {tooltipData.axisFormattedValue} + }, + }} + > + + + + + + + + {tooltipData.seriesItems.map((seriesItem) => ( + + + + - - - {tooltipData.seriesItems.map((seriesItem) => ( - - - - - - ))} - -
+ {tooltipData.axisFormattedValue} +
+
+
+ + {seriesItem.formattedLabel} + + + {seriesItem.formattedValue}
-
-
- - {seriesItem.formattedLabel} - - - {seriesItem.formattedValue} -
- - - + ))} + +
+
+ ); } diff --git a/docs/data/charts/tooltip/CustomItemTooltip.js b/docs/data/charts/tooltip/CustomItemTooltip.js index 2f7c2310c5d5..99ceb0dca0ff 100644 --- a/docs/data/charts/tooltip/CustomItemTooltip.js +++ b/docs/data/charts/tooltip/CustomItemTooltip.js @@ -1,144 +1,44 @@ import * as React from 'react'; -import NoSsr from '@mui/material/NoSsr'; -import Popper from '@mui/material/Popper'; import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; -import { useSvgRef } from '@mui/x-charts/hooks'; - -function usePointer() { - const svgRef = useSvgRef(); - const popperRef = React.useRef(null); - const positionRef = React.useRef({ x: 0, y: 0 }); - - // Use a ref to avoid rerendering on every mousemove event. - const [pointer, setPointer] = React.useState({ - isActive: false, - isMousePointer: false, - pointerHeight: 0, - }); - - React.useEffect(() => { - const element = svgRef.current; - if (element === null) { - return () => {}; - } - - const handleOut = (event) => { - if (event.pointerType !== 'mouse') { - setPointer((prev) => ({ - ...prev, - isActive: false, - })); - } - }; - - const handleEnter = (event) => { - setPointer({ - isActive: true, - isMousePointer: event.pointerType === 'mouse', - pointerHeight: event.height, - }); - }; - - const handleMove = (event) => { - positionRef.current = { - x: event.clientX, - y: event.clientY, - }; - popperRef.current?.update(); - }; - - element.addEventListener('pointerenter', handleEnter); - element.addEventListener('pointerup', handleOut); - element.addEventListener('pointermove', handleMove); - - return () => { - element.removeEventListener('pointerenter', handleEnter); - element.removeEventListener('pointerup', handleOut); - element.removeEventListener('pointermove', handleMove); - }; - }, [svgRef]); - - return { - ...pointer, - popperRef, - anchorEl: { - getBoundingClientRect: () => ({ - x: positionRef.current.x, - y: positionRef.current.y, - top: positionRef.current.y, - left: positionRef.current.x, - right: positionRef.current.x, - bottom: positionRef.current.y, - width: 0, - height: 0, - toJSON: () => '', - }), - }, - }; -} +import { ChartsTooltipContainer, useItemTooltip } from '@mui/x-charts/ChartsTooltip'; export function CustomItemTooltip() { const tooltipData = useItemTooltip(); - const { isActive, isMousePointer, pointerHeight, popperRef, anchorEl } = - usePointer(); - if (!tooltipData || !isActive) { + if (!tooltipData) { // No data to display return null; } - // Adapt the tooltip offset to the size of the pointer. - const yOffset = isMousePointer ? 0 : 40 - pointerHeight; - return ( - - + theme.zIndex.modal, + m: 1, + p: 1.5, + border: 'solid', + borderWidth: 2, + borderColor: 'divider', }} - open - placement={isMousePointer ? 'top-end' : 'top'} - anchorEl={anchorEl} - popperRef={popperRef} - modifiers={[ - { - name: 'offset', - options: { - offset: [0, yOffset], - }, - }, - ]} > - - -
- - {tooltipData.label} - - {tooltipData.formattedValue} - - - - + +
+ + {tooltipData.label} + + {tooltipData.formattedValue} + + + ); } diff --git a/docs/data/charts/tooltip/CustomItemTooltip.tsx b/docs/data/charts/tooltip/CustomItemTooltip.tsx index 077243411c5d..99ceb0dca0ff 100644 --- a/docs/data/charts/tooltip/CustomItemTooltip.tsx +++ b/docs/data/charts/tooltip/CustomItemTooltip.tsx @@ -1,150 +1,44 @@ import * as React from 'react'; -import NoSsr from '@mui/material/NoSsr'; -import Popper, { PopperProps } from '@mui/material/Popper'; import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; -import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; -import { useSvgRef } from '@mui/x-charts/hooks'; - -type PointerState = { - isActive: boolean; - isMousePointer: boolean; - pointerHeight: number; -}; - -function usePointer(): PointerState & Pick { - const svgRef = useSvgRef(); - const popperRef: PopperProps['popperRef'] = React.useRef(null); - const positionRef = React.useRef({ x: 0, y: 0 }); - - // Use a ref to avoid rerendering on every mousemove event. - const [pointer, setPointer] = React.useState({ - isActive: false, - isMousePointer: false, - pointerHeight: 0, - }); - - React.useEffect(() => { - const element = svgRef.current; - if (element === null) { - return () => {}; - } - - const handleOut = (event: PointerEvent) => { - if (event.pointerType !== 'mouse') { - setPointer((prev) => ({ - ...prev, - isActive: false, - })); - } - }; - - const handleEnter = (event: PointerEvent) => { - setPointer({ - isActive: true, - isMousePointer: event.pointerType === 'mouse', - pointerHeight: event.height, - }); - }; - - const handleMove = (event: PointerEvent) => { - positionRef.current = { - x: event.clientX, - y: event.clientY, - }; - popperRef.current?.update(); - }; - - element.addEventListener('pointerenter', handleEnter); - element.addEventListener('pointerup', handleOut); - element.addEventListener('pointermove', handleMove); - - return () => { - element.removeEventListener('pointerenter', handleEnter); - element.removeEventListener('pointerup', handleOut); - element.removeEventListener('pointermove', handleMove); - }; - }, [svgRef]); - - return { - ...pointer, - popperRef, - anchorEl: { - getBoundingClientRect: () => ({ - x: positionRef.current.x, - y: positionRef.current.y, - top: positionRef.current.y, - left: positionRef.current.x, - right: positionRef.current.x, - bottom: positionRef.current.y, - width: 0, - height: 0, - toJSON: () => '', - }), - }, - }; -} +import { ChartsTooltipContainer, useItemTooltip } from '@mui/x-charts/ChartsTooltip'; export function CustomItemTooltip() { const tooltipData = useItemTooltip(); - const { isActive, isMousePointer, pointerHeight, popperRef, anchorEl } = - usePointer(); - if (!tooltipData || !isActive) { + if (!tooltipData) { // No data to display return null; } - // Adapt the tooltip offset to the size of the pointer. - const yOffset = isMousePointer ? 0 : 40 - pointerHeight; - return ( - - + theme.zIndex.modal, + m: 1, + p: 1.5, + border: 'solid', + borderWidth: 2, + borderColor: 'divider', }} - open - placement={isMousePointer ? 'top-end' : 'top'} - anchorEl={anchorEl} - popperRef={popperRef} - modifiers={[ - { - name: 'offset', - options: { - offset: [0, yOffset], - }, - }, - ]} > - - -
- - {tooltipData.label} - - {tooltipData.formattedValue} - - - - + +
+ + {tooltipData.label} + + {tooltipData.formattedValue} + + + ); } diff --git a/docs/data/charts/tooltip/CustomItemTooltipContent.js b/docs/data/charts/tooltip/CustomItemTooltipContent.js deleted file mode 100644 index 6cda5693841c..000000000000 --- a/docs/data/charts/tooltip/CustomItemTooltipContent.js +++ /dev/null @@ -1,37 +0,0 @@ -import * as React from 'react'; -import Stack from '@mui/material/Stack'; -import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; - -/** - * Render a basic tooltip content for an item. - */ -export function CustomItemTooltipContent(props) { - return ( - - -
- - {props.label} - - {props.formattedValue} - - - ); -} diff --git a/docs/data/charts/tooltip/CustomItemTooltipContent.tsx b/docs/data/charts/tooltip/CustomItemTooltipContent.tsx deleted file mode 100644 index a85a7ec3fe28..000000000000 --- a/docs/data/charts/tooltip/CustomItemTooltipContent.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; -import Stack from '@mui/material/Stack'; -import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; -import { UseItemTooltipReturnValue } from '@mui/x-charts/ChartsTooltip'; -import { ChartSeriesType } from '@mui/x-charts/internals'; - -/** - * Render a basic tooltip content for an item. - */ -export function CustomItemTooltipContent( - props: Pick< - UseItemTooltipReturnValue, - 'color' | 'label' | 'formattedValue' - >, -) { - return ( - - -
- - {props.label} - - {props.formattedValue} - - - ); -} diff --git a/docs/data/charts/tooltip/CustomTooltipPosition.js b/docs/data/charts/tooltip/CustomTooltipPosition.js index 7bb8180ba629..0853674803a2 100644 --- a/docs/data/charts/tooltip/CustomTooltipPosition.js +++ b/docs/data/charts/tooltip/CustomTooltipPosition.js @@ -9,6 +9,10 @@ import { BarPlot } from '@mui/x-charts/BarChart'; import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; import { ChartsClipPath } from '@mui/x-charts/ChartsClipPath'; import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis'; +import { + ChartsTooltipContainer, + ChartsItemTooltipContent, +} from '@mui/x-charts/ChartsTooltip'; import { ItemTooltip } from './ItemTooltip'; import { ItemTooltipFixedY } from './ItemTooltipFixedY'; import { ItemTooltipTopElement } from './ItemTooltipTopElement'; @@ -19,6 +23,14 @@ export default function CustomTooltipPosition() { const id = React.useId(); const clipPathId = `${id}-clip-path`; + + // Pick one of the custom tooltip wrapper according to the state. + const TooltipPlacement = + (tooltipType === 'mouse' && ItemTooltip) || + (tooltipType === 'fixedY' && ItemTooltipFixedY) || + (tooltipType === 'itemTop' && ItemTooltipTopElement) || + ChartsTooltipContainer; + return (
@@ -55,9 +67,11 @@ export default function CustomTooltipPosition() { - {tooltipType === 'mouse' && } - {tooltipType === 'fixedY' && } - {tooltipType === 'itemTop' && } + {/* Our custom tooltip wrapper with the default item content. */} + + + +
diff --git a/docs/data/charts/tooltip/CustomTooltipPosition.tsx b/docs/data/charts/tooltip/CustomTooltipPosition.tsx index 49596ca4ed65..4f0deaf7bcd5 100644 --- a/docs/data/charts/tooltip/CustomTooltipPosition.tsx +++ b/docs/data/charts/tooltip/CustomTooltipPosition.tsx @@ -9,6 +9,10 @@ import { BarPlot } from '@mui/x-charts/BarChart'; import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'; import { ChartsClipPath } from '@mui/x-charts/ChartsClipPath'; import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis'; +import { + ChartsTooltipContainer, + ChartsItemTooltipContent, +} from '@mui/x-charts/ChartsTooltip'; import { ItemTooltip } from './ItemTooltip'; import { ItemTooltipFixedY } from './ItemTooltipFixedY'; import { ItemTooltipTopElement } from './ItemTooltipTopElement'; @@ -21,6 +25,14 @@ export default function CustomTooltipPosition() { const id = React.useId(); const clipPathId = `${id}-clip-path`; + + // Pick one of the custom tooltip wrapper according to the state. + const TooltipPlacement = + (tooltipType === 'mouse' && ItemTooltip) || + (tooltipType === 'fixedY' && ItemTooltipFixedY) || + (tooltipType === 'itemTop' && ItemTooltipTopElement) || + ChartsTooltipContainer; + return (
@@ -60,9 +72,11 @@ export default function CustomTooltipPosition() { - {tooltipType === 'mouse' && } - {tooltipType === 'fixedY' && } - {tooltipType === 'itemTop' && } + {/* Our custom tooltip wrapper with the default item content. */} + + + +
diff --git a/docs/data/charts/tooltip/Interaction.js b/docs/data/charts/tooltip/Interaction.js index aa9cfe094a79..d99346368b88 100644 --- a/docs/data/charts/tooltip/Interaction.js +++ b/docs/data/charts/tooltip/Interaction.js @@ -21,8 +21,8 @@ const barChartsParams = { export default function Interaction() { return ( - - + + ); } diff --git a/docs/data/charts/tooltip/Interaction.tsx b/docs/data/charts/tooltip/Interaction.tsx index cacdca34fd5a..5443660027f8 100644 --- a/docs/data/charts/tooltip/Interaction.tsx +++ b/docs/data/charts/tooltip/Interaction.tsx @@ -21,8 +21,8 @@ const barChartsParams = { export default function Interaction() { return ( - - + + ); } diff --git a/docs/data/charts/tooltip/Interaction.tsx.preview b/docs/data/charts/tooltip/Interaction.tsx.preview index dee07e073af0..09da31b473bb 100644 --- a/docs/data/charts/tooltip/Interaction.tsx.preview +++ b/docs/data/charts/tooltip/Interaction.tsx.preview @@ -1,2 +1,2 @@ - - \ No newline at end of file + + \ No newline at end of file diff --git a/docs/data/charts/tooltip/ItemTooltip.js b/docs/data/charts/tooltip/ItemTooltip.js index 4e3b52476e27..17e9e2b3cf77 100644 --- a/docs/data/charts/tooltip/ItemTooltip.js +++ b/docs/data/charts/tooltip/ItemTooltip.js @@ -3,7 +3,6 @@ import NoSsr from '@mui/material/NoSsr'; import Popper from '@mui/material/Popper'; import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; import { useSvgRef } from '@mui/x-charts/hooks'; -import { CustomItemTooltipContent } from './CustomItemTooltipContent'; function usePointer() { const svgRef = useSvgRef(); @@ -78,7 +77,7 @@ function usePointer() { }; } -export function ItemTooltip() { +export function ItemTooltip({ children }) { const tooltipData = useItemTooltip(); const { isActive, isMousePointer, pointerHeight, popperRef, anchorEl } = usePointer(); @@ -111,7 +110,7 @@ export function ItemTooltip() { }, ]} > - + {children} ); diff --git a/docs/data/charts/tooltip/ItemTooltip.tsx b/docs/data/charts/tooltip/ItemTooltip.tsx index 1f4277d578c7..682e0e9d300b 100644 --- a/docs/data/charts/tooltip/ItemTooltip.tsx +++ b/docs/data/charts/tooltip/ItemTooltip.tsx @@ -3,7 +3,6 @@ import NoSsr from '@mui/material/NoSsr'; import Popper, { PopperProps } from '@mui/material/Popper'; import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; import { useSvgRef } from '@mui/x-charts/hooks'; -import { CustomItemTooltipContent } from './CustomItemTooltipContent'; type PointerState = { isActive: boolean; @@ -84,7 +83,7 @@ function usePointer(): PointerState & Pick - + {children} ); diff --git a/docs/data/charts/tooltip/ItemTooltipFixedY.js b/docs/data/charts/tooltip/ItemTooltipFixedY.js index aa11e750dc8d..93f94d31c0e8 100644 --- a/docs/data/charts/tooltip/ItemTooltipFixedY.js +++ b/docs/data/charts/tooltip/ItemTooltipFixedY.js @@ -3,7 +3,6 @@ import NoSsr from '@mui/material/NoSsr'; import Popper from '@mui/material/Popper'; import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; import { useDrawingArea, useSvgRef } from '@mui/x-charts/hooks'; -import { CustomItemTooltipContent } from './CustomItemTooltipContent'; function usePointer() { const svgRef = useSvgRef(); @@ -50,7 +49,7 @@ function usePointer() { return pointer; } -export function ItemTooltipFixedY() { +export function ItemTooltipFixedY({ children }) { const tooltipData = useItemTooltip(); const { isActive } = usePointer(); @@ -109,7 +108,7 @@ export function ItemTooltipFixedY() { }} popperRef={popperRef} > - + {children} ); diff --git a/docs/data/charts/tooltip/ItemTooltipFixedY.tsx b/docs/data/charts/tooltip/ItemTooltipFixedY.tsx index 925b27453789..70c7bf29ec7d 100644 --- a/docs/data/charts/tooltip/ItemTooltipFixedY.tsx +++ b/docs/data/charts/tooltip/ItemTooltipFixedY.tsx @@ -3,7 +3,6 @@ import NoSsr from '@mui/material/NoSsr'; import Popper, { PopperProps } from '@mui/material/Popper'; import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; import { useDrawingArea, useSvgRef } from '@mui/x-charts/hooks'; -import { CustomItemTooltipContent } from './CustomItemTooltipContent'; type PointerState = { isActive: boolean; @@ -56,7 +55,7 @@ function usePointer(): PointerState { return pointer; } -export function ItemTooltipFixedY() { +export function ItemTooltipFixedY({ children }: React.PropsWithChildren) { const tooltipData = useItemTooltip(); const { isActive } = usePointer(); @@ -115,7 +114,7 @@ export function ItemTooltipFixedY() { }} popperRef={popperRef} > - + {children} ); diff --git a/docs/data/charts/tooltip/ItemTooltipTopElement.js b/docs/data/charts/tooltip/ItemTooltipTopElement.js index 538a729564c9..2625c997155f 100644 --- a/docs/data/charts/tooltip/ItemTooltipTopElement.js +++ b/docs/data/charts/tooltip/ItemTooltipTopElement.js @@ -4,7 +4,6 @@ import NoSsr from '@mui/material/NoSsr'; import Popper from '@mui/material/Popper'; import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; import { useSvgRef, useXAxis, useXScale, useYScale } from '@mui/x-charts/hooks'; -import { CustomItemTooltipContent } from './CustomItemTooltipContent'; function usePointer() { const svgRef = useSvgRef(); @@ -51,7 +50,7 @@ function usePointer() { return pointer; } -export function ItemTooltipTopElement() { +export function ItemTooltipTopElement({ children }) { const tooltipData = useItemTooltip(); const { isActive } = usePointer(); // Get xAxis config to access its data array. @@ -115,7 +114,7 @@ export function ItemTooltipTopElement() { }), }} > - + {children} ); diff --git a/docs/data/charts/tooltip/ItemTooltipTopElement.tsx b/docs/data/charts/tooltip/ItemTooltipTopElement.tsx index 9c73fa1d4383..d3f359951d83 100644 --- a/docs/data/charts/tooltip/ItemTooltipTopElement.tsx +++ b/docs/data/charts/tooltip/ItemTooltipTopElement.tsx @@ -4,7 +4,6 @@ import NoSsr from '@mui/material/NoSsr'; import Popper from '@mui/material/Popper'; import { useItemTooltip } from '@mui/x-charts/ChartsTooltip'; import { useSvgRef, useXAxis, useXScale, useYScale } from '@mui/x-charts/hooks'; -import { CustomItemTooltipContent } from './CustomItemTooltipContent'; type PointerState = { isActive: boolean; @@ -57,7 +56,7 @@ function usePointer(): PointerState { return pointer; } -export function ItemTooltipTopElement() { +export function ItemTooltipTopElement({ children }: React.PropsWithChildren) { const tooltipData = useItemTooltip<'bar'>(); const { isActive } = usePointer(); // Get xAxis config to access its data array. @@ -123,7 +122,7 @@ export function ItemTooltipTopElement() { }), }} > - + {children} ); diff --git a/docs/data/charts/tooltip/tooltip.md b/docs/data/charts/tooltip/tooltip.md index f53171fca6e5..d13b996cca3f 100644 --- a/docs/data/charts/tooltip/tooltip.md +++ b/docs/data/charts/tooltip/tooltip.md @@ -1,24 +1,26 @@ --- title: Charts - Tooltip productId: x-charts -components: ChartsTooltip, DefaultChartsAxisTooltipContent, DefaultChartsItemTooltipContent +components: ChartsTooltip, ChartsAxisTooltipContent, ChartsItemTooltipContent, ChartsTooltipContainer --- # Charts - Tooltip

Tooltip provides extra data on charts item.

-In all charts components, you can pass props to the tooltip by using `tooltip={{...}}`. -If you are using composition, you can add the `` component and pass props directly. +In all charts components, the tooltip is accessible via the slot `tooltip`. +If you are using composition, you can use the `` component. ## Tooltip trigger -The tooltip can be triggered by two kinds of events: +The Tooltip can be triggered by two kinds of events: - `'item'`—when the user's mouse hovers over an item on the chart, the tooltip displays data about this specific item. - `'axis'`—the user's mouse position is associated with a value of the x-axis. The tooltip displays data about all series at this specific x value. - `'none'`—disable the tooltip. +To pass this trigger attribute to the tooltip use `slotProps.tooltip.trigger`. + {{"demo": "Interaction.js"}} ## Customization @@ -90,30 +92,49 @@ It removes the header showing the x-axis value from the tooltip. ### Overriding content -To modify the tooltip content, use `slots.itemContent` or `slots.axisContent`. -The first one is rendered when tooltip trigger is set to `"item"`. -The second one when trigger is set to `"axis"`. +To override tooltip content, provide a custom component to `slots.tooltip`. +Some helper are provided, such as: + +- `` which provide a tooltip with built-in open and position management. +- `useItemTooltip()` which provides all basic information associated to the current item. +- `useAxisTooltip()` which provides all basic information associated to the current axis. + +Here is the basic scheme to follow. +Examples about helpers are provided in the composition section. ```jsx -// With single component +import { ChartsTooltipContainer } from '@mui/x-charts/ChartsTooltip'; + +function CustomItemTooltip() { + const tooltipData = useItemTooltip(); + + if (!tooltipData) { // No data to display + return null; + } + + return ( + + {/** Your custom content **/} + + ) +} + // With composition // ... - + ``` +### Overriding placement + +To override tooltip placement, override to the tooltip with `slots.tooltip`. +If you want to keep the default content, you can place the `ChartsItemTooltipContent` or `ChartsAxisTooltipContent` in your custom tooltip. + ## Composition If you're using composition, by default, the axis listens for mouse events to get its current x/y values. diff --git a/docs/data/chartsApiPages.ts b/docs/data/chartsApiPages.ts index 0cb3b0977674..724d92693ea9 100644 --- a/docs/data/chartsApiPages.ts +++ b/docs/data/chartsApiPages.ts @@ -55,6 +55,10 @@ const chartsApiPages: MuiPage[] = [ pathname: '/x/api/charts/charts-axis-highlight', title: 'ChartsAxisHighlight', }, + { + pathname: '/x/api/charts/charts-axis-tooltip-content', + title: 'ChartsAxisTooltipContent', + }, { pathname: '/x/api/charts/charts-clip-path', title: 'ChartsClipPath', @@ -63,6 +67,10 @@ const chartsApiPages: MuiPage[] = [ pathname: '/x/api/charts/charts-grid', title: 'ChartsGrid', }, + { + pathname: '/x/api/charts/charts-item-tooltip-content', + title: 'ChartsItemTooltipContent', + }, { pathname: '/x/api/charts/charts-legend', title: 'ChartsLegend', @@ -87,6 +95,10 @@ const chartsApiPages: MuiPage[] = [ pathname: '/x/api/charts/charts-tooltip', title: 'ChartsTooltip', }, + { + pathname: '/x/api/charts/charts-tooltip-container', + title: 'ChartsTooltipContainer', + }, { pathname: '/x/api/charts/charts-voronoi-handler', title: 'ChartsVoronoiHandler', @@ -103,23 +115,10 @@ const chartsApiPages: MuiPage[] = [ pathname: '/x/api/charts/continuous-color-legend', title: 'ContinuousColorLegend', }, - { - pathname: '/x/api/charts/default-charts-axis-tooltip-content', - title: 'DefaultChartsAxisTooltipContent', - }, - { - pathname: '/x/api/charts/default-charts-item-tooltip-content', - title: 'DefaultChartsItemTooltipContent', - }, { pathname: '/x/api/charts/default-charts-legend', title: 'DefaultChartsLegend', }, - { - pathname: '/x/api/charts/default-heatmap-tooltip', - title: 'DefaultHeatmapTooltip', - plan: 'pro', - }, { pathname: '/x/api/charts/gauge', title: 'Gauge', diff --git a/docs/pages/x/api/charts/bar-chart-pro.json b/docs/pages/x/api/charts/bar-chart-pro.json index 202c0e1a1544..e6999eac514e 100644 --- a/docs/pages/x/api/charts/bar-chart-pro.json +++ b/docs/pages/x/api/charts/bar-chart-pro.json @@ -92,13 +92,6 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, - "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, - "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } - }, "topAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" diff --git a/docs/pages/x/api/charts/bar-chart.json b/docs/pages/x/api/charts/bar-chart.json index 6d95694c7694..aa9385f93970 100644 --- a/docs/pages/x/api/charts/bar-chart.json +++ b/docs/pages/x/api/charts/bar-chart.json @@ -85,13 +85,6 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, - "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, - "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } - }, "topAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" @@ -117,12 +110,6 @@ "import { BarChart } from '@mui/x-charts-pro';" ], "slots": [ - { - "name": "axisContent", - "description": "Custom component for displaying tooltip content when triggered by axis event.", - "default": "DefaultChartsAxisTooltipContent", - "class": null - }, { "name": "axisLabel", "description": "Custom component for axis label.", @@ -159,12 +146,6 @@ "default": "BarLabel", "class": null }, - { - "name": "itemContent", - "description": "Custom component for displaying tooltip content when triggered by item event.", - "default": "DefaultChartsItemTooltipContent", - "class": null - }, { "name": "legend", "description": "Custom rendering of the legend.", @@ -184,7 +165,7 @@ "class": null }, { - "name": "popper", + "name": "tooltip", "description": "Custom component for the tooltip popper.", "default": "ChartsTooltipRoot", "class": null diff --git a/docs/pages/x/api/charts/default-charts-axis-tooltip-content.js b/docs/pages/x/api/charts/charts-axis-tooltip-content.js similarity index 72% rename from docs/pages/x/api/charts/default-charts-axis-tooltip-content.js rename to docs/pages/x/api/charts/charts-axis-tooltip-content.js index 662486e7e061..9dc6feb6568c 100644 --- a/docs/pages/x/api/charts/default-charts-axis-tooltip-content.js +++ b/docs/pages/x/api/charts/charts-axis-tooltip-content.js @@ -1,7 +1,7 @@ import * as React from 'react'; import ApiPage from 'docs/src/modules/components/ApiPage'; import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './default-charts-axis-tooltip-content.json'; +import jsonPageContent from './charts-axis-tooltip-content.json'; export default function Page(props) { const { descriptions, pageContent } = props; @@ -10,9 +10,9 @@ export default function Page(props) { Page.getInitialProps = () => { const req = require.context( - 'docsx/translations/api-docs/charts/default-charts-axis-tooltip-content', + 'docsx/translations/api-docs/charts/charts-axis-tooltip-content', false, - /\.\/default-charts-axis-tooltip-content.*.json$/, + /\.\/charts-axis-tooltip-content.*.json$/, ); const descriptions = mapApiPageTranslations(req); diff --git a/docs/pages/x/api/charts/charts-axis-tooltip-content.json b/docs/pages/x/api/charts/charts-axis-tooltip-content.json new file mode 100644 index 000000000000..490c5caabb74 --- /dev/null +++ b/docs/pages/x/api/charts/charts-axis-tooltip-content.json @@ -0,0 +1,70 @@ +{ + "props": { "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } } }, + "name": "ChartsAxisTooltipContent", + "imports": [ + "import { ChartsAxisTooltipContent } from '@mui/x-charts/ChartsTooltip';", + "import { ChartsAxisTooltipContent } from '@mui/x-charts';", + "import { ChartsAxisTooltipContent } from '@mui/x-charts-pro';" + ], + "classes": [ + { + "key": "cell", + "className": "MuiChartsAxisTooltipContent-cell", + "description": "Styles applied to the cell element.", + "isGlobal": false + }, + { + "key": "labelCell", + "className": "MuiChartsAxisTooltipContent-labelCell", + "description": "Styles applied to the labelCell element.", + "isGlobal": false + }, + { + "key": "mark", + "className": "MuiChartsAxisTooltipContent-mark", + "description": "Styles applied to the mark element.", + "isGlobal": false + }, + { + "key": "markCell", + "className": "MuiChartsAxisTooltipContent-markCell", + "description": "Styles applied to the markCell element.", + "isGlobal": false + }, + { + "key": "paper", + "className": "MuiChartsAxisTooltipContent-paper", + "description": "Styles applied to the paper element.", + "isGlobal": false + }, + { + "key": "root", + "className": "MuiChartsAxisTooltipContent-root", + "description": "Styles applied to the root element.", + "isGlobal": false + }, + { + "key": "row", + "className": "MuiChartsAxisTooltipContent-row", + "description": "Styles applied to the row element.", + "isGlobal": false + }, + { + "key": "table", + "className": "MuiChartsAxisTooltipContent-table", + "description": "Styles applied to the table element.", + "isGlobal": false + }, + { + "key": "valueCell", + "className": "MuiChartsAxisTooltipContent-valueCell", + "description": "Styles applied to the valueCell element.", + "isGlobal": false + } + ], + "muiName": "MuiChartsAxisTooltipContent", + "filename": "/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/charts/default-charts-item-tooltip-content.js b/docs/pages/x/api/charts/charts-item-tooltip-content.js similarity index 72% rename from docs/pages/x/api/charts/default-charts-item-tooltip-content.js rename to docs/pages/x/api/charts/charts-item-tooltip-content.js index 64821059860d..3eb3dbfb139a 100644 --- a/docs/pages/x/api/charts/default-charts-item-tooltip-content.js +++ b/docs/pages/x/api/charts/charts-item-tooltip-content.js @@ -1,7 +1,7 @@ import * as React from 'react'; import ApiPage from 'docs/src/modules/components/ApiPage'; import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './default-charts-item-tooltip-content.json'; +import jsonPageContent from './charts-item-tooltip-content.json'; export default function Page(props) { const { descriptions, pageContent } = props; @@ -10,9 +10,9 @@ export default function Page(props) { Page.getInitialProps = () => { const req = require.context( - 'docsx/translations/api-docs/charts/default-charts-item-tooltip-content', + 'docsx/translations/api-docs/charts/charts-item-tooltip-content', false, - /\.\/default-charts-item-tooltip-content.*.json$/, + /\.\/charts-item-tooltip-content.*.json$/, ); const descriptions = mapApiPageTranslations(req); diff --git a/docs/pages/x/api/charts/charts-item-tooltip-content.json b/docs/pages/x/api/charts/charts-item-tooltip-content.json new file mode 100644 index 000000000000..02c2c55fb327 --- /dev/null +++ b/docs/pages/x/api/charts/charts-item-tooltip-content.json @@ -0,0 +1,70 @@ +{ + "props": { "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } } }, + "name": "ChartsItemTooltipContent", + "imports": [ + "import { ChartsItemTooltipContent } from '@mui/x-charts/ChartsTooltip';", + "import { ChartsItemTooltipContent } from '@mui/x-charts';", + "import { ChartsItemTooltipContent } from '@mui/x-charts-pro';" + ], + "classes": [ + { + "key": "cell", + "className": "MuiChartsItemTooltipContent-cell", + "description": "Styles applied to the cell element.", + "isGlobal": false + }, + { + "key": "labelCell", + "className": "MuiChartsItemTooltipContent-labelCell", + "description": "Styles applied to the labelCell element.", + "isGlobal": false + }, + { + "key": "mark", + "className": "MuiChartsItemTooltipContent-mark", + "description": "Styles applied to the mark element.", + "isGlobal": false + }, + { + "key": "markCell", + "className": "MuiChartsItemTooltipContent-markCell", + "description": "Styles applied to the markCell element.", + "isGlobal": false + }, + { + "key": "paper", + "className": "MuiChartsItemTooltipContent-paper", + "description": "Styles applied to the paper element.", + "isGlobal": false + }, + { + "key": "root", + "className": "MuiChartsItemTooltipContent-root", + "description": "Styles applied to the root element.", + "isGlobal": false + }, + { + "key": "row", + "className": "MuiChartsItemTooltipContent-row", + "description": "Styles applied to the row element.", + "isGlobal": false + }, + { + "key": "table", + "className": "MuiChartsItemTooltipContent-table", + "description": "Styles applied to the table element.", + "isGlobal": false + }, + { + "key": "valueCell", + "className": "MuiChartsItemTooltipContent-valueCell", + "description": "Styles applied to the valueCell element.", + "isGlobal": false + } + ], + "muiName": "MuiChartsItemTooltipContent", + "filename": "/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/charts/default-heatmap-tooltip.js b/docs/pages/x/api/charts/charts-tooltip-container.js similarity index 75% rename from docs/pages/x/api/charts/default-heatmap-tooltip.js rename to docs/pages/x/api/charts/charts-tooltip-container.js index 2f8ce6db2a16..12e07a81bb75 100644 --- a/docs/pages/x/api/charts/default-heatmap-tooltip.js +++ b/docs/pages/x/api/charts/charts-tooltip-container.js @@ -1,7 +1,7 @@ import * as React from 'react'; import ApiPage from 'docs/src/modules/components/ApiPage'; import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './default-heatmap-tooltip.json'; +import jsonPageContent from './charts-tooltip-container.json'; export default function Page(props) { const { descriptions, pageContent } = props; @@ -10,9 +10,9 @@ export default function Page(props) { Page.getInitialProps = () => { const req = require.context( - 'docsx/translations/api-docs/charts/default-heatmap-tooltip', + 'docsx/translations/api-docs/charts/charts-tooltip-container', false, - /\.\/default-heatmap-tooltip.*.json$/, + /\.\/charts-tooltip-container.*.json$/, ); const descriptions = mapApiPageTranslations(req); diff --git a/docs/pages/x/api/charts/charts-tooltip-container.json b/docs/pages/x/api/charts/charts-tooltip-container.json new file mode 100644 index 000000000000..5eae783a77e0 --- /dev/null +++ b/docs/pages/x/api/charts/charts-tooltip-container.json @@ -0,0 +1,144 @@ +{ + "props": { + "anchorEl": { + "type": { + "name": "union", + "description": "(props, propName) => {\n if (props[propName] == null) {\n return new Error(`Prop '${propName}' is required but wasn't specified`);\n }\n if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) {\n return new Error(`Expected prop '${propName}' to be of type Element`);\n }\n return null;\n}
| func
| { contextElement?: (props, propName) => {\n if (props[propName] == null) {\n return null;\n }\n if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) {\n return new Error(`Expected prop '${propName}' to be of type Element`);\n }\n return null;\n}, getBoundingClientRect: func }" + } + }, + "children": { "type": { "name": "node" } }, + "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, + "component": { "type": { "name": "elementType" } }, + "components": { + "type": { "name": "shape", "description": "{ Root?: elementType }" }, + "default": "{}" + }, + "componentsProps": { + "type": { "name": "shape", "description": "{ root?: func
| object }" }, + "default": "{}" + }, + "container": { + "type": { + "name": "union", + "description": "(props, propName) => {\n if (props[propName] == null) {\n return new Error(`Prop '${propName}' is required but wasn't specified`);\n }\n if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) {\n return new Error(`Expected prop '${propName}' to be of type Element`);\n }\n return null;\n}
| func" + } + }, + "disablePortal": { "type": { "name": "bool" }, "default": "false" }, + "keepMounted": { "type": { "name": "bool" }, "default": "false" }, + "modifiers": { + "type": { + "name": "arrayOf", + "description": "Array<{ data?: object, effect?: func, enabled?: bool, fn?: func, name?: any, options?: object, phase?: 'afterMain'
| 'afterRead'
| 'afterWrite'
| 'beforeMain'
| 'beforeRead'
| 'beforeWrite'
| 'main'
| 'read'
| 'write', requires?: Array<string>, requiresIfExists?: Array<string> }>" + } + }, + "open": { "type": { "name": "bool" } }, + "placement": { + "type": { + "name": "enum", + "description": "'auto-end'
| 'auto-start'
| 'auto'
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'left-end'
| 'left-start'
| 'left'
| 'right-end'
| 'right-start'
| 'right'
| 'top-end'
| 'top-start'
| 'top'" + }, + "default": "'bottom'" + }, + "popperOptions": { + "type": { + "name": "shape", + "description": "{ modifiers?: array, onFirstUpdate?: func, placement?: 'auto-end'
| 'auto-start'
| 'auto'
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'left-end'
| 'left-start'
| 'left'
| 'right-end'
| 'right-start'
| 'right'
| 'top-end'
| 'top-start'
| 'top', strategy?: 'absolute'
| 'fixed' }" + }, + "default": "{}" + }, + "popperRef": { + "type": { + "name": "union", + "description": "func
| { current?: { destroy: func, forceUpdate: func, setOptions: func, state: { attributes: object, elements: object, modifiersData: object, options: object, orderedModifiers: Array<object>, placement: 'auto-end'
| 'auto-start'
| 'auto'
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'left-end'
| 'left-start'
| 'left'
| 'right-end'
| 'right-start'
| 'right'
| 'top-end'
| 'top-start'
| 'top', rects: object, reset: bool, scrollParents: object, strategy: 'absolute'
| 'fixed', styles: object }, update: func } }" + } + }, + "slotProps": { "type": { "name": "object" }, "default": "{}" }, + "slots": { + "type": { "name": "object" }, + "default": "{}", + "additionalInfo": { "slotsApi": true } + }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "transition": { "type": { "name": "bool" }, "default": "false" }, + "trigger": { + "type": { + "name": "enum", + "description": "'axis'
| 'item'
| 'none'" + }, + "default": "'axis'" + } + }, + "name": "ChartsTooltipContainer", + "imports": [ + "import { ChartsTooltipContainer } from '@mui/x-charts/ChartsTooltip';", + "import { ChartsTooltipContainer } from '@mui/x-charts';", + "import { ChartsTooltipContainer } from '@mui/x-charts-pro';" + ], + "classes": [ + { + "key": "cell", + "className": "MuiChartsTooltipContainer-cell", + "description": "Styles applied to the cell element.", + "isGlobal": false + }, + { + "key": "labelCell", + "className": "MuiChartsTooltipContainer-labelCell", + "description": "Styles applied to the labelCell element.", + "isGlobal": false + }, + { + "key": "mark", + "className": "MuiChartsTooltipContainer-mark", + "description": "Styles applied to the mark element.", + "isGlobal": false + }, + { + "key": "markCell", + "className": "MuiChartsTooltipContainer-markCell", + "description": "Styles applied to the markCell element.", + "isGlobal": false + }, + { + "key": "paper", + "className": "MuiChartsTooltipContainer-paper", + "description": "Styles applied to the paper element.", + "isGlobal": false + }, + { + "key": "root", + "className": "MuiChartsTooltipContainer-root", + "description": "Styles applied to the root element.", + "isGlobal": false + }, + { + "key": "row", + "className": "MuiChartsTooltipContainer-row", + "description": "Styles applied to the row element.", + "isGlobal": false + }, + { + "key": "table", + "className": "MuiChartsTooltipContainer-table", + "description": "Styles applied to the table element.", + "isGlobal": false + }, + { + "key": "valueCell", + "className": "MuiChartsTooltipContainer-valueCell", + "description": "Styles applied to the valueCell element.", + "isGlobal": false + } + ], + "muiName": "MuiChartsTooltipContainer", + "filename": "/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx", + "inheritance": null, + "demos": "", + "cssComponent": false +} diff --git a/docs/pages/x/api/charts/charts-tooltip.json b/docs/pages/x/api/charts/charts-tooltip.json index cc191b7a0bf8..551707108abd 100644 --- a/docs/pages/x/api/charts/charts-tooltip.json +++ b/docs/pages/x/api/charts/charts-tooltip.json @@ -1,15 +1,55 @@ { "props": { - "axisContent": { - "type": { "name": "elementType" }, - "deprecated": true, - "deprecationInfo": "Use slots.axisContent instead" + "anchorEl": { + "type": { + "name": "union", + "description": "(props, propName) => {\n if (props[propName] == null) {\n return new Error(`Prop '${propName}' is required but wasn't specified`);\n }\n if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) {\n return new Error(`Expected prop '${propName}' to be of type Element`);\n }\n return null;\n}
| func
| { contextElement?: (props, propName) => {\n if (props[propName] == null) {\n return null;\n }\n if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) {\n return new Error(`Expected prop '${propName}' to be of type Element`);\n }\n return null;\n}, getBoundingClientRect: func }" + } }, "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "itemContent": { - "type": { "name": "elementType" }, - "deprecated": true, - "deprecationInfo": "Use slots.itemContent instead" + "component": { "type": { "name": "elementType" } }, + "components": { + "type": { "name": "shape", "description": "{ Root?: elementType }" }, + "default": "{}" + }, + "componentsProps": { + "type": { "name": "shape", "description": "{ root?: func
| object }" }, + "default": "{}" + }, + "container": { + "type": { + "name": "union", + "description": "(props, propName) => {\n if (props[propName] == null) {\n return new Error(`Prop '${propName}' is required but wasn't specified`);\n }\n if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) {\n return new Error(`Expected prop '${propName}' to be of type Element`);\n }\n return null;\n}
| func" + } + }, + "disablePortal": { "type": { "name": "bool" }, "default": "false" }, + "keepMounted": { "type": { "name": "bool" }, "default": "false" }, + "modifiers": { + "type": { + "name": "arrayOf", + "description": "Array<{ data?: object, effect?: func, enabled?: bool, fn?: func, name?: any, options?: object, phase?: 'afterMain'
| 'afterRead'
| 'afterWrite'
| 'beforeMain'
| 'beforeRead'
| 'beforeWrite'
| 'main'
| 'read'
| 'write', requires?: Array<string>, requiresIfExists?: Array<string> }>" + } + }, + "open": { "type": { "name": "bool" } }, + "placement": { + "type": { + "name": "enum", + "description": "'auto-end'
| 'auto-start'
| 'auto'
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'left-end'
| 'left-start'
| 'left'
| 'right-end'
| 'right-start'
| 'right'
| 'top-end'
| 'top-start'
| 'top'" + }, + "default": "'bottom'" + }, + "popperOptions": { + "type": { + "name": "shape", + "description": "{ modifiers?: array, onFirstUpdate?: func, placement?: 'auto-end'
| 'auto-start'
| 'auto'
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'left-end'
| 'left-start'
| 'left'
| 'right-end'
| 'right-start'
| 'right'
| 'top-end'
| 'top-start'
| 'top', strategy?: 'absolute'
| 'fixed' }" + }, + "default": "{}" + }, + "popperRef": { + "type": { + "name": "union", + "description": "func
| { current?: { destroy: func, forceUpdate: func, setOptions: func, state: { attributes: object, elements: object, modifiersData: object, options: object, orderedModifiers: Array<object>, placement: 'auto-end'
| 'auto-start'
| 'auto'
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'left-end'
| 'left-start'
| 'left'
| 'right-end'
| 'right-start'
| 'right'
| 'top-end'
| 'top-start'
| 'top', rects: object, reset: bool, scrollParents: object, strategy: 'absolute'
| 'fixed', styles: object }, update: func } }" + } }, "slotProps": { "type": { "name": "object" }, "default": "{}" }, "slots": { @@ -17,6 +57,14 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, + "sx": { + "type": { + "name": "union", + "description": "Array<func
| object
| bool>
| func
| object" + }, + "additionalInfo": { "sx": true } + }, + "transition": { "type": { "name": "bool" }, "default": "false" }, "trigger": { "type": { "name": "enum", @@ -31,26 +79,6 @@ "import { ChartsTooltip } from '@mui/x-charts';", "import { ChartsTooltip } from '@mui/x-charts-pro';" ], - "slots": [ - { - "name": "axisContent", - "description": "Custom component for displaying tooltip content when triggered by axis event.", - "default": "DefaultChartsAxisTooltipContent", - "class": null - }, - { - "name": "itemContent", - "description": "Custom component for displaying tooltip content when triggered by item event.", - "default": "DefaultChartsItemTooltipContent", - "class": null - }, - { - "name": "popper", - "description": "Custom component for the tooltip popper.", - "default": "ChartsTooltipRoot", - "class": null - } - ], "classes": [ { "key": "cell", diff --git a/docs/pages/x/api/charts/default-charts-axis-tooltip-content.json b/docs/pages/x/api/charts/default-charts-axis-tooltip-content.json deleted file mode 100644 index 2594869a42ab..000000000000 --- a/docs/pages/x/api/charts/default-charts-axis-tooltip-content.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "props": { - "axis": { "type": { "name": "object" }, "required": true }, - "axisData": { - "type": { - "name": "shape", - "description": "{ x?: { index?: number, value: Date
| number
| string }, y?: { index?: number, value: Date
| number
| string } }" - }, - "required": true - }, - "classes": { - "type": { "name": "object" }, - "required": true, - "additionalInfo": { "cssApi": true } - }, - "series": { - "type": { "name": "arrayOf", "description": "Array<object>" }, - "required": true - }, - "axisValue": { - "type": { "name": "union", "description": "Date
| number
| string" } - }, - "dataIndex": { "type": { "name": "number" } } - }, - "name": "DefaultChartsAxisTooltipContent", - "imports": [ - "import { DefaultChartsAxisTooltipContent } from '@mui/x-charts/ChartsTooltip';", - "import { DefaultChartsAxisTooltipContent } from '@mui/x-charts';", - "import { DefaultChartsAxisTooltipContent } from '@mui/x-charts-pro';" - ], - "classes": [ - { - "key": "cell", - "className": "MuiDefaultChartsAxisTooltipContent-cell", - "description": "Styles applied to the cell element.", - "isGlobal": false - }, - { - "key": "labelCell", - "className": "MuiDefaultChartsAxisTooltipContent-labelCell", - "description": "Styles applied to the labelCell element.", - "isGlobal": false - }, - { - "key": "mark", - "className": "MuiDefaultChartsAxisTooltipContent-mark", - "description": "Styles applied to the mark element.", - "isGlobal": false - }, - { - "key": "markCell", - "className": "MuiDefaultChartsAxisTooltipContent-markCell", - "description": "Styles applied to the markCell element.", - "isGlobal": false - }, - { - "key": "paper", - "className": "MuiDefaultChartsAxisTooltipContent-paper", - "description": "Styles applied to the paper element.", - "isGlobal": false - }, - { - "key": "root", - "className": "MuiDefaultChartsAxisTooltipContent-root", - "description": "Styles applied to the root element.", - "isGlobal": false - }, - { - "key": "row", - "className": "MuiDefaultChartsAxisTooltipContent-row", - "description": "Styles applied to the row element.", - "isGlobal": false - }, - { - "key": "table", - "className": "MuiDefaultChartsAxisTooltipContent-table", - "description": "Styles applied to the table element.", - "isGlobal": false - }, - { - "key": "valueCell", - "className": "MuiDefaultChartsAxisTooltipContent-valueCell", - "description": "Styles applied to the valueCell element.", - "isGlobal": false - } - ], - "muiName": "MuiDefaultChartsAxisTooltipContent", - "filename": "/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx", - "inheritance": null, - "demos": "", - "cssComponent": false -} diff --git a/docs/pages/x/api/charts/default-charts-item-tooltip-content.json b/docs/pages/x/api/charts/default-charts-item-tooltip-content.json deleted file mode 100644 index 7d76f641a34f..000000000000 --- a/docs/pages/x/api/charts/default-charts-item-tooltip-content.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "props": { - "classes": { - "type": { "name": "object" }, - "required": true, - "additionalInfo": { "cssApi": true } - }, - "getColor": { - "type": { "name": "func" }, - "required": true, - "signature": { - "type": "function(dataIndex: number) => string", - "describedArgs": ["dataIndex"], - "returned": "string" - } - }, - "itemData": { - "type": { - "name": "shape", - "description": "{ dataIndex?: number, seriesId: number
| string, type: 'bar'
| 'line'
| 'pie'
| 'scatter' }" - }, - "required": true - }, - "series": { "type": { "name": "object" }, "required": true } - }, - "name": "DefaultChartsItemTooltipContent", - "imports": [ - "import { DefaultChartsItemTooltipContent } from '@mui/x-charts/ChartsTooltip';", - "import { DefaultChartsItemTooltipContent } from '@mui/x-charts';", - "import { DefaultChartsItemTooltipContent } from '@mui/x-charts-pro';" - ], - "classes": [ - { - "key": "cell", - "className": "MuiDefaultChartsItemTooltipContent-cell", - "description": "Styles applied to the cell element.", - "isGlobal": false - }, - { - "key": "labelCell", - "className": "MuiDefaultChartsItemTooltipContent-labelCell", - "description": "Styles applied to the labelCell element.", - "isGlobal": false - }, - { - "key": "mark", - "className": "MuiDefaultChartsItemTooltipContent-mark", - "description": "Styles applied to the mark element.", - "isGlobal": false - }, - { - "key": "markCell", - "className": "MuiDefaultChartsItemTooltipContent-markCell", - "description": "Styles applied to the markCell element.", - "isGlobal": false - }, - { - "key": "paper", - "className": "MuiDefaultChartsItemTooltipContent-paper", - "description": "Styles applied to the paper element.", - "isGlobal": false - }, - { - "key": "root", - "className": "MuiDefaultChartsItemTooltipContent-root", - "description": "Styles applied to the root element.", - "isGlobal": false - }, - { - "key": "row", - "className": "MuiDefaultChartsItemTooltipContent-row", - "description": "Styles applied to the row element.", - "isGlobal": false - }, - { - "key": "table", - "className": "MuiDefaultChartsItemTooltipContent-table", - "description": "Styles applied to the table element.", - "isGlobal": false - }, - { - "key": "valueCell", - "className": "MuiDefaultChartsItemTooltipContent-valueCell", - "description": "Styles applied to the valueCell element.", - "isGlobal": false - } - ], - "muiName": "MuiDefaultChartsItemTooltipContent", - "filename": "/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx", - "inheritance": null, - "demos": "", - "cssComponent": false -} diff --git a/docs/pages/x/api/charts/default-heatmap-tooltip.json b/docs/pages/x/api/charts/default-heatmap-tooltip.json deleted file mode 100644 index 66e8ffa29495..000000000000 --- a/docs/pages/x/api/charts/default-heatmap-tooltip.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "props": { - "classes": { - "type": { "name": "object" }, - "required": true, - "additionalInfo": { "cssApi": true } - }, - "getColor": { - "type": { "name": "func" }, - "required": true, - "signature": { - "type": "function(dataIndex: number) => string", - "describedArgs": ["dataIndex"], - "returned": "string" - } - }, - "itemData": { - "type": { - "name": "shape", - "description": "{ dataIndex: number, seriesId: number
| string, type: 'heatmap' }" - }, - "required": true - }, - "series": { "type": { "name": "object" }, "required": true } - }, - "name": "DefaultHeatmapTooltip", - "imports": [ - "import { DefaultHeatmapTooltip } from '@mui/x-charts-pro/Heatmap';", - "import { DefaultHeatmapTooltip } from '@mui/x-charts-pro';" - ], - "classes": [ - { - "key": "cell", - "className": "MuiDefaultHeatmapTooltip-cell", - "description": "Styles applied to the cell element.", - "isGlobal": false - }, - { - "key": "labelCell", - "className": "MuiDefaultHeatmapTooltip-labelCell", - "description": "Styles applied to the labelCell element.", - "isGlobal": false - }, - { - "key": "mark", - "className": "MuiDefaultHeatmapTooltip-mark", - "description": "Styles applied to the mark element.", - "isGlobal": false - }, - { - "key": "markCell", - "className": "MuiDefaultHeatmapTooltip-markCell", - "description": "Styles applied to the markCell element.", - "isGlobal": false - }, - { - "key": "paper", - "className": "MuiDefaultHeatmapTooltip-paper", - "description": "Styles applied to the paper element.", - "isGlobal": false - }, - { - "key": "root", - "className": "MuiDefaultHeatmapTooltip-root", - "description": "Styles applied to the root element.", - "isGlobal": false - }, - { - "key": "row", - "className": "MuiDefaultHeatmapTooltip-row", - "description": "Styles applied to the row element.", - "isGlobal": false - }, - { - "key": "table", - "className": "MuiDefaultHeatmapTooltip-table", - "description": "Styles applied to the table element.", - "isGlobal": false - }, - { - "key": "valueCell", - "className": "MuiDefaultHeatmapTooltip-valueCell", - "description": "Styles applied to the valueCell element.", - "isGlobal": false - } - ], - "muiName": "MuiDefaultHeatmapTooltip", - "filename": "/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx", - "inheritance": null, - "demos": "", - "cssComponent": false -} diff --git a/docs/pages/x/api/charts/heatmap.json b/docs/pages/x/api/charts/heatmap.json index 333f0c5ea659..0e42547e3966 100644 --- a/docs/pages/x/api/charts/heatmap.json +++ b/docs/pages/x/api/charts/heatmap.json @@ -72,10 +72,7 @@ "additionalInfo": { "slotsApi": true } }, "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, + "type": { "name": "object" }, "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } }, "topAxis": { diff --git a/docs/pages/x/api/charts/line-chart-pro.json b/docs/pages/x/api/charts/line-chart-pro.json index f2f0491e3ea5..da018ce78424 100644 --- a/docs/pages/x/api/charts/line-chart-pro.json +++ b/docs/pages/x/api/charts/line-chart-pro.json @@ -85,14 +85,6 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, - "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, - "default": "{ trigger: 'item' }", - "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } - }, "topAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" diff --git a/docs/pages/x/api/charts/line-chart.json b/docs/pages/x/api/charts/line-chart.json index f7862a09a001..6ecb8a0d4633 100644 --- a/docs/pages/x/api/charts/line-chart.json +++ b/docs/pages/x/api/charts/line-chart.json @@ -78,14 +78,6 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, - "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, - "default": "{ trigger: 'item' }", - "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } - }, "topAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" @@ -117,12 +109,6 @@ "default": "AnimatedArea", "class": null }, - { - "name": "axisContent", - "description": "Custom component for displaying tooltip content when triggered by axis event.", - "default": "DefaultChartsAxisTooltipContent", - "class": null - }, { "name": "axisLabel", "description": "Custom component for axis label.", @@ -147,12 +133,6 @@ "default": "ChartsText", "class": null }, - { - "name": "itemContent", - "description": "Custom component for displaying tooltip content when triggered by item event.", - "default": "DefaultChartsItemTooltipContent", - "class": null - }, { "name": "legend", "description": "Custom rendering of the legend.", @@ -180,7 +160,7 @@ "class": null }, { - "name": "popper", + "name": "tooltip", "description": "Custom component for the tooltip popper.", "default": "ChartsTooltipRoot", "class": null diff --git a/docs/pages/x/api/charts/pie-chart.json b/docs/pages/x/api/charts/pie-chart.json index 41b20f6e27f9..d4b6bfe884d3 100644 --- a/docs/pages/x/api/charts/pie-chart.json +++ b/docs/pages/x/api/charts/pie-chart.json @@ -41,14 +41,6 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, - "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, - "default": "{ trigger: 'item' }", - "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } - }, "width": { "type": { "name": "number" } }, "xAxis": { "type": { @@ -70,18 +62,6 @@ "import { PieChart } from '@mui/x-charts-pro';" ], "slots": [ - { - "name": "axisContent", - "description": "Custom component for displaying tooltip content when triggered by axis event.", - "default": "DefaultChartsAxisTooltipContent", - "class": null - }, - { - "name": "itemContent", - "description": "Custom component for displaying tooltip content when triggered by item event.", - "default": "DefaultChartsItemTooltipContent", - "class": null - }, { "name": "legend", "description": "Custom rendering of the legend.", @@ -103,7 +83,7 @@ { "name": "pieArc", "description": "", "class": null }, { "name": "pieArcLabel", "description": "", "class": null }, { - "name": "popper", + "name": "tooltip", "description": "Custom component for the tooltip popper.", "default": "ChartsTooltipRoot", "class": null diff --git a/docs/pages/x/api/charts/scatter-chart-pro.json b/docs/pages/x/api/charts/scatter-chart-pro.json index e9aa9a25aa8e..bca0f97741f7 100644 --- a/docs/pages/x/api/charts/scatter-chart-pro.json +++ b/docs/pages/x/api/charts/scatter-chart-pro.json @@ -81,14 +81,6 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, - "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, - "default": "{ trigger: 'item' }", - "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } - }, "topAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" diff --git a/docs/pages/x/api/charts/scatter-chart.json b/docs/pages/x/api/charts/scatter-chart.json index d647c8234b40..f573b3e0ab7f 100644 --- a/docs/pages/x/api/charts/scatter-chart.json +++ b/docs/pages/x/api/charts/scatter-chart.json @@ -74,14 +74,6 @@ "default": "{}", "additionalInfo": { "slotsApi": true } }, - "tooltip": { - "type": { - "name": "shape", - "description": "{ axisContent?: elementType, classes?: object, itemContent?: elementType, slotProps?: object, slots?: object, trigger?: 'axis'
| 'item'
| 'none' }" - }, - "default": "{ trigger: 'item' }", - "seeMoreLink": { "url": "https://mui.com/x/react-charts/tooltip/", "text": "tooltip docs" } - }, "topAxis": { "type": { "name": "union", "description": "object
| string" }, "default": "null" @@ -114,12 +106,6 @@ "import { ScatterChart } from '@mui/x-charts-pro';" ], "slots": [ - { - "name": "axisContent", - "description": "Custom component for displaying tooltip content when triggered by axis event.", - "default": "DefaultChartsAxisTooltipContent", - "class": null - }, { "name": "axisLabel", "description": "Custom component for axis label.", @@ -144,12 +130,6 @@ "default": "ChartsText", "class": null }, - { - "name": "itemContent", - "description": "Custom component for displaying tooltip content when triggered by item event.", - "default": "DefaultChartsItemTooltipContent", - "class": null - }, { "name": "legend", "description": "Custom rendering of the legend.", @@ -168,13 +148,13 @@ "default": "ChartsNoDataOverlay", "class": null }, + { "name": "scatter", "description": "", "class": null }, { - "name": "popper", + "name": "tooltip", "description": "Custom component for the tooltip popper.", "default": "ChartsTooltipRoot", "class": null - }, - { "name": "scatter", "description": "", "class": null } + } ], "classes": [], "spread": true, diff --git a/docs/pages/x/api/charts/spark-line-chart.json b/docs/pages/x/api/charts/spark-line-chart.json index 4b8753568039..683d2ce39d35 100644 --- a/docs/pages/x/api/charts/spark-line-chart.json +++ b/docs/pages/x/api/charts/spark-line-chart.json @@ -81,24 +81,12 @@ "default": "AnimatedArea", "class": null }, - { - "name": "axisContent", - "description": "Custom component for displaying tooltip content when triggered by axis event.", - "default": "DefaultChartsAxisTooltipContent", - "class": null - }, { "name": "bar", "description": "The component that renders the bar.", "default": "BarElementPath", "class": null }, - { - "name": "itemContent", - "description": "Custom component for displaying tooltip content when triggered by item event.", - "default": "DefaultChartsItemTooltipContent", - "class": null - }, { "name": "line", "description": "The component that renders the line.", @@ -108,7 +96,7 @@ { "name": "lineHighlight", "description": "", "class": null }, { "name": "mark", "description": "", "class": null }, { - "name": "popper", + "name": "tooltip", "description": "Custom component for the tooltip popper.", "default": "ChartsTooltipRoot", "class": null diff --git a/docs/scripts/generateProptypes.ts b/docs/scripts/generateProptypes.ts index cad6d50efeee..832fb60f8047 100644 --- a/docs/scripts/generateProptypes.ts +++ b/docs/scripts/generateProptypes.ts @@ -10,11 +10,7 @@ import { import { fixBabelGeneratorIssues, fixLineEndings } from '@mui/internal-docs-utils'; import { createXTypeScriptProjects, XTypeScriptProject } from './createXTypeScriptProjects'; -const COMPONENTS_WITHOUT_PROPTYPES = [ - 'ChartsAxisTooltipContent', - 'ChartsItemTooltipContent', - 'AnimatedBarElement', -]; +const COMPONENTS_WITHOUT_PROPTYPES = ['AnimatedBarElement']; async function generateProptypes(project: XTypeScriptProject, sourceFile: string) { const isDateObject = (name: string) => { diff --git a/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json b/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json index 7b30aa9f4c6d..6c9d9aca524b 100644 --- a/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json +++ b/docs/translations/api-docs/charts/bar-chart-pro/bar-chart-pro.json @@ -68,10 +68,6 @@ }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, - "tooltip": { - "description": "The configuration of the tooltip.", - "seeMoreText": "See {{link}} for more details." - }, "topAxis": { "description": "Indicate which axis to display the top of the charts. Can be a string (the id of the axis) or an object ChartsXAxisProps." }, diff --git a/docs/translations/api-docs/charts/bar-chart/bar-chart.json b/docs/translations/api-docs/charts/bar-chart/bar-chart.json index 684ba329429b..f1214f5f990b 100644 --- a/docs/translations/api-docs/charts/bar-chart/bar-chart.json +++ b/docs/translations/api-docs/charts/bar-chart/bar-chart.json @@ -64,10 +64,6 @@ }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, - "tooltip": { - "description": "The configuration of the tooltip.", - "seeMoreText": "See {{link}} for more details." - }, "topAxis": { "description": "Indicate which axis to display the top of the charts. Can be a string (the id of the axis) or an object ChartsXAxisProps." }, @@ -83,17 +79,15 @@ }, "classDescriptions": {}, "slotDescriptions": { - "axisContent": "Custom component for displaying tooltip content when triggered by axis event.", "axisLabel": "Custom component for axis label.", "axisLine": "Custom component for the axis main line.", "axisTick": "Custom component for the axis tick.", "axisTickLabel": "Custom component for tick label.", "bar": "The component that renders the bar.", "barLabel": "The component that renders the bar label.", - "itemContent": "Custom component for displaying tooltip content when triggered by item event.", "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.", - "popper": "Custom component for the tooltip popper." + "tooltip": "Custom component for the tooltip popper." } } diff --git a/docs/translations/api-docs/charts/default-charts-axis-tooltip-content/default-charts-axis-tooltip-content.json b/docs/translations/api-docs/charts/charts-axis-tooltip-content/charts-axis-tooltip-content.json similarity index 72% rename from docs/translations/api-docs/charts/default-charts-axis-tooltip-content/default-charts-axis-tooltip-content.json rename to docs/translations/api-docs/charts/charts-axis-tooltip-content/charts-axis-tooltip-content.json index 3e7c7c6cc6e9..53a4cfd97b0f 100644 --- a/docs/translations/api-docs/charts/default-charts-axis-tooltip-content/default-charts-axis-tooltip-content.json +++ b/docs/translations/api-docs/charts/charts-axis-tooltip-content/charts-axis-tooltip-content.json @@ -1,12 +1,7 @@ { "componentDescription": "", "propDescriptions": { - "axis": { "description": "The properties of the triggered axis." }, - "axisData": { "description": "Data identifying the triggered axis." }, - "axisValue": { "description": "The value associated to the current mouse position." }, - "classes": { "description": "Override or extend the styles applied to the component." }, - "dataIndex": { "description": "The index of the data item triggered." }, - "series": { "description": "The series linked to the triggered axis." } + "classes": { "description": "Override or extend the styles applied to the component." } }, "classDescriptions": { "cell": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the cell element" }, diff --git a/docs/translations/api-docs/charts/default-charts-item-tooltip-content/default-charts-item-tooltip-content.json b/docs/translations/api-docs/charts/charts-item-tooltip-content/charts-item-tooltip-content.json similarity index 71% rename from docs/translations/api-docs/charts/default-charts-item-tooltip-content/default-charts-item-tooltip-content.json rename to docs/translations/api-docs/charts/charts-item-tooltip-content/charts-item-tooltip-content.json index c7ea4d31307f..53a4cfd97b0f 100644 --- a/docs/translations/api-docs/charts/default-charts-item-tooltip-content/default-charts-item-tooltip-content.json +++ b/docs/translations/api-docs/charts/charts-item-tooltip-content/charts-item-tooltip-content.json @@ -1,16 +1,7 @@ { "componentDescription": "", "propDescriptions": { - "classes": { "description": "Override or extend the styles applied to the component." }, - "getColor": { - "description": "Get the color of the item with index dataIndex.", - "typeDescriptions": { - "dataIndex": "The data index of the item.", - "string": "The color to display." - } - }, - "itemData": { "description": "The data used to identify the triggered item." }, - "series": { "description": "The series linked to the triggered axis." } + "classes": { "description": "Override or extend the styles applied to the component." } }, "classDescriptions": { "cell": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the cell element" }, diff --git a/docs/translations/api-docs/charts/charts-tooltip-container/charts-tooltip-container.json b/docs/translations/api-docs/charts/charts-tooltip-container/charts-tooltip-container.json new file mode 100644 index 000000000000..b64c46287a30 --- /dev/null +++ b/docs/translations/api-docs/charts/charts-tooltip-container/charts-tooltip-container.json @@ -0,0 +1,68 @@ +{ + "componentDescription": "", + "propDescriptions": { + "anchorEl": { + "description": "An HTML element, virtualElement, or a function that returns either. It's used to set the position of the popper. The return value will passed as the reference object of the Popper instance." + }, + "children": { "description": "Popper render function or node." }, + "classes": { "description": "Override or extend the styles applied to the component." }, + "component": { + "description": "The component used for the root node. Either a string to use a HTML element or a component." + }, + "components": { + "description": "The components used for each slot inside the Popper. Either a string to use a HTML element or a component." + }, + "componentsProps": { "description": "The props used for each slot inside the Popper." }, + "container": { + "description": "An HTML element or function that returns one. The container will have the portal children appended to it.
You can also provide a callback, which is called in a React layout effect. This lets you set the container from a ref, and also makes server-side rendering possible.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time." + }, + "disablePortal": { + "description": "The children will be under the DOM hierarchy of the parent component." + }, + "keepMounted": { + "description": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Popper." + }, + "modifiers": { + "description": "Popper.js is based on a "plugin-like" architecture, most of its features are fully encapsulated "modifiers".
A modifier is a function that is called each time Popper.js needs to compute the position of the popper. For this reason, modifiers should be very performant to avoid bottlenecks. To learn how to create a modifier, read the modifiers documentation." + }, + "open": { "description": "If true, the component is shown." }, + "placement": { "description": "Popper placement." }, + "popperOptions": { + "description": "Options provided to the Popper.js instance." + }, + "popperRef": { "description": "A ref that points to the used popper instance." }, + "slotProps": { "description": "The props used for each slot inside the Popper." }, + "slots": { + "description": "The components used for each slot inside the Popper. Either a string to use a HTML element or a component." + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles." + }, + "transition": { + "description": "Help supporting a react-transition-group/Transition component." + }, + "trigger": { + "description": "Select the kind of tooltip to display - 'item': Shows data about the item below the mouse. - 'axis': Shows values associated with the hovered x value - 'none': Does not display tooltip" + } + }, + "classDescriptions": { + "cell": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the cell element" }, + "labelCell": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the labelCell element" + }, + "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the mark element" }, + "markCell": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the markCell element" + }, + "paper": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the paper element" }, + "root": { "description": "Styles applied to the root element." }, + "row": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the row element" }, + "table": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the table element" }, + "valueCell": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the valueCell element" + } + } +} diff --git a/docs/translations/api-docs/charts/charts-tooltip/charts-tooltip.json b/docs/translations/api-docs/charts/charts-tooltip/charts-tooltip.json index a268da37e6cf..13d995719059 100644 --- a/docs/translations/api-docs/charts/charts-tooltip/charts-tooltip.json +++ b/docs/translations/api-docs/charts/charts-tooltip/charts-tooltip.json @@ -1,15 +1,45 @@ { "componentDescription": "", "propDescriptions": { - "axisContent": { - "description": "Component to override the tooltip content when trigger is set to 'axis'." + "anchorEl": { + "description": "An HTML element, virtualElement, or a function that returns either. It's used to set the position of the popper. The return value will passed as the reference object of the Popper instance." }, "classes": { "description": "Override or extend the styles applied to the component." }, - "itemContent": { - "description": "Component to override the tooltip content when trigger is set to 'item'." + "component": { + "description": "The component used for the root node. Either a string to use a HTML element or a component." + }, + "components": { + "description": "The components used for each slot inside the Popper. Either a string to use a HTML element or a component." + }, + "componentsProps": { "description": "The props used for each slot inside the Popper." }, + "container": { + "description": "An HTML element or function that returns one. The container will have the portal children appended to it.
You can also provide a callback, which is called in a React layout effect. This lets you set the container from a ref, and also makes server-side rendering possible.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time." + }, + "disablePortal": { + "description": "The children will be under the DOM hierarchy of the parent component." + }, + "keepMounted": { + "description": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Popper." + }, + "modifiers": { + "description": "Popper.js is based on a "plugin-like" architecture, most of its features are fully encapsulated "modifiers".
A modifier is a function that is called each time Popper.js needs to compute the position of the popper. For this reason, modifiers should be very performant to avoid bottlenecks. To learn how to create a modifier, read the modifiers documentation." + }, + "open": { "description": "If true, the component is shown." }, + "placement": { "description": "Popper placement." }, + "popperOptions": { + "description": "Options provided to the Popper.js instance." + }, + "popperRef": { "description": "A ref that points to the used popper instance." }, + "slotProps": { "description": "The props used for each slot inside the Popper." }, + "slots": { + "description": "The components used for each slot inside the Popper. Either a string to use a HTML element or a component." + }, + "sx": { + "description": "The system prop that allows defining system overrides as well as additional CSS styles." + }, + "transition": { + "description": "Help supporting a react-transition-group/Transition component." }, - "slotProps": { "description": "The props used for each component slot." }, - "slots": { "description": "Overridable component slots." }, "trigger": { "description": "Select the kind of tooltip to display - 'item': Shows data about the item below the mouse. - 'axis': Shows values associated with the hovered x value - 'none': Does not display tooltip" } @@ -33,10 +63,5 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the valueCell element" } - }, - "slotDescriptions": { - "axisContent": "Custom component for displaying tooltip content when triggered by axis event.", - "itemContent": "Custom component for displaying tooltip content when triggered by item event.", - "popper": "Custom component for the tooltip popper." } } diff --git a/docs/translations/api-docs/charts/default-heatmap-tooltip/default-heatmap-tooltip.json b/docs/translations/api-docs/charts/default-heatmap-tooltip/default-heatmap-tooltip.json deleted file mode 100644 index 0c7b9190337e..000000000000 --- a/docs/translations/api-docs/charts/default-heatmap-tooltip/default-heatmap-tooltip.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "componentDescription": "", - "propDescriptions": { - "classes": { "description": "Override or extend the styles applied to the component." }, - "getColor": { - "description": "Get the color of the item with index dataIndex.", - "typeDescriptions": { - "dataIndex": "The data index of the item.", - "string": "The color to display." - } - }, - "itemData": { "description": "The data used to identify the triggered item." }, - "series": { "description": "The series linked to the triggered item." } - }, - "classDescriptions": { - "cell": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the cell element" }, - "labelCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the labelCell element" - }, - "mark": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the mark element" }, - "markCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the markCell element" - }, - "paper": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the paper element" }, - "root": { "description": "Styles applied to the root element." }, - "row": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the row element" }, - "table": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the table element" }, - "valueCell": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the valueCell element" - } - } -} diff --git a/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json b/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json index e331e549cdbc..827d16ab4cd1 100644 --- a/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json +++ b/docs/translations/api-docs/charts/line-chart-pro/line-chart-pro.json @@ -63,10 +63,6 @@ "skipAnimation": { "description": "If true, animations are skipped." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, - "tooltip": { - "description": "The configuration of the tooltip.", - "seeMoreText": "See {{link}} for more details." - }, "topAxis": { "description": "Indicate which axis to display the top of the charts. Can be a string (the id of the axis) or an object ChartsXAxisProps." }, diff --git a/docs/translations/api-docs/charts/line-chart/line-chart.json b/docs/translations/api-docs/charts/line-chart/line-chart.json index 8b166a32278f..efd9317f9eb4 100644 --- a/docs/translations/api-docs/charts/line-chart/line-chart.json +++ b/docs/translations/api-docs/charts/line-chart/line-chart.json @@ -59,10 +59,6 @@ "skipAnimation": { "description": "If true, animations are skipped." }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, - "tooltip": { - "description": "The configuration of the tooltip.", - "seeMoreText": "See {{link}} for more details." - }, "topAxis": { "description": "Indicate which axis to display the top of the charts. Can be a string (the id of the axis) or an object ChartsXAxisProps." }, @@ -79,18 +75,16 @@ "classDescriptions": {}, "slotDescriptions": { "area": "The component that renders the area.", - "axisContent": "Custom component for displaying tooltip content when triggered by axis event.", "axisLabel": "Custom component for axis label.", "axisLine": "Custom component for the axis main line.", "axisTick": "Custom component for the axis tick.", "axisTickLabel": "Custom component for tick label.", - "itemContent": "Custom component for displaying tooltip content when triggered by item event.", "legend": "Custom rendering of the legend.", "line": "The component that renders the line.", "lineHighlight": "", "loadingOverlay": "Overlay component rendered when the chart is in a loading state.", "mark": "", "noDataOverlay": "Overlay component rendered when the chart has no data to display.", - "popper": "Custom component for the tooltip popper." + "tooltip": "Custom component for the tooltip popper." } } diff --git a/docs/translations/api-docs/charts/pie-chart/pie-chart.json b/docs/translations/api-docs/charts/pie-chart/pie-chart.json index 837389853351..981a35075a12 100644 --- a/docs/translations/api-docs/charts/pie-chart/pie-chart.json +++ b/docs/translations/api-docs/charts/pie-chart/pie-chart.json @@ -32,10 +32,6 @@ }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, - "tooltip": { - "description": "The configuration of the tooltip.", - "seeMoreText": "See {{link}} for more details." - }, "width": { "description": "The width of the chart in px. If not defined, it takes the width of the parent element." }, @@ -48,13 +44,11 @@ }, "classDescriptions": {}, "slotDescriptions": { - "axisContent": "Custom component for displaying tooltip content when triggered by axis event.", - "itemContent": "Custom component for displaying tooltip content when triggered by item event.", "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.", "pieArc": "", "pieArcLabel": "", - "popper": "Custom component for the tooltip popper." + "tooltip": "Custom component for the tooltip popper." } } diff --git a/docs/translations/api-docs/charts/scatter-chart-pro/scatter-chart-pro.json b/docs/translations/api-docs/charts/scatter-chart-pro/scatter-chart-pro.json index 1ec6c60e26b4..5d1e1a64cfe9 100644 --- a/docs/translations/api-docs/charts/scatter-chart-pro/scatter-chart-pro.json +++ b/docs/translations/api-docs/charts/scatter-chart-pro/scatter-chart-pro.json @@ -59,10 +59,6 @@ }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, - "tooltip": { - "description": "The configuration of the tooltip.", - "seeMoreText": "See {{link}} for more details." - }, "topAxis": { "description": "Indicate which axis to display the top of the charts. Can be a string (the id of the axis) or an object ChartsXAxisProps." }, diff --git a/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json b/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json index f9aba25321b7..85123d0e7102 100644 --- a/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json +++ b/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json @@ -55,10 +55,6 @@ }, "slotProps": { "description": "The props used for each component slot." }, "slots": { "description": "Overridable component slots." }, - "tooltip": { - "description": "The configuration of the tooltip.", - "seeMoreText": "See {{link}} for more details." - }, "topAxis": { "description": "Indicate which axis to display the top of the charts. Can be a string (the id of the axis) or an object ChartsXAxisProps." }, @@ -78,16 +74,14 @@ }, "classDescriptions": {}, "slotDescriptions": { - "axisContent": "Custom component for displaying tooltip content when triggered by axis event.", "axisLabel": "Custom component for axis label.", "axisLine": "Custom component for the axis main line.", "axisTick": "Custom component for the axis tick.", "axisTickLabel": "Custom component for tick label.", - "itemContent": "Custom component for displaying tooltip content when triggered by item event.", "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.", - "popper": "Custom component for the tooltip popper.", - "scatter": "" + "scatter": "", + "tooltip": "Custom component for the tooltip popper." } } diff --git a/docs/translations/api-docs/charts/spark-line-chart/spark-line-chart.json b/docs/translations/api-docs/charts/spark-line-chart/spark-line-chart.json index 24e7cb1b996b..342905c4fba4 100644 --- a/docs/translations/api-docs/charts/spark-line-chart/spark-line-chart.json +++ b/docs/translations/api-docs/charts/spark-line-chart/spark-line-chart.json @@ -54,12 +54,10 @@ "classDescriptions": {}, "slotDescriptions": { "area": "The component that renders the area.", - "axisContent": "Custom component for displaying tooltip content when triggered by axis event.", "bar": "The component that renders the bar.", - "itemContent": "Custom component for displaying tooltip content when triggered by item event.", "line": "The component that renders the line.", "lineHighlight": "", "mark": "", - "popper": "Custom component for the tooltip popper." + "tooltip": "Custom component for the tooltip popper." } } diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index bac0f2306e56..5508b75db439 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -94,10 +94,11 @@ const BarChartPro = React.forwardRef(function BarChartPro( chartsAxisProps, axisHighlightProps, legendProps, - tooltipProps, children, } = useBarChartProps(other); + const Tooltip = props.slots?.tooltip ?? ChartsTooltip; + return ( {props.onAxisClick && } @@ -109,7 +110,7 @@ const BarChartPro = React.forwardRef(function BarChartPro( {!props.hideLegend && } - {!props.loading && } + {!props.loading && } {children} @@ -275,18 +276,6 @@ BarChartPro.propTypes = { PropTypes.object, ]), title: PropTypes.string, - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * Indicate which axis to display the top of the charts. * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. diff --git a/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx b/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx deleted file mode 100644 index 26f6f281d4e1..000000000000 --- a/packages/x-charts-pro/src/Heatmap/DefaultHeatmapTooltip.tsx +++ /dev/null @@ -1,103 +0,0 @@ -'use client'; -import * as React from 'react'; -import PropTypes from 'prop-types'; -import clsx from 'clsx'; -import { - ChartsItemContentProps, - ChartsTooltipPaper, - ChartsTooltipTable, - ChartsTooltipRow, - ChartsTooltipCell, - ChartsTooltipMark, -} from '@mui/x-charts/ChartsTooltip'; -import { useXAxis, useYAxis } from '@mui/x-charts/hooks'; -import { getLabel } from '@mui/x-charts/internals'; - -function DefaultHeatmapTooltip(props: ChartsItemContentProps<'heatmap'>) { - const { series, itemData, sx, classes, getColor } = props; - - const xAxis = useXAxis(); - const yAxis = useYAxis(); - - if (itemData.dataIndex === undefined || !series.data[itemData.dataIndex]) { - return null; - } - - const color = getColor(itemData.dataIndex); - - const valueItem = series.data[itemData.dataIndex]; - const [xIndex, yIndex] = valueItem; - - const formattedX = - xAxis.valueFormatter?.(xAxis.data![xIndex], { location: 'tooltip' }) ?? - xAxis.data![xIndex].toLocaleString(); - const formattedY = - yAxis.valueFormatter?.(yAxis.data![yIndex], { location: 'tooltip' }) ?? - yAxis.data![yIndex].toLocaleString(); - const formattedValue = series.valueFormatter(valueItem, { dataIndex: itemData.dataIndex }); - - const seriesLabel = getLabel(series.label, 'tooltip'); - - return ( - - - - - {formattedX} - {formattedX && formattedY && } - {formattedY} - - - - - - - - - {seriesLabel} - - - {formattedValue} - - - - - - ); -} - -DefaultHeatmapTooltip.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- - /** - * Override or extend the styles applied to the component. - */ - classes: PropTypes.object.isRequired, - /** - * Get the color of the item with index `dataIndex`. - * @param {number} dataIndex The data index of the item. - * @returns {string} The color to display. - */ - getColor: PropTypes.func.isRequired, - /** - * The data used to identify the triggered item. - */ - itemData: PropTypes.shape({ - dataIndex: PropTypes.number.isRequired, - seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - type: PropTypes.oneOf(['heatmap']).isRequired, - }).isRequired, - /** - * The series linked to the triggered item. - */ - series: PropTypes.object.isRequired, - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), -} as any; - -export { DefaultHeatmapTooltip }; diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index c430cd6674c5..7f72b1acbe20 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -6,12 +6,7 @@ import useId from '@mui/utils/useId'; import { MakeOptional } from '@mui/x-internals/types'; import { interpolateRgbBasis } from '@mui/x-charts-vendor/d3-interpolate'; import { ChartsAxis, ChartsAxisProps } from '@mui/x-charts/ChartsAxis'; -import { - ChartsTooltip, - ChartsTooltipProps, - ChartsTooltipSlotProps, - ChartsTooltipSlots, -} from '@mui/x-charts/ChartsTooltip'; +import { ChartsTooltipProps } from '@mui/x-charts/ChartsTooltip'; import { ChartsAxisSlots, ChartsAxisSlotProps, @@ -34,19 +29,22 @@ import { ChartContainerPro, ChartContainerProProps } from '../ChartContainerPro' import { HeatmapSeriesType } from '../models/seriesType/heatmap'; import { HeatmapPlot } from './HeatmapPlot'; import { plugin as heatmapPlugin } from './plugin'; -import { DefaultHeatmapTooltip } from './DefaultHeatmapTooltip'; +import { HeatmapTooltip, HeatmapTooltipProps } from './HeatmapTooltip'; import { HeatmapItemSlotProps, HeatmapItemSlots } from './HeatmapItem'; -export interface HeatmapSlots - extends ChartsAxisSlots, - Omit, 'axisContent'>, - ChartsOverlaySlots, - HeatmapItemSlots {} +export interface HeatmapSlots extends ChartsAxisSlots, ChartsOverlaySlots, HeatmapItemSlots { + /** + * Custom component for the tooltip popper. + * @default ChartsTooltipRoot + */ + tooltip?: React.ElementType; +} export interface HeatmapSlotProps extends ChartsAxisSlotProps, - Omit, 'axisContent'>, ChartsOverlaySlotProps, - HeatmapItemSlotProps {} + HeatmapItemSlotProps { + tooltip?: Partial; +} export interface HeatmapProps extends Omit< @@ -77,7 +75,7 @@ export interface HeatmapProps * The configuration of the tooltip. * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. */ - tooltip?: ChartsTooltipProps<'heatmap'>; + tooltip?: ChartsTooltipProps; /** * Overridable component slots. * @default {} @@ -119,7 +117,6 @@ const Heatmap = React.forwardRef(function Heatmap( colors, dataset, sx, - tooltip, topAxis, leftAxis, rightAxis, @@ -161,6 +158,8 @@ const Heatmap = React.forwardRef(function Heatmap( [zAxis], ); + const Tooltip = props.slots?.tooltip ?? HeatmapTooltip; + return ( - {!loading && ( - - )} + {!loading && } {children} @@ -317,14 +309,7 @@ Heatmap.propTypes = { * The configuration of the tooltip. * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), + tooltip: PropTypes.object, /** * Indicate which axis to display the top of the charts. * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. diff --git a/packages/x-charts-pro/src/Heatmap/HeatmapTooltip.tsx b/packages/x-charts-pro/src/Heatmap/HeatmapTooltip.tsx new file mode 100644 index 000000000000..2ecefa914ce3 --- /dev/null +++ b/packages/x-charts-pro/src/Heatmap/HeatmapTooltip.tsx @@ -0,0 +1,371 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import clsx from 'clsx'; +import composeClasses from '@mui/utils/composeClasses'; +import { + ChartsTooltipPaper, + ChartsTooltipTable, + ChartsTooltipRow, + ChartsTooltipCell, + ChartsTooltipMark, + useItemTooltip, + ChartsTooltipContainerProps, + getChartsTooltipUtilityClass, + ChartsTooltipContainer, +} from '@mui/x-charts/ChartsTooltip'; +import { useXAxis, useYAxis } from '@mui/x-charts/hooks'; +import { getLabel } from '@mui/x-charts/internals'; +import { useHeatmapSeries } from '../hooks/useSeries'; + +export interface HeatmapTooltipProps + extends Omit {} + +const useUtilityClasses = (ownerState: { classes: HeatmapTooltipProps['classes'] }) => { + const { classes } = ownerState; + + const slots = { + root: ['root'], + paper: ['paper'], + table: ['table'], + row: ['row'], + cell: ['cell'], + mark: ['mark'], + markCell: ['markCell'], + labelCell: ['labelCell'], + valueCell: ['valueCell'], + }; + + return composeClasses(slots, getChartsTooltipUtilityClass, classes); +}; + +/** + * @ignore - internal component. + */ +function DefaultHeatmapTooltipContent(props: Pick) { + const { classes } = props; + + const xAxis = useXAxis(); + const yAxis = useYAxis(); + const heatmapSeries = useHeatmapSeries(); + + const tooltipData = useItemTooltip<'heatmap'>(); + + if (!tooltipData || !heatmapSeries || heatmapSeries.seriesOrder.length === 0) { + return null; + } + + const { series, seriesOrder } = heatmapSeries; + const seriesId = seriesOrder[0]; + + const { color, value, identifier } = tooltipData; + + const [xIndex, yIndex] = value; + + const formattedX = + xAxis.valueFormatter?.(xAxis.data![xIndex], { location: 'tooltip' }) ?? + xAxis.data![xIndex].toLocaleString(); + const formattedY = + yAxis.valueFormatter?.(yAxis.data![yIndex], { location: 'tooltip' }) ?? + yAxis.data![yIndex].toLocaleString(); + const formattedValue = series[seriesId].valueFormatter(value, { + dataIndex: identifier.dataIndex, + }); + + const seriesLabel = getLabel(series[seriesId].label, 'tooltip'); + + return ( + + + + + {formattedX} + {formattedX && formattedY && } + {formattedY} + + + + + + + + + {seriesLabel} + + + {formattedValue} + + + + + + ); +} + +DefaultHeatmapTooltipContent.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, +} as any; + +function HeatmapTooltip(props: HeatmapTooltipProps) { + const classes = useUtilityClasses({ classes: props.classes }); + + return ( + + + + ); +} + +HeatmapTooltip.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * An HTML element, [virtualElement](https://popper.js.org/docs/v2/virtual-elements/), + * or a function that returns either. + * It's used to set the position of the popper. + * The return value will passed as the reference object of the Popper instance. + */ + anchorEl: PropTypes.oneOfType([ + (props, propName) => { + if (props[propName] == null) { + return new Error(`Prop '${propName}' is required but wasn't specified`); + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + PropTypes.func, + PropTypes.shape({ + contextElement: (props, propName) => { + if (props[propName] == null) { + return null; + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + getBoundingClientRect: PropTypes.func.isRequired, + }), + ]), + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + /** + * The component used for the root node. + * Either a string to use a HTML element or a component. + */ + component: PropTypes.elementType, + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + components: PropTypes.shape({ + Root: PropTypes.elementType, + }), + /** + * The props used for each slot inside the Popper. + * @default {} + */ + componentsProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * An HTML element or function that returns one. + * The `container` will have the portal children appended to it. + * + * You can also provide a callback, which is called in a React layout effect. + * This lets you set the container from a ref, and also makes server-side rendering possible. + * + * By default, it uses the body of the top-level document object, + * so it's simply `document.body` most of the time. + */ + container: PropTypes.oneOfType([ + (props, propName) => { + if (props[propName] == null) { + return new Error(`Prop '${propName}' is required but wasn't specified`); + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + PropTypes.func, + ]), + /** + * The `children` will be under the DOM hierarchy of the parent component. + * @default false + */ + disablePortal: PropTypes.bool, + /** + * Always keep the children in the DOM. + * This prop can be useful in SEO situation or + * when you want to maximize the responsiveness of the Popper. + * @default false + */ + keepMounted: PropTypes.bool, + /** + * Popper.js is based on a "plugin-like" architecture, + * most of its features are fully encapsulated "modifiers". + * + * A modifier is a function that is called each time Popper.js needs to + * compute the position of the popper. + * For this reason, modifiers should be very performant to avoid bottlenecks. + * To learn how to create a modifier, [read the modifiers documentation](https://popper.js.org/docs/v2/modifiers/). + */ + modifiers: PropTypes.arrayOf( + PropTypes.shape({ + data: PropTypes.object, + effect: PropTypes.func, + enabled: PropTypes.bool, + fn: PropTypes.func, + name: PropTypes.any, + options: PropTypes.object, + phase: PropTypes.oneOf([ + 'afterMain', + 'afterRead', + 'afterWrite', + 'beforeMain', + 'beforeRead', + 'beforeWrite', + 'main', + 'read', + 'write', + ]), + requires: PropTypes.arrayOf(PropTypes.string), + requiresIfExists: PropTypes.arrayOf(PropTypes.string), + }), + ), + /** + * If `true`, the component is shown. + */ + open: PropTypes.bool, + /** + * Popper placement. + * @default 'bottom' + */ + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]), + /** + * Options provided to the [`Popper.js`](https://popper.js.org/docs/v2/constructors/#options) instance. + * @default {} + */ + popperOptions: PropTypes.shape({ + modifiers: PropTypes.array, + onFirstUpdate: PropTypes.func, + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]), + strategy: PropTypes.oneOf(['absolute', 'fixed']), + }), + /** + * A ref that points to the used popper instance. + */ + popperRef: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + current: PropTypes.shape({ + destroy: PropTypes.func.isRequired, + forceUpdate: PropTypes.func.isRequired, + setOptions: PropTypes.func.isRequired, + state: PropTypes.shape({ + attributes: PropTypes.object.isRequired, + elements: PropTypes.object.isRequired, + modifiersData: PropTypes.object.isRequired, + options: PropTypes.object.isRequired, + orderedModifiers: PropTypes.arrayOf(PropTypes.object).isRequired, + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]).isRequired, + rects: PropTypes.object.isRequired, + reset: PropTypes.bool.isRequired, + scrollParents: PropTypes.object.isRequired, + strategy: PropTypes.oneOf(['absolute', 'fixed']).isRequired, + styles: PropTypes.object.isRequired, + }).isRequired, + update: PropTypes.func.isRequired, + }), + }), + ]), + /** + * The props used for each slot inside the Popper. + * @default {} + */ + slotProps: PropTypes.object, + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.object, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Help supporting a react-transition-group/Transition component. + * @default false + */ + transition: PropTypes.bool, +} as any; + +export { HeatmapTooltip }; diff --git a/packages/x-charts-pro/src/Heatmap/index.ts b/packages/x-charts-pro/src/Heatmap/index.ts index ceba96993d01..d1aca0961766 100644 --- a/packages/x-charts-pro/src/Heatmap/index.ts +++ b/packages/x-charts-pro/src/Heatmap/index.ts @@ -2,5 +2,5 @@ import type {} from '../typeOverloads'; export { Heatmap } from './Heatmap'; export { HeatmapPlot } from './HeatmapPlot'; -export * from './DefaultHeatmapTooltip'; +export * from './HeatmapTooltip'; export * from './heatmapClasses'; diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index fbd60d08f188..e9dec5d30cca 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -163,10 +163,11 @@ const LineChartPro = React.forwardRef(function LineChartPro( axisHighlightProps, lineHighlightPlotProps, legendProps, - tooltipProps, children, } = useLineChartProps(other); + const Tooltip = props.slots?.tooltip ?? ChartsTooltip; + return ( {props.onAxisClick && } @@ -184,7 +185,7 @@ const LineChartPro = React.forwardRef(function LineChartPro( {!props.hideLegend && } - {!props.loading && } + {!props.loading && } {children} @@ -346,19 +347,6 @@ LineChartPro.propTypes = { PropTypes.object, ]), title: PropTypes.string, - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * Indicate which axis to display the top of the charts. * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index 56cdfd6bc7d7..b8fd1543b725 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -44,10 +44,11 @@ const ScatterChartPro = React.forwardRef(function ScatterChartPro( overlayProps, legendProps, axisHighlightProps, - tooltipProps, children, } = useScatterChartProps(other); + const Tooltip = props.slots?.tooltip ?? ChartsTooltip; + return ( @@ -61,7 +62,7 @@ const ScatterChartPro = React.forwardRef(function ScatterChartPro( {!props.hideLegend && } - {!props.loading && } + {!props.loading && } {children} @@ -207,19 +208,6 @@ ScatterChartPro.propTypes = { PropTypes.object, ]), title: PropTypes.string, - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * Indicate which axis to display the top of the charts. * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 9df325e00349..e437a1a68821 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -7,12 +7,8 @@ import { BarPlot, BarPlotProps, BarPlotSlotProps, BarPlotSlots } from './BarPlot import { ChartContainer, ChartContainerProps } from '../ChartContainer'; import { ChartsAxis, ChartsAxisProps } from '../ChartsAxis'; import { BarSeriesType } from '../models/seriesType/bar'; -import { - ChartsTooltip, - ChartsTooltipProps, - ChartsTooltipSlotProps, - ChartsTooltipSlots, -} from '../ChartsTooltip'; +import { ChartsTooltip } from '../ChartsTooltip'; +import { ChartsTooltipSlots, ChartsTooltipSlotProps } from '../ChartsTooltip/ChartTooltip.types'; import { ChartsLegend, ChartsLegendSlots, ChartsLegendSlotProps } from '../ChartsLegend'; import { ChartsAxisHighlight, ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsClipPath } from '../ChartsClipPath'; @@ -34,14 +30,14 @@ export interface BarChartSlots extends ChartsAxisSlots, BarPlotSlots, ChartsLegendSlots, - ChartsTooltipSlots<'bar'>, - ChartsOverlaySlots {} + ChartsOverlaySlots, + ChartsTooltipSlots {} export interface BarChartSlotProps extends ChartsAxisSlotProps, BarPlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps<'bar'>, - ChartsOverlaySlotProps {} + ChartsOverlaySlotProps, + ChartsTooltipSlotProps {} export interface BarChartProps extends Omit, @@ -54,11 +50,6 @@ export interface BarChartProps * An array of [[BarSeriesType]] objects. */ series: MakeOptional[]; - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - */ - tooltip?: ChartsTooltipProps<'bar'>; /** * Option to display a cartesian grid in the background. */ @@ -119,10 +110,11 @@ const BarChart = React.forwardRef(function BarChart( chartsAxisProps, axisHighlightProps, legendProps, - tooltipProps, children, } = useBarChartProps(props); + const Tooltip = props.slots?.tooltip ?? ChartsTooltip; + return ( {props.onAxisClick && } @@ -134,7 +126,7 @@ const BarChart = React.forwardRef(function BarChart( {!props.hideLegend && } - {!props.loading && } + {!props.loading && } {children} @@ -293,18 +285,6 @@ BarChart.propTypes = { PropTypes.object, ]), title: PropTypes.string, - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * Indicate which axis to display the top of the charts. * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. diff --git a/packages/x-charts/src/BarChart/useBarChartProps.ts b/packages/x-charts/src/BarChart/useBarChartProps.ts index 29e508841e40..ab65c93ad40e 100644 --- a/packages/x-charts/src/BarChart/useBarChartProps.ts +++ b/packages/x-charts/src/BarChart/useBarChartProps.ts @@ -11,7 +11,6 @@ import { ChartsOverlayProps } from '../ChartsOverlay'; import { ChartsAxisProps } from '../ChartsAxis'; import { ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsLegendProps } from '../ChartsLegend'; -import { ChartsTooltipProps } from '../ChartsTooltip'; /** * A helper function that extracts BarChartProps from the input props @@ -31,7 +30,6 @@ export const useBarChartProps = (props: BarChartProps) => { colors, dataset, sx, - tooltip, onAxisClick, axisHighlight, grid, @@ -92,7 +90,7 @@ export const useBarChartProps = (props: BarChartProps) => { highlightedItem, onHighlightChange, disableAxisListener: - tooltip?.trigger !== 'axis' && + slotProps?.tooltip?.trigger !== 'axis' && axisHighlight?.x === 'none' && axisHighlight?.y === 'none' && !onAxisClick, @@ -150,12 +148,6 @@ export const useBarChartProps = (props: BarChartProps) => { slotProps, }; - const tooltipProps: ChartsTooltipProps<'bar'> = { - ...tooltip, - slots, - slotProps, - }; - return { chartContainerProps, barPlotProps, @@ -167,7 +159,6 @@ export const useBarChartProps = (props: BarChartProps) => { chartsAxisProps, axisHighlightProps, legendProps, - tooltipProps, children, }; }; diff --git a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx index a5a7d65b0ab7..de763e59a328 100644 --- a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx +++ b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx @@ -1,10 +1,10 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { useStore } from '../internals/useStore'; import { useSeries } from '../hooks/useSeries'; import { useSvgRef } from '../hooks'; import { useCartesianContext } from '../context/CartesianProvider'; +import { useStore } from '../internals/useStore'; export type ChartsAxisData = { dataIndex: number; diff --git a/packages/x-charts/src/ChartsTooltip/ChartTooltip.types.ts b/packages/x-charts/src/ChartsTooltip/ChartTooltip.types.ts new file mode 100644 index 000000000000..f2a68ed60b56 --- /dev/null +++ b/packages/x-charts/src/ChartsTooltip/ChartTooltip.types.ts @@ -0,0 +1,17 @@ +import { ChartsTooltipProps } from './ChartsTooltip'; + +export interface ChartsTooltipSlots { + /** + * Custom component for the tooltip popper. + * @default ChartsTooltipRoot + */ + tooltip?: React.ElementType; +} + +export interface ChartsTooltipSlotProps { + /** + * Custom component for the tooltip popper. + * @default ChartsTooltipRoot + */ + tooltip?: Partial; +} diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index ed4f1a6608b4..a6a0f2bfcdc4 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -1,140 +1,96 @@ +'use client'; import * as React from 'react'; +import PropTypes from 'prop-types'; import { SxProps, Theme } from '@mui/material/styles'; -import useSlotProps from '@mui/utils/useSlotProps'; -import { AxisInteractionData } from '../internals/plugins/models'; -import { useCartesianContext } from '../context/CartesianProvider'; -import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; -import { AxisDefaultized } from '../models/axis'; -import { ChartsTooltipClasses } from './chartsTooltipClasses'; -import { DefaultChartsAxisTooltipContent } from './DefaultChartsAxisTooltipContent'; -import { ZAxisContext } from '../context/ZAxisContextProvider'; -import { useColorProcessor } from '../context/PluginProvider/useColorProcessor'; -import { isCartesianSeriesType } from '../internals/isCartesian'; -import { useSeries } from '../hooks/useSeries'; - -type ChartSeriesDefaultizedWithColorGetter = ChartSeriesDefaultized & { - getColor: (dataIndex: number) => string; -}; - -export type ChartsAxisContentProps = { - /** - * Data identifying the triggered axis. - */ - axisData: AxisInteractionData; - /** - * The series linked to the triggered axis. - */ - series: ChartSeriesDefaultizedWithColorGetter[]; - /** - * The properties of the triggered axis. - */ - axis: AxisDefaultized; - /** - * The index of the data item triggered. - */ - dataIndex?: null | number; - /** - * The value associated to the current mouse position. - */ - axisValue: string | number | Date | null; +import Typography from '@mui/material/Typography'; +import clsx from 'clsx'; +import { ChartsTooltipClasses, useUtilityClasses } from './chartsTooltipClasses'; +import { + ChartsTooltipCell, + ChartsTooltipMark, + ChartsTooltipPaper, + ChartsTooltipRow, + ChartsTooltipTable, +} from './ChartsTooltipTable'; +import { useAxisTooltip } from './useAxisTooltip'; +import { useXAxis, useYAxis } from '../hooks'; + +export interface ChartsAxisTooltipContentProps { /** * Override or extend the styles applied to the component. */ - classes: ChartsTooltipClasses; + classes?: Partial; sx?: SxProps; -}; - -/** - * @ignore - internal component. - */ -function ChartsAxisTooltipContent(props: { - axisData: AxisInteractionData; - content?: React.ElementType; - contentProps?: Partial; - sx?: SxProps; - classes: ChartsAxisContentProps['classes']; -}) { - const { content, contentProps, axisData, sx, classes } = props; - - const isXaxis = axisData.x && axisData.x.index !== -1; - - const dataIndex = isXaxis ? axisData.x && axisData.x.index : axisData.y && axisData.y.index; - const axisValue = isXaxis ? axisData.x && axisData.x.value : axisData.y && axisData.y.value; - - const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); - const { zAxisIds, zAxis } = React.useContext(ZAxisContext); - const series = useSeries(); - - const colorProcessors = useColorProcessor(); - - const USED_AXIS_ID = isXaxis ? xAxisIds[0] : yAxisIds[0]; - - const relevantSeries = React.useMemo(() => { - const rep: any[] = []; - Object.keys(series) - .filter(isCartesianSeriesType) - .forEach((seriesType) => { - series[seriesType]!.seriesOrder.forEach((seriesId) => { - const item = series[seriesType]!.series[seriesId]; - - const providedXAxisId = item.xAxisId; - const providedYAxisId = item.yAxisId; - - const axisKey = isXaxis ? providedXAxisId : providedYAxisId; - - if (axisKey === undefined || axisKey === USED_AXIS_ID) { - const seriesToAdd = series[seriesType]!.series[seriesId]; - - const xAxisId = providedXAxisId ?? xAxisIds[0]; - const yAxisId = providedYAxisId ?? yAxisIds[0]; - const zAxisId = (seriesToAdd as any).zAxisId ?? zAxisIds[0]; - - const getColor = - colorProcessors[seriesType]?.( - seriesToAdd as any, - xAxis[xAxisId], - yAxis[yAxisId], - zAxisId && zAxis[zAxisId], - ) ?? (() => ''); - - rep.push({ ...seriesToAdd, getColor }); - } - }); - }); - return rep; - }, [ - USED_AXIS_ID, - colorProcessors, - isXaxis, - series, - xAxis, - xAxisIds, - yAxis, - yAxisIds, - zAxis, - zAxisIds, - ]); - - const relevantAxis = React.useMemo(() => { - return isXaxis ? xAxis[USED_AXIS_ID] : yAxis[USED_AXIS_ID]; - }, [USED_AXIS_ID, isXaxis, xAxis, yAxis]); +} - const Content = content ?? DefaultChartsAxisTooltipContent; - const chartTooltipContentProps = useSlotProps({ - elementType: Content, - externalSlotProps: contentProps, - additionalProps: { - axisData, - series: relevantSeries, - axis: relevantAxis, - dataIndex, - axisValue, - sx, - classes, - }, - ownerState: {}, - }); - return ; +function ChartsAxisTooltipContent(props: ChartsAxisTooltipContentProps) { + const { classes: propClasses, sx } = props; + const tootlipData = useAxisTooltip(); + const xAxis = useXAxis(); + const yAxis = useYAxis(); + + const classes = useUtilityClasses(propClasses); + + if (tootlipData === null) { + return null; + } + + const { axisDirection, axisValue, axisFormattedValue, seriesItems } = tootlipData; + + const axis = axisDirection === 'x' ? xAxis : yAxis; + + return ( + + + {axisValue != null && !axis.hideTooltip && ( + + + + {axisFormattedValue} + + + + )} + + + {seriesItems.map(({ seriesId, color, formattedValue, formattedLabel }) => { + if (formattedValue == null) { + return null; + } + return ( + + + {color && } + + + {formattedLabel ? {formattedLabel} : null} + + + {formattedValue} + + + ); + })} + + + + ); } +ChartsAxisTooltipContent.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), +} as any; + export { ChartsAxisTooltipContent }; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index 8d374db974f7..fc2b33395c15 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -1,85 +1,72 @@ +'use client'; import * as React from 'react'; +import PropTypes from 'prop-types'; +import clsx from 'clsx'; import { SxProps, Theme } from '@mui/material/styles'; -import useSlotProps from '@mui/utils/useSlotProps'; -import { ItemInteractionData } from '../internals/plugins/models'; -import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; -import { ChartsTooltipClasses } from './chartsTooltipClasses'; -import { DefaultChartsItemTooltipContent } from './DefaultChartsItemTooltipContent'; -import { useCartesianContext } from '../context/CartesianProvider'; -import { ZAxisContext } from '../context/ZAxisContextProvider'; -import { useColorProcessor } from '../context/PluginProvider/useColorProcessor'; -import { useSeries } from '../hooks/useSeries'; +import { ChartsTooltipClasses, useUtilityClasses } from './chartsTooltipClasses'; +import { useItemTooltip } from './useItemTooltip'; +import { + ChartsTooltipCell, + ChartsTooltipMark, + ChartsTooltipPaper, + ChartsTooltipRow, + ChartsTooltipTable, +} from './ChartsTooltipTable'; -export interface ChartsItemContentProps { - /** - * The data used to identify the triggered item. - */ - itemData: ItemInteractionData; - /** - * The series linked to the triggered item. - */ - series: ChartSeriesDefaultized; +export interface ChartsItemTooltipContentProps { /** * Override or extend the styles applied to the component. */ - classes: ChartsTooltipClasses; - /** - * Get the color of the item with index `dataIndex`. - * @param {number} dataIndex The data index of the item. - * @returns {string} The color to display. - */ - getColor: (dataIndex: number) => string; + classes?: Partial; sx?: SxProps; } -export interface ChartsItemTooltipContentProps { - itemData: ItemInteractionData; - content?: React.ElementType>; - contentProps?: Partial>; - sx?: SxProps; - classes: ChartsItemContentProps['classes']; -} +function ChartsItemTooltipContent(props: ChartsItemTooltipContentProps) { + const { classes: propClasses, sx } = props; + const tooltipData = useItemTooltip(); -/** - * @ignore - internal component. - */ -function ChartsItemTooltipContent( - props: ChartsItemTooltipContentProps, -) { - const { content, itemData, sx, classes, contentProps } = props; + const classes = useUtilityClasses(propClasses); - const series = useSeries()[itemData.type]!.series[itemData.seriesId] as ChartSeriesDefaultized; + if (!tooltipData) { + return null; + } + const { color, label, formattedValue } = tooltipData; - const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); - const { zAxis, zAxisIds } = React.useContext(ZAxisContext); - const colorProcessors = useColorProcessor(); - - const xAxisId = (series as any).xAxisId ?? xAxisIds[0]; - const yAxisId = (series as any).yAxisId ?? yAxisIds[0]; - const zAxisId = (series as any).zAxisId ?? zAxisIds[0]; - - const getColor = - colorProcessors[series.type]?.( - series as any, - xAxisId && xAxis[xAxisId], - yAxisId && yAxis[yAxisId], - zAxisId && zAxis[zAxisId], - ) ?? (() => ''); - - const Content = content ?? DefaultChartsItemTooltipContent; - const chartTooltipContentProps = useSlotProps({ - elementType: Content, - externalSlotProps: contentProps, - additionalProps: { - itemData, - series, - sx, - classes, - getColor, - }, - ownerState: {}, - }); - return ; + return ( + + + + + + + + + {label} + + + {formattedValue} + + + + + + ); } +ChartsItemTooltipContent.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), +} as any; + export { ChartsItemTooltipContent }; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx index 544dac733866..6173a3f6bd2f 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx @@ -1,120 +1,12 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import composeClasses from '@mui/utils/composeClasses'; -import useLazyRef from '@mui/utils/useLazyRef'; -import { styled, useThemeProps, SxProps, Theme } from '@mui/material/styles'; -import Popper, { PopperProps as BasePopperProps } from '@mui/material/Popper'; -import NoSsr from '@mui/material/NoSsr'; -import useSlotProps from '@mui/utils/useSlotProps'; -import { useSvgRef } from '../hooks/useSvgRef'; -import { getTooltipHasData, TriggerOptions, usePointerType } from './utils'; -import { ChartSeriesType } from '../models/seriesType/config'; -import { ChartsItemContentProps, ChartsItemTooltipContent } from './ChartsItemTooltipContent'; -import { ChartsAxisContentProps, ChartsAxisTooltipContent } from './ChartsAxisTooltipContent'; -import { ChartsTooltipClasses, getChartsTooltipUtilityClass } from './chartsTooltipClasses'; -import { - selectorChartsInteractionItem, - selectorChartsInteractionAxis, -} from '../context/InteractionSelectors'; -import { ItemInteractionData, AxisInteractionData } from '../internals/plugins/models'; -import { useSelector } from '../internals/useSelector'; -import { useStore } from '../internals/useStore'; +import { ChartsItemTooltipContent } from './ChartsItemTooltipContent'; +import { ChartsAxisTooltipContent } from './ChartsAxisTooltipContent'; +import { ChartsTooltipContainer, ChartsTooltipContainerProps } from './ChartsTooltipContainer'; +import { useUtilityClasses } from './chartsTooltipClasses'; -export type PopperProps = BasePopperProps & { - /** - * The system prop that allows defining system overrides as well as additional CSS styles. - */ - sx?: SxProps; -}; - -export interface ChartsTooltipSlots { - /** - * Custom component for the tooltip popper. - * @default ChartsTooltipRoot - */ - popper?: React.ElementType; - /** - * Custom component for displaying tooltip content when triggered by axis event. - * @default DefaultChartsAxisTooltipContent - */ - axisContent?: React.ElementType; - /** - * Custom component for displaying tooltip content when triggered by item event. - * @default DefaultChartsItemTooltipContent - */ - itemContent?: React.ElementType>; -} - -export interface ChartsTooltipSlotProps { - popper?: Partial; - axisContent?: Partial; - itemContent?: Partial>; -} - -export interface ChartsTooltipProps { - /** - * Select the kind of tooltip to display - * - 'item': Shows data about the item below the mouse. - * - 'axis': Shows values associated with the hovered x value - * - 'none': Does not display tooltip - * @default 'axis' - */ - trigger?: TriggerOptions; - /** - * Component to override the tooltip content when trigger is set to 'item'. - * @deprecated Use slots.itemContent instead - */ - itemContent?: React.ElementType>; - /** - * Component to override the tooltip content when trigger is set to 'axis'. - * @deprecated Use slots.axisContent instead - */ - axisContent?: React.ElementType; - /** - * Override or extend the styles applied to the component. - */ - classes?: Partial; - /** - * Overridable component slots. - * @default {} - */ - slots?: ChartsTooltipSlots; - /** - * The props used for each component slot. - * @default {} - */ - slotProps?: ChartsTooltipSlotProps; -} - -const useUtilityClasses = (ownerState: { - classes: ChartsTooltipProps['classes']; -}) => { - const { classes } = ownerState; - - const slots = { - root: ['root'], - paper: ['paper'], - table: ['table'], - row: ['row'], - cell: ['cell'], - mark: ['mark'], - markCell: ['markCell'], - labelCell: ['labelCell'], - valueCell: ['valueCell'], - }; - - return composeClasses(slots, getChartsTooltipUtilityClass, classes); -}; - -const ChartsTooltipRoot = styled(Popper, { - name: 'MuiChartsTooltip', - slot: 'Root', - overridesResolver: (_, styles) => styles.root, -})(({ theme }) => ({ - pointerEvents: 'none', - zIndex: theme.zIndex.modal, -})); +export interface ChartsTooltipProps extends Omit {} /** * Demos: @@ -125,113 +17,19 @@ const ChartsTooltipRoot = styled(Popper, { * * - [ChartsTooltip API](https://mui.com/x/api/charts/charts-tool-tip/) */ -function ChartsTooltip(inProps: ChartsTooltipProps) { - const props = useThemeProps({ - props: inProps, - name: 'MuiChartsTooltip', - }); - const { trigger = 'axis', itemContent, axisContent, slots, slotProps } = props; - - const svgRef = useSvgRef(); - const pointerType = usePointerType(); - - const popperRef: PopperProps['popperRef'] = React.useRef(null); - - const positionRef = useLazyRef(() => ({ x: 0, y: 0 })); +function ChartsTooltip(props: ChartsTooltipProps) { + const { classes: propClasses, trigger = 'axis' } = props; - const store = useStore(); - const item = useSelector(store, selectorChartsInteractionItem); - const axis = useSelector(store, selectorChartsInteractionAxis); - - const displayedData = trigger === 'item' ? item : axis; - - const tooltipHasData = getTooltipHasData(trigger, displayedData); - const popperOpen = pointerType !== null && tooltipHasData; - - const classes = useUtilityClasses({ classes: props.classes }); - - const PopperComponent = slots?.popper ?? ChartsTooltipRoot; - const popperProps = useSlotProps({ - elementType: PopperComponent, - externalSlotProps: slotProps?.popper, - additionalProps: { - open: popperOpen, - placement: pointerType?.pointerType === 'mouse' ? ('right-start' as const) : ('top' as const), - popperRef, - anchorEl: { - getBoundingClientRect: () => ({ - x: positionRef.current.x, - y: positionRef.current.y, - top: positionRef.current.y, - left: positionRef.current.x, - right: positionRef.current.x, - bottom: positionRef.current.y, - width: 0, - height: 0, - toJSON: () => '', - }), - }, - modifiers: [ - { - name: 'offset', - options: { - offset: [0, pointerType?.pointerType === 'touch' ? 40 - pointerType.height : 0], - }, - }, - ], - }, - ownerState: {}, - }); - - React.useEffect(() => { - const element = svgRef.current; - if (element === null) { - return () => {}; - } - - const handleMove = (event: PointerEvent) => { - // eslint-disable-next-line react-compiler/react-compiler - positionRef.current = { - x: event.clientX, - y: event.clientY, - }; - popperRef.current?.update(); - }; - element.addEventListener('pointermove', handleMove); - - return () => { - element.removeEventListener('pointermove', handleMove); - }; - }, [svgRef, positionRef]); - - if (trigger === 'none') { - return null; - } + const classes = useUtilityClasses(propClasses); return ( - - {popperOpen && ( - - {trigger === 'item' ? ( - } - content={(slots?.itemContent ?? itemContent) as any} - contentProps={slotProps?.itemContent as Partial>} - sx={{ mx: 2 }} - classes={classes} - /> - ) : ( - - )} - + + {trigger === 'axis' ? ( + + ) : ( + )} - +
); } @@ -241,29 +39,243 @@ ChartsTooltip.propTypes = { // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- /** - * Component to override the tooltip content when trigger is set to 'axis'. - * @deprecated Use slots.axisContent instead + * An HTML element, [virtualElement](https://popper.js.org/docs/v2/virtual-elements/), + * or a function that returns either. + * It's used to set the position of the popper. + * The return value will passed as the reference object of the Popper instance. */ - axisContent: PropTypes.elementType, + anchorEl: PropTypes.oneOfType([ + (props, propName) => { + if (props[propName] == null) { + return new Error(`Prop '${propName}' is required but wasn't specified`); + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + PropTypes.func, + PropTypes.shape({ + contextElement: (props, propName) => { + if (props[propName] == null) { + return null; + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + getBoundingClientRect: PropTypes.func.isRequired, + }), + ]), /** * Override or extend the styles applied to the component. */ classes: PropTypes.object, /** - * Component to override the tooltip content when trigger is set to 'item'. - * @deprecated Use slots.itemContent instead + * The component used for the root node. + * Either a string to use a HTML element or a component. */ - itemContent: PropTypes.elementType, + component: PropTypes.elementType, /** - * The props used for each component slot. + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + components: PropTypes.shape({ + Root: PropTypes.elementType, + }), + /** + * The props used for each slot inside the Popper. + * @default {} + */ + componentsProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * An HTML element or function that returns one. + * The `container` will have the portal children appended to it. + * + * You can also provide a callback, which is called in a React layout effect. + * This lets you set the container from a ref, and also makes server-side rendering possible. + * + * By default, it uses the body of the top-level document object, + * so it's simply `document.body` most of the time. + */ + container: PropTypes.oneOfType([ + (props, propName) => { + if (props[propName] == null) { + return new Error(`Prop '${propName}' is required but wasn't specified`); + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + PropTypes.func, + ]), + /** + * The `children` will be under the DOM hierarchy of the parent component. + * @default false + */ + disablePortal: PropTypes.bool, + /** + * Always keep the children in the DOM. + * This prop can be useful in SEO situation or + * when you want to maximize the responsiveness of the Popper. + * @default false + */ + keepMounted: PropTypes.bool, + /** + * Popper.js is based on a "plugin-like" architecture, + * most of its features are fully encapsulated "modifiers". + * + * A modifier is a function that is called each time Popper.js needs to + * compute the position of the popper. + * For this reason, modifiers should be very performant to avoid bottlenecks. + * To learn how to create a modifier, [read the modifiers documentation](https://popper.js.org/docs/v2/modifiers/). + */ + modifiers: PropTypes.arrayOf( + PropTypes.shape({ + data: PropTypes.object, + effect: PropTypes.func, + enabled: PropTypes.bool, + fn: PropTypes.func, + name: PropTypes.any, + options: PropTypes.object, + phase: PropTypes.oneOf([ + 'afterMain', + 'afterRead', + 'afterWrite', + 'beforeMain', + 'beforeRead', + 'beforeWrite', + 'main', + 'read', + 'write', + ]), + requires: PropTypes.arrayOf(PropTypes.string), + requiresIfExists: PropTypes.arrayOf(PropTypes.string), + }), + ), + /** + * If `true`, the component is shown. + */ + open: PropTypes.bool, + /** + * Popper placement. + * @default 'bottom' + */ + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]), + /** + * Options provided to the [`Popper.js`](https://popper.js.org/docs/v2/constructors/#options) instance. + * @default {} + */ + popperOptions: PropTypes.shape({ + modifiers: PropTypes.array, + onFirstUpdate: PropTypes.func, + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]), + strategy: PropTypes.oneOf(['absolute', 'fixed']), + }), + /** + * A ref that points to the used popper instance. + */ + popperRef: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + current: PropTypes.shape({ + destroy: PropTypes.func.isRequired, + forceUpdate: PropTypes.func.isRequired, + setOptions: PropTypes.func.isRequired, + state: PropTypes.shape({ + attributes: PropTypes.object.isRequired, + elements: PropTypes.object.isRequired, + modifiersData: PropTypes.object.isRequired, + options: PropTypes.object.isRequired, + orderedModifiers: PropTypes.arrayOf(PropTypes.object).isRequired, + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]).isRequired, + rects: PropTypes.object.isRequired, + reset: PropTypes.bool.isRequired, + scrollParents: PropTypes.object.isRequired, + strategy: PropTypes.oneOf(['absolute', 'fixed']).isRequired, + styles: PropTypes.object.isRequired, + }).isRequired, + update: PropTypes.func.isRequired, + }), + }), + ]), + /** + * The props used for each slot inside the Popper. * @default {} */ slotProps: PropTypes.object, /** - * Overridable component slots. + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. * @default {} */ slots: PropTypes.object, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Help supporting a react-transition-group/Transition component. + * @default false + */ + transition: PropTypes.bool, /** * Select the kind of tooltip to display * - 'item': Shows data about the item below the mouse. diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx new file mode 100644 index 000000000000..3fcfa1f9234e --- /dev/null +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltipContainer.tsx @@ -0,0 +1,402 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import useLazyRef from '@mui/utils/useLazyRef'; +import { styled, useThemeProps } from '@mui/material/styles'; +import Popper, { PopperProps } from '@mui/material/Popper'; +import NoSsr from '@mui/material/NoSsr'; +import { useSvgRef } from '../hooks/useSvgRef'; +import { TriggerOptions, usePointerType } from './utils'; +import { ChartsTooltipClasses } from './chartsTooltipClasses'; +import { useSelector } from '../internals/useSelector'; +import { useStore } from '../internals/useStore'; +import { useXAxis } from '../hooks'; +import { + selectorChartsInteractionItemIsDefined, + selectorChartsInteractionXAxisIsDefined, + selectorChartsInteractionYAxisIsDefined, +} from '../context/InteractionSelectors'; + +export interface ChartsTooltipContainerProps extends Partial { + /** + * Select the kind of tooltip to display + * - 'item': Shows data about the item below the mouse. + * - 'axis': Shows values associated with the hovered x value + * - 'none': Does not display tooltip + * @default 'axis' + */ + trigger?: TriggerOptions; + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; + children?: React.ReactNode; +} + +const ChartsTooltipRoot = styled(Popper, { + name: 'MuiChartsTooltip', + slot: 'Root', + overridesResolver: (_, styles) => styles.root, +})(({ theme }) => ({ + pointerEvents: 'none', + zIndex: theme.zIndex.modal, +})); + +/** + * Demos: + * + * - [ChartsTooltip](https://mui.com/x/react-charts/tooltip/) + * + * API: + * + * - [ChartsTooltip API](https://mui.com/x/api/charts/charts-tool-tip/) + */ +function ChartsTooltipContainer(inProps: ChartsTooltipContainerProps) { + const props = useThemeProps({ + props: inProps, + name: 'MuiChartsTooltipContainer', + }); + const { trigger = 'axis', classes, children, ...other } = props; + + const svgRef = useSvgRef(); + const pointerType = usePointerType(); + const xAxis = useXAxis(); + + const xAxisHasData = xAxis.data !== undefined && xAxis.data.length !== 0; + + const popperRef: PopperProps['popperRef'] = React.useRef(null); + const positionRef = useLazyRef(() => ({ x: 0, y: 0 })); + + const store = useStore(); + const isOpen = useSelector( + store, + // eslint-disable-next-line no-nested-ternary + trigger === 'axis' + ? xAxisHasData + ? selectorChartsInteractionXAxisIsDefined + : selectorChartsInteractionYAxisIsDefined + : selectorChartsInteractionItemIsDefined, + ); + + const popperOpen = pointerType !== null && isOpen; // tooltipHasData; + + React.useEffect(() => { + const element = svgRef.current; + if (element === null) { + return () => {}; + } + + const handleMove = (event: PointerEvent) => { + // eslint-disable-next-line react-compiler/react-compiler + positionRef.current = { x: event.clientX, y: event.clientY }; + popperRef.current?.update(); + }; + element.addEventListener('pointermove', handleMove); + + return () => { + element.removeEventListener('pointermove', handleMove); + }; + }, [svgRef, positionRef]); + + if (trigger === 'none') { + return null; + } + + return ( + + {popperOpen && ( + ({ + x: positionRef.current.x, + y: positionRef.current.y, + top: positionRef.current.y, + left: positionRef.current.x, + right: positionRef.current.x, + bottom: positionRef.current.y, + width: 0, + height: 0, + toJSON: () => '', + }), + }} + modifiers={[ + { + name: 'offset', + options: { + offset: [0, pointerType?.pointerType === 'touch' ? 40 - pointerType.height : 0], + }, + }, + ]} + {...other} + > + {children} + + )} + + ); +} + +ChartsTooltipContainer.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + /** + * An HTML element, [virtualElement](https://popper.js.org/docs/v2/virtual-elements/), + * or a function that returns either. + * It's used to set the position of the popper. + * The return value will passed as the reference object of the Popper instance. + */ + anchorEl: PropTypes.oneOfType([ + (props, propName) => { + if (props[propName] == null) { + return new Error(`Prop '${propName}' is required but wasn't specified`); + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + PropTypes.func, + PropTypes.shape({ + contextElement: (props, propName) => { + if (props[propName] == null) { + return null; + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + getBoundingClientRect: PropTypes.func.isRequired, + }), + ]), + /** + * Popper render function or node. + */ + children: PropTypes.node, + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + /** + * The component used for the root node. + * Either a string to use a HTML element or a component. + */ + component: PropTypes.elementType, + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + components: PropTypes.shape({ + Root: PropTypes.elementType, + }), + /** + * The props used for each slot inside the Popper. + * @default {} + */ + componentsProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * An HTML element or function that returns one. + * The `container` will have the portal children appended to it. + * + * You can also provide a callback, which is called in a React layout effect. + * This lets you set the container from a ref, and also makes server-side rendering possible. + * + * By default, it uses the body of the top-level document object, + * so it's simply `document.body` most of the time. + */ + container: PropTypes.oneOfType([ + (props, propName) => { + if (props[propName] == null) { + return new Error(`Prop '${propName}' is required but wasn't specified`); + } + if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) { + return new Error(`Expected prop '${propName}' to be of type Element`); + } + return null; + }, + PropTypes.func, + ]), + /** + * The `children` will be under the DOM hierarchy of the parent component. + * @default false + */ + disablePortal: PropTypes.bool, + /** + * Always keep the children in the DOM. + * This prop can be useful in SEO situation or + * when you want to maximize the responsiveness of the Popper. + * @default false + */ + keepMounted: PropTypes.bool, + /** + * Popper.js is based on a "plugin-like" architecture, + * most of its features are fully encapsulated "modifiers". + * + * A modifier is a function that is called each time Popper.js needs to + * compute the position of the popper. + * For this reason, modifiers should be very performant to avoid bottlenecks. + * To learn how to create a modifier, [read the modifiers documentation](https://popper.js.org/docs/v2/modifiers/). + */ + modifiers: PropTypes.arrayOf( + PropTypes.shape({ + data: PropTypes.object, + effect: PropTypes.func, + enabled: PropTypes.bool, + fn: PropTypes.func, + name: PropTypes.any, + options: PropTypes.object, + phase: PropTypes.oneOf([ + 'afterMain', + 'afterRead', + 'afterWrite', + 'beforeMain', + 'beforeRead', + 'beforeWrite', + 'main', + 'read', + 'write', + ]), + requires: PropTypes.arrayOf(PropTypes.string), + requiresIfExists: PropTypes.arrayOf(PropTypes.string), + }), + ), + /** + * If `true`, the component is shown. + */ + open: PropTypes.bool, + /** + * Popper placement. + * @default 'bottom' + */ + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]), + /** + * Options provided to the [`Popper.js`](https://popper.js.org/docs/v2/constructors/#options) instance. + * @default {} + */ + popperOptions: PropTypes.shape({ + modifiers: PropTypes.array, + onFirstUpdate: PropTypes.func, + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]), + strategy: PropTypes.oneOf(['absolute', 'fixed']), + }), + /** + * A ref that points to the used popper instance. + */ + popperRef: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + current: PropTypes.shape({ + destroy: PropTypes.func.isRequired, + forceUpdate: PropTypes.func.isRequired, + setOptions: PropTypes.func.isRequired, + state: PropTypes.shape({ + attributes: PropTypes.object.isRequired, + elements: PropTypes.object.isRequired, + modifiersData: PropTypes.object.isRequired, + options: PropTypes.object.isRequired, + orderedModifiers: PropTypes.arrayOf(PropTypes.object).isRequired, + placement: PropTypes.oneOf([ + 'auto-end', + 'auto-start', + 'auto', + 'bottom-end', + 'bottom-start', + 'bottom', + 'left-end', + 'left-start', + 'left', + 'right-end', + 'right-start', + 'right', + 'top-end', + 'top-start', + 'top', + ]).isRequired, + rects: PropTypes.object.isRequired, + reset: PropTypes.bool.isRequired, + scrollParents: PropTypes.object.isRequired, + strategy: PropTypes.oneOf(['absolute', 'fixed']).isRequired, + styles: PropTypes.object.isRequired, + }).isRequired, + update: PropTypes.func.isRequired, + }), + }), + ]), + /** + * The props used for each slot inside the Popper. + * @default {} + */ + slotProps: PropTypes.object, + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.object, + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), + PropTypes.func, + PropTypes.object, + ]), + /** + * Help supporting a react-transition-group/Transition component. + * @default false + */ + transition: PropTypes.bool, + /** + * Select the kind of tooltip to display + * - 'item': Shows data about the item below the mouse. + * - 'axis': Shows values associated with the hovered x value + * - 'none': Does not display tooltip + * @default 'axis' + */ + trigger: PropTypes.oneOf(['axis', 'item', 'none']), +} as any; + +export { ChartsTooltipContainer }; diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx deleted file mode 100644 index 4ea9771b02fe..000000000000 --- a/packages/x-charts/src/ChartsTooltip/DefaultChartsAxisTooltipContent.tsx +++ /dev/null @@ -1,119 +0,0 @@ -'use client'; -import * as React from 'react'; -import PropTypes from 'prop-types'; -import clsx from 'clsx'; -import Typography from '@mui/material/Typography'; -import { - ChartsTooltipCell, - ChartsTooltipPaper, - ChartsTooltipTable, - ChartsTooltipMark, - ChartsTooltipRow, -} from './ChartsTooltipTable'; -import type { ChartsAxisContentProps } from './ChartsAxisTooltipContent'; -import { utcFormatter } from './utils'; -import { getLabel } from '../internals/getLabel'; -import { isCartesianSeries } from '../internals/isCartesian'; - -function DefaultChartsAxisTooltipContent(props: ChartsAxisContentProps) { - const { series, axis, dataIndex, axisValue, sx, classes } = props; - - if (dataIndex == null) { - return null; - } - - const axisFormatter = - axis.valueFormatter ?? - ((v: string | number | Date) => - axis.scaleType === 'utc' ? utcFormatter(v) : v.toLocaleString()); - - return ( - - - {axisValue != null && !axis.hideTooltip && ( - - - - {axisFormatter(axisValue, { location: 'tooltip' })} - - - - )} - - - {series.filter(isCartesianSeries).map(({ id, label, valueFormatter, data, getColor }) => { - // @ts-ignore - const formattedValue = valueFormatter(data[dataIndex] ?? null, { dataIndex }); - if (formattedValue == null) { - return null; - } - const formattedLabel = getLabel(label, 'tooltip'); - const color = getColor(dataIndex); - return ( - - - {color && } - - - {formattedLabel ? {formattedLabel} : null} - - - {formattedValue} - - - ); - })} - - - - ); -} - -DefaultChartsAxisTooltipContent.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- - /** - * The properties of the triggered axis. - */ - axis: PropTypes.object.isRequired, - /** - * Data identifying the triggered axis. - */ - axisData: PropTypes.shape({ - x: PropTypes.shape({ - index: PropTypes.number, - value: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - }), - y: PropTypes.shape({ - index: PropTypes.number, - value: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]) - .isRequired, - }), - }).isRequired, - /** - * The value associated to the current mouse position. - */ - axisValue: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.number, PropTypes.string]), - /** - * Override or extend the styles applied to the component. - */ - classes: PropTypes.object.isRequired, - /** - * The index of the data item triggered. - */ - dataIndex: PropTypes.number, - /** - * The series linked to the triggered axis. - */ - series: PropTypes.arrayOf(PropTypes.object).isRequired, - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), -} as any; - -export { DefaultChartsAxisTooltipContent }; diff --git a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx deleted file mode 100644 index 70dc2bd15133..000000000000 --- a/packages/x-charts/src/ChartsTooltip/DefaultChartsItemTooltipContent.tsx +++ /dev/null @@ -1,101 +0,0 @@ -'use client'; -import * as React from 'react'; -import PropTypes from 'prop-types'; -import clsx from 'clsx'; -import { ChartSeriesType } from '../models/seriesType/config'; -import { - ChartsTooltipTable, - ChartsTooltipCell, - ChartsTooltipMark, - ChartsTooltipPaper, - ChartsTooltipRow, -} from './ChartsTooltipTable'; -import type { ChartsItemContentProps } from './ChartsItemTooltipContent'; -import { CommonSeriesType } from '../models/seriesType/common'; -import { getLabel } from '../internals/getLabel'; - -function DefaultChartsItemTooltipContent( - props: ChartsItemContentProps, -) { - const { series, itemData, sx, classes, getColor } = props; - - if (itemData.dataIndex === undefined || !series.data[itemData.dataIndex]) { - return null; - } - const { displayedLabel, color } = - series.type === 'pie' - ? { - color: getColor(itemData.dataIndex), - displayedLabel: getLabel(series.data[itemData.dataIndex].label, 'tooltip'), - } - : { - color: getColor(itemData.dataIndex), - displayedLabel: getLabel(series.label, 'tooltip'), - }; - - const value = - series.type === 'pie' - ? { - ...series.data[itemData.dataIndex], - label: getLabel(series.data[itemData.dataIndex].label, 'tooltip'), - } - : series.data[itemData.dataIndex]; - const formattedValue = ( - series.valueFormatter as CommonSeriesType['valueFormatter'] - )?.(value, { dataIndex: itemData.dataIndex }); - return ( - - - - - - - - - {displayedLabel} - - - {formattedValue} - - - - - - ); -} - -DefaultChartsItemTooltipContent.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- - /** - * Override or extend the styles applied to the component. - */ - classes: PropTypes.object.isRequired, - /** - * Get the color of the item with index `dataIndex`. - * @param {number} dataIndex The data index of the item. - * @returns {string} The color to display. - */ - getColor: PropTypes.func.isRequired, - /** - * The data used to identify the triggered item. - */ - itemData: PropTypes.shape({ - dataIndex: PropTypes.number, - seriesId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - type: PropTypes.oneOf(['bar', 'line', 'pie', 'scatter']).isRequired, - }).isRequired, - /** - * The series linked to the triggered axis. - */ - series: PropTypes.object.isRequired, - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), -} as any; - -export { DefaultChartsItemTooltipContent }; diff --git a/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts b/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts index b4ada8e0254b..ca48ae98be11 100644 --- a/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts +++ b/packages/x-charts/src/ChartsTooltip/chartsTooltipClasses.ts @@ -1,7 +1,6 @@ -import { - unstable_generateUtilityClass as generateUtilityClass, - unstable_generateUtilityClasses as generateUtilityClasses, -} from '@mui/utils'; +import generateUtilityClass from '@mui/utils/generateUtilityClass'; +import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; +import composeClasses from '@mui/utils/composeClasses'; export interface ChartsTooltipClasses { /** Styles applied to the root element. */ @@ -37,3 +36,19 @@ export const chartsTooltipClasses: ChartsTooltipClasses = generateUtilityClasses 'MuiChartsTooltip', ['root', 'paper', 'table', 'row', 'cell', 'mark', 'markCell', 'labelCell', 'valueCell'], ); + +export const useUtilityClasses = (classes?: Partial) => { + const slots = { + root: ['root'], + paper: ['paper'], + table: ['table'], + row: ['row'], + cell: ['cell'], + mark: ['mark'], + markCell: ['markCell'], + labelCell: ['labelCell'], + valueCell: ['valueCell'], + }; + + return composeClasses(slots, getChartsTooltipUtilityClass, classes); +}; diff --git a/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx b/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx index bde48ebc9f35..2fa0ee4139b3 100644 --- a/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx +++ b/packages/x-charts/src/ChartsTooltip/contentDisplayed.test.tsx @@ -184,7 +184,7 @@ describe('ChartsTooltip', () => { { dataKey: 'v2', id: 's2', label: 'S2' }, ]} xAxis={[{ scaleType: 'band', dataKey: 'x' }]} - tooltip={{ trigger: 'item' }} + slotProps={{ tooltip: { trigger: 'item' } }} />
, ); @@ -229,7 +229,7 @@ describe('ChartsTooltip', () => { ]} layout="horizontal" yAxis={[{ scaleType: 'band', dataKey: 'x' }]} - tooltip={{ trigger: 'item' }} + slotProps={{ tooltip: { trigger: 'item' } }} />
, ); diff --git a/packages/x-charts/src/ChartsTooltip/index.ts b/packages/x-charts/src/ChartsTooltip/index.ts index 103ca309163f..5ab32ee5621e 100644 --- a/packages/x-charts/src/ChartsTooltip/index.ts +++ b/packages/x-charts/src/ChartsTooltip/index.ts @@ -1,12 +1,11 @@ export * from './ChartsTooltip'; -export * from './chartsTooltipClasses'; +export * from './ChartsTooltipContainer'; +export type { ChartsTooltipClasses, ChartsTooltipClassKey } from './chartsTooltipClasses'; +export { getChartsTooltipUtilityClass, chartsTooltipClasses } from './chartsTooltipClasses'; export * from './ChartsAxisTooltipContent'; export * from './ChartsItemTooltipContent'; -export * from './DefaultChartsAxisTooltipContent'; -export * from './DefaultChartsItemTooltipContent'; - export * from './ChartsTooltipTable'; export * from './useItemTooltip'; diff --git a/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx b/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx index aff76dca6187..01d5edf64255 100644 --- a/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx @@ -6,24 +6,23 @@ import { ZAxisContext } from '../context/ZAxisContextProvider'; import { useColorProcessor } from '../context/PluginProvider/useColorProcessor'; import { SeriesId } from '../models/seriesType/common'; import { CartesianChartSeriesType, ChartsSeriesConfig } from '../models/seriesType/config'; +import { useStore } from '../internals/useStore'; +import { useSelector } from '../internals/useSelector'; import { getLabel } from '../internals/getLabel'; import { isCartesianSeriesType } from '../internals/isCartesian'; import { utcFormatter } from './utils'; +import { useXAxis, useYAxis } from '../hooks/useAxis'; import { - selectorChartsInteractionAxis, selectorChartsInteractionXAxis, selectorChartsInteractionYAxis, } from '../context/InteractionSelectors'; -import { useXAxis, useYAxis } from '../hooks'; -import { useSelector } from '../internals/useSelector'; -import { useStore } from '../internals/useStore'; -import { AxisInteractionData } from '../internals/plugins/models'; export interface UseAxisTooltipReturnValue< SeriesT extends CartesianChartSeriesType = CartesianChartSeriesType, AxisValueT extends string | number | Date = string | number | Date, > { - identifier: AxisInteractionData; + axisDirection: 'x' | 'y'; + dataIndex: number; seriesItems: SeriesItem[]; axisValue: AxisValueT; axisFormattedValue: string; @@ -44,9 +43,6 @@ export function useAxisTooltip(): null | UseAxisTooltipReturnValue { const xAxisHasData = defaultXAxis.data !== undefined && defaultXAxis.data.length !== 0; const store = useStore(); - - // This line will be removed in v8 because it degrade perfs for no reason except avoiding breaking change. - const axis = useSelector(store, selectorChartsInteractionAxis); const axisData = useSelector( store, xAxisHasData ? selectorChartsInteractionXAxis : selectorChartsInteractionYAxis, @@ -124,7 +120,8 @@ export function useAxisTooltip(): null | UseAxisTooltipReturnValue { const axisFormattedValue = axisFormatter(axisValue, { location: 'tooltip' }); return { - identifier: axis, + axisDirection: xAxisHasData ? 'x' : 'y', + dataIndex, seriesItems: relevantSeries, axisValue, axisFormattedValue, diff --git a/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx b/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx index 96023ae1b272..1e487a863e91 100644 --- a/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx @@ -25,8 +25,9 @@ export interface UseItemTooltipReturnValue { } export function useItemTooltip(): null | UseItemTooltipReturnValue { - const stroe = useStore(); - const item = useSelector(stroe, selectorChartsInteractionItem); + const store = useStore(); + const item = useSelector(store, selectorChartsInteractionItem); + const series = useSeries(); const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); diff --git a/packages/x-charts/src/ChartsTooltip/utils.tsx b/packages/x-charts/src/ChartsTooltip/utils.tsx index 6964b5ef3e45..3f43b2e17f2c 100644 --- a/packages/x-charts/src/ChartsTooltip/utils.tsx +++ b/packages/x-charts/src/ChartsTooltip/utils.tsx @@ -1,6 +1,4 @@ import * as React from 'react'; -import { AxisInteractionData, ItemInteractionData } from '../internals/plugins/models'; -import { ChartSeriesType } from '../models/seriesType/config'; import { useSvgRef } from '../hooks'; type MousePosition = { @@ -99,20 +97,6 @@ export function usePointerType(): null | PointerType { export type TriggerOptions = 'item' | 'axis' | 'none'; -export function getTooltipHasData( - trigger: TriggerOptions, - displayedData: null | AxisInteractionData | ItemInteractionData, -): boolean { - if (trigger === 'item') { - return displayedData !== null; - } - - const hasAxisXData = (displayedData as AxisInteractionData).x !== null; - const hasAxisYData = (displayedData as AxisInteractionData).y !== null; - - return hasAxisXData || hasAxisYData; -} - export function utcFormatter(v: string | number | Date): string { if (v instanceof Date) { return v.toUTCString(); diff --git a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx index f0169fb95025..29d830331757 100644 --- a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx +++ b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx @@ -34,6 +34,7 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { const svgRef = useSvgRef(); const drawingArea = useDrawingArea(); const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); + const store = useStore(); const { series, seriesOrder } = useScatterSeries() ?? {}; diff --git a/packages/x-charts/src/LineChart/CircleMarkElement.tsx b/packages/x-charts/src/LineChart/CircleMarkElement.tsx index ddc1608cc44c..75caf10d3f58 100644 --- a/packages/x-charts/src/LineChart/CircleMarkElement.tsx +++ b/packages/x-charts/src/LineChart/CircleMarkElement.tsx @@ -68,6 +68,7 @@ function CircleMarkElement(props: CircleMarkElementProps) { const { isFaded, isHighlighted } = useItemHighlighted({ seriesId: id, }); + const store = useStore(); const xAxisIdentifier = useSelector(store, selectorChartsInteractionXAxis); diff --git a/packages/x-charts/src/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index f9e74e7043dc..6b36690dca8c 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -9,12 +9,8 @@ import { ChartContainer, ChartContainerProps } from '../ChartContainer'; import { MarkPlot, MarkPlotProps, MarkPlotSlotProps, MarkPlotSlots } from './MarkPlot'; import { ChartsAxis, ChartsAxisProps } from '../ChartsAxis/ChartsAxis'; import { LineSeriesType } from '../models/seriesType/line'; -import { - ChartsTooltip, - ChartsTooltipProps, - ChartsTooltipSlotProps, - ChartsTooltipSlots, -} from '../ChartsTooltip'; +import { ChartsTooltip } from '../ChartsTooltip'; +import { ChartsTooltipSlots, ChartsTooltipSlotProps } from '../ChartsTooltip/ChartTooltip.types'; import { ChartsLegend, ChartsLegendSlotProps, ChartsLegendSlots } from '../ChartsLegend'; import { ChartsAxisHighlight, ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsClipPath } from '../ChartsClipPath'; @@ -44,8 +40,8 @@ export interface LineChartSlots MarkPlotSlots, LineHighlightPlotSlots, ChartsLegendSlots, - ChartsTooltipSlots<'line'>, - ChartsOverlaySlots {} + ChartsOverlaySlots, + ChartsTooltipSlots {} export interface LineChartSlotProps extends ChartsAxisSlotProps, AreaPlotSlotProps, @@ -53,8 +49,8 @@ export interface LineChartSlotProps MarkPlotSlotProps, LineHighlightPlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps<'line'>, - ChartsOverlaySlotProps {} + ChartsOverlaySlotProps, + ChartsTooltipSlotProps {} export interface LineChartProps extends Omit, @@ -66,12 +62,6 @@ export interface LineChartProps * An array of [[LineSeriesType]] objects. */ series: MakeOptional[]; - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip?: ChartsTooltipProps<'line'>; /** * Option to display a cartesian grid in the background. */ @@ -152,10 +142,11 @@ const LineChart = React.forwardRef(function LineChart( axisHighlightProps, lineHighlightPlotProps, legendProps, - tooltipProps, children, } = useLineChartProps(props); + const Tooltip = props.slots?.tooltip ?? ChartsTooltip; + return ( {props.onAxisClick && } @@ -173,7 +164,7 @@ const LineChart = React.forwardRef(function LineChart( {!props.hideLegend && } - {!props.loading && } + {!props.loading && } {children} @@ -328,19 +319,6 @@ LineChart.propTypes = { PropTypes.object, ]), title: PropTypes.string, - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * Indicate which axis to display the top of the charts. * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. diff --git a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx index 7c6e30437bd0..bd37e6e2ec4b 100644 --- a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx +++ b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { SlotComponentPropsFromProps } from '@mui/x-internals/types'; +import { useStore } from '../internals/useStore'; +import { useSelector } from '../internals/useSelector'; import { useCartesianContext } from '../context/CartesianProvider'; import { LineHighlightElement, LineHighlightElementProps } from './LineHighlightElement'; import { getValueToPositionMapper } from '../hooks/useScale'; @@ -10,8 +12,6 @@ import getColor from './getColor'; import { useLineSeries } from '../hooks/useSeries'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { selectorChartsInteractionXAxis } from '../context/InteractionSelectors'; -import { useSelector } from '../internals/useSelector'; -import { useStore } from '../internals/useStore'; export interface LineHighlightPlotSlots { lineHighlight?: React.JSXElementConstructor; @@ -50,6 +50,7 @@ function LineHighlightPlot(props: LineHighlightPlotProps) { const seriesData = useLineSeries(); const axisData = useCartesianContext(); const drawingArea = useDrawingArea(); + const store = useStore(); const xAxisIdentifier = useSelector(store, selectorChartsInteractionXAxis); diff --git a/packages/x-charts/src/LineChart/useLineChartProps.ts b/packages/x-charts/src/LineChart/useLineChartProps.ts index 294ae7878ca7..05cef6fc627b 100644 --- a/packages/x-charts/src/LineChart/useLineChartProps.ts +++ b/packages/x-charts/src/LineChart/useLineChartProps.ts @@ -7,7 +7,6 @@ import { ChartsGridProps } from '../ChartsGrid'; import { ChartsLegendProps } from '../ChartsLegend'; import { ChartsOnAxisClickHandlerProps } from '../ChartsOnAxisClickHandler'; import { ChartsOverlayProps } from '../ChartsOverlay'; -import { ChartsTooltipProps } from '../ChartsTooltip'; import { DEFAULT_X_AXIS_KEY } from '../constants'; import { ChartContainerProps } from '../ChartContainer'; import { AreaPlotProps } from './AreaPlot'; @@ -34,7 +33,6 @@ export const useLineChartProps = (props: LineChartProps) => { colors, dataset, sx, - tooltip, onAxisClick, onAreaClick, onLineClick, @@ -89,7 +87,7 @@ export const useLineChartProps = (props: LineChartProps) => { highlightedItem, onHighlightChange, disableAxisListener: - tooltip?.trigger !== 'axis' && + slotProps?.tooltip?.trigger !== 'axis' && axisHighlight?.x === 'none' && axisHighlight?.y === 'none' && !onAxisClick, @@ -164,12 +162,6 @@ export const useLineChartProps = (props: LineChartProps) => { slotProps, }; - const tooltipProps: ChartsTooltipProps<'line'> = { - ...tooltip, - slots, - slotProps, - }; - return { chartContainerProps, axisClickHandlerProps, @@ -184,7 +176,6 @@ export const useLineChartProps = (props: LineChartProps) => { axisHighlightProps, lineHighlightPlotProps, legendProps, - tooltipProps, children, }; }; diff --git a/packages/x-charts/src/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 49e1ccd3816d..77bd0de044ae 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -6,12 +6,8 @@ import { useThemeProps } from '@mui/material/styles'; import { MakeOptional } from '@mui/x-internals/types'; import { ChartContainer, ChartContainerProps } from '../ChartContainer'; import { PieSeriesType } from '../models/seriesType'; -import { - ChartsTooltip, - ChartsTooltipProps, - ChartsTooltipSlotProps, - ChartsTooltipSlots, -} from '../ChartsTooltip'; +import { ChartsTooltip } from '../ChartsTooltip'; +import { ChartsTooltipSlots, ChartsTooltipSlotProps } from '../ChartsTooltip/ChartTooltip.types'; import { ChartsLegend, ChartsLegendSlotProps, ChartsLegendSlots } from '../ChartsLegend'; import { PiePlot, PiePlotProps, PiePlotSlotProps, PiePlotSlots } from './PiePlot'; import { PieValueType } from '../models/seriesType/pie'; @@ -25,14 +21,14 @@ import { export interface PieChartSlots extends PiePlotSlots, ChartsLegendSlots, - ChartsTooltipSlots<'pie'>, - ChartsOverlaySlots {} + ChartsOverlaySlots, + ChartsTooltipSlots {} export interface PieChartSlotProps extends PiePlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps<'pie'>, - ChartsOverlaySlotProps {} + ChartsOverlaySlotProps, + ChartsTooltipSlotProps {} export interface PieChartProps extends Omit, @@ -43,12 +39,6 @@ export interface PieChartProps * An array of [[PieSeriesType]] objects. */ series: MakeOptional>, 'type'>[]; - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip?: ChartsTooltipProps<'pie'>; /** * If `true`, the legend is not rendered. */ @@ -96,7 +86,6 @@ const PieChart = React.forwardRef(function PieChart( margin: marginProps, colors, sx, - tooltip = { trigger: 'item' }, skipAnimation, hideLegend, children, @@ -113,6 +102,7 @@ const PieChart = React.forwardRef(function PieChart( const margin = { ...(isRtl ? defaultRTLMargin : defaultMargin), ...marginProps }; + const Tooltip = slots?.tooltip ?? ChartsTooltip; return ( )} - {!loading && } + {!loading && } {children} ); @@ -236,19 +226,6 @@ PieChart.propTypes = { PropTypes.object, ]), title: PropTypes.string, - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * The width of the chart in px. If not defined, it takes the width of the parent element. */ diff --git a/packages/x-charts/src/ScatterChart/Scatter.tsx b/packages/x-charts/src/ScatterChart/Scatter.tsx index b6a95e703587..515efa382cf7 100644 --- a/packages/x-charts/src/ScatterChart/Scatter.tsx +++ b/packages/x-charts/src/ScatterChart/Scatter.tsx @@ -8,12 +8,12 @@ import { } from '../models/seriesType/scatter'; import { getValueToPositionMapper } from '../hooks/useScale'; import { useInteractionItemProps } from '../hooks/useInteractionItemProps'; +import { useStore } from '../internals/useStore'; +import { useSelector } from '../internals/useSelector'; import { D3Scale } from '../models/axis'; import { useHighlighted } from '../context'; import { useDrawingArea } from '../hooks/useDrawingArea'; import { selectorChartsInteractionIsVoronoiEnabled } from '../context/InteractionSelectors'; -import { useSelector } from '../internals/useSelector'; -import { useStore } from '../internals/useStore'; export interface ScatterProps { series: DefaultizedScatterSeriesType; diff --git a/packages/x-charts/src/ScatterChart/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 686bda969083..1ad1242fc8d8 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -12,12 +12,8 @@ import { import { ChartContainer, ChartContainerProps } from '../ChartContainer'; import { ChartsAxis, ChartsAxisProps } from '../ChartsAxis'; import { ScatterSeriesType } from '../models/seriesType/scatter'; -import { - ChartsTooltip, - ChartsTooltipProps, - ChartsTooltipSlotProps, - ChartsTooltipSlots, -} from '../ChartsTooltip'; +import { ChartsTooltip } from '../ChartsTooltip'; +import { ChartsTooltipSlots, ChartsTooltipSlotProps } from '../ChartsTooltip/ChartTooltip.types'; import { ChartsLegend, ChartsLegendSlotProps, ChartsLegendSlots } from '../ChartsLegend'; import { ChartsOverlay, @@ -39,14 +35,14 @@ export interface ScatterChartSlots extends ChartsAxisSlots, ScatterPlotSlots, ChartsLegendSlots, - ChartsTooltipSlots<'scatter'>, - ChartsOverlaySlots {} + ChartsOverlaySlots, + ChartsTooltipSlots {} export interface ScatterChartSlotProps extends ChartsAxisSlotProps, ScatterPlotSlotProps, ChartsLegendSlotProps, - ChartsTooltipSlotProps<'scatter'>, - ChartsOverlaySlotProps {} + ChartsOverlaySlotProps, + ChartsTooltipSlotProps {} export interface ScatterChartProps extends Omit, @@ -59,12 +55,6 @@ export interface ScatterChartProps * An array of [[ScatterSeriesType]] objects. */ series: MakeOptional[]; - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip?: ChartsTooltipProps<'scatter'>; /** * The configuration of axes highlight. * @see See {@link https://mui.com/x/react-charts/highlighting/ highlighting docs} for more details. @@ -127,9 +117,11 @@ const ScatterChart = React.forwardRef(function ScatterChart( overlayProps, legendProps, axisHighlightProps, - tooltipProps, children, } = useScatterChartProps(props); + + const Tooltip = props.slots?.tooltip ?? ChartsTooltip; + return ( @@ -143,7 +135,7 @@ const ScatterChart = React.forwardRef(function ScatterChart( {!props.hideLegend && } - {!props.loading && } + {!props.loading && } {children} @@ -282,19 +274,6 @@ ScatterChart.propTypes = { PropTypes.object, ]), title: PropTypes.string, - /** - * The configuration of the tooltip. - * @see See {@link https://mui.com/x/react-charts/tooltip/ tooltip docs} for more details. - * @default { trigger: 'item' } - */ - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * Indicate which axis to display the top of the charts. * Can be a string (the id of the axis) or an object `ChartsXAxisProps`. diff --git a/packages/x-charts/src/ScatterChart/useScatterChartProps.ts b/packages/x-charts/src/ScatterChart/useScatterChartProps.ts index dbeb259b5a06..0399f0543a96 100644 --- a/packages/x-charts/src/ScatterChart/useScatterChartProps.ts +++ b/packages/x-charts/src/ScatterChart/useScatterChartProps.ts @@ -4,7 +4,6 @@ import { ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { ChartsGridProps } from '../ChartsGrid'; import { ChartsLegendProps } from '../ChartsLegend'; import { ChartsOverlayProps } from '../ChartsOverlay'; -import { ChartsTooltipProps } from '../ChartsTooltip'; import type { ChartsVoronoiHandlerProps } from '../ChartsVoronoiHandler'; import { ChartContainerProps } from '../ChartContainer'; import { ZAxisContextProviderProps } from '../context'; @@ -24,7 +23,6 @@ export const useScatterChartProps = (props: ScatterChartProps) => { yAxis, zAxis, series, - tooltip, axisHighlight, voronoiMaxRadius, disableVoronoi, @@ -108,13 +106,6 @@ export const useScatterChartProps = (props: ScatterChartProps) => { ...axisHighlight, }; - const tooltipProps: ChartsTooltipProps<'scatter'> = { - trigger: 'item' as const, - ...tooltip, - slots, - slotProps, - }; - return { chartContainerProps, zAxisProps, @@ -125,7 +116,6 @@ export const useScatterChartProps = (props: ScatterChartProps) => { overlayProps, legendProps, axisHighlightProps, - tooltipProps, children, }; }; diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index ed53fbff42e3..0499352f5132 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -6,12 +6,8 @@ import { BarPlot } from '../BarChart'; import { LinePlot, AreaPlot, LineHighlightPlot } from '../LineChart'; import { ChartContainer, ChartContainerProps } from '../ChartContainer'; import { DEFAULT_X_AXIS_KEY } from '../constants'; -import { - ChartsTooltip, - ChartsTooltipProps, - ChartsTooltipSlotProps, - ChartsTooltipSlots, -} from '../ChartsTooltip'; +import { ChartsTooltip } from '../ChartsTooltip'; +import { ChartsTooltipSlots, ChartsTooltipSlotProps } from '../ChartsTooltip/ChartTooltip.types'; import { ChartsAxisHighlight, ChartsAxisHighlightProps } from '../ChartsAxisHighlight'; import { AxisConfig, ChartsXAxisProps, ChartsYAxisProps, ScaleName } from '../models/axis'; import { LineSeriesType, BarSeriesType } from '../models/seriesType'; @@ -28,14 +24,14 @@ export interface SparkLineChartSlots MarkPlotSlots, LineHighlightPlotSlots, Omit, - ChartsTooltipSlots<'line' | 'bar'> {} + ChartsTooltipSlots {} export interface SparkLineChartSlotProps extends AreaPlotSlotProps, LinePlotSlotProps, MarkPlotSlotProps, LineHighlightPlotSlotProps, BarPlotSlotProps, - ChartsTooltipSlotProps<'line' | 'bar'> {} + ChartsTooltipSlotProps {} export interface SparkLineChartProps extends Omit { @@ -49,7 +45,6 @@ export interface SparkLineChartProps * Notice it is a single [[AxisConfig]] object, not an array of configuration. */ yAxis?: MakeOptional, 'id'>; - tooltip?: ChartsTooltipProps<'line' | 'bar'>; axisHighlight?: ChartsAxisHighlightProps; /** * Type of plot used. @@ -142,7 +137,6 @@ const SparkLineChart = React.forwardRef(function SparkLineChart( colors, sx, showTooltip, - tooltip, showHighlight, axisHighlight: inAxisHighlight, children, @@ -164,6 +158,8 @@ const SparkLineChart = React.forwardRef(function SparkLineChart( ...inAxisHighlight, }; + const Tooltip = props.slots?.tooltip ?? ChartsTooltip; + return ( - {showTooltip && } + {showTooltip && } {children} @@ -350,14 +346,6 @@ SparkLineChart.propTypes = { PropTypes.object, ]), title: PropTypes.string, - tooltip: PropTypes.shape({ - axisContent: PropTypes.elementType, - classes: PropTypes.object, - itemContent: PropTypes.elementType, - slotProps: PropTypes.object, - slots: PropTypes.object, - trigger: PropTypes.oneOf(['axis', 'item', 'none']), - }), /** * Formatter used by the tooltip. * @param {number} value The value to format. diff --git a/packages/x-charts/src/hooks/useInteractionItemProps.ts b/packages/x-charts/src/hooks/useInteractionItemProps.ts index 7474425fe650..7a99e65b8f3d 100644 --- a/packages/x-charts/src/hooks/useInteractionItemProps.ts +++ b/packages/x-charts/src/hooks/useInteractionItemProps.ts @@ -6,6 +6,7 @@ import { useStore } from '../internals/useStore'; export const useInteractionItemProps = (skip?: boolean) => { const store = useStore(); + const { setHighlighted, clearHighlighted } = useHighlighted(); if (skip) { diff --git a/packages/x-charts/src/internals/plugins/utils/ChartsStore.ts b/packages/x-charts/src/internals/plugins/utils/ChartsStore.ts new file mode 100644 index 000000000000..04278c928481 --- /dev/null +++ b/packages/x-charts/src/internals/plugins/utils/ChartsStore.ts @@ -0,0 +1,35 @@ +import type { ChartState } from '../models'; // For now this is fixed. Will need to support generic if we add plugins + +type Listener = (value: T) => void; + +export type StoreUpdater = (prevState: ChartState) => ChartState; + +export class ChartsStore { + public value: ChartState; + + private listeners: Set>; + + constructor(value: ChartState) { + this.value = value; + this.listeners = new Set(); + } + + public subscribe = (fn: Listener) => { + this.listeners.add(fn); + return () => { + this.listeners.delete(fn); + }; + }; + + public getSnapshot = () => { + return this.value; + }; + + public update = (updater: StoreUpdater) => { + const newState = updater(this.value); + if (newState !== this.value) { + this.value = newState; + this.listeners.forEach((l) => l(newState)); + } + }; +} diff --git a/packages/x-charts/src/internals/useStore.ts b/packages/x-charts/src/internals/useStore.ts index 17e6d3b6316f..f906789004aa 100644 --- a/packages/x-charts/src/internals/useStore.ts +++ b/packages/x-charts/src/internals/useStore.ts @@ -6,7 +6,6 @@ export function useStore(skipError?: boolean): ChartStore { const charts = React.useContext(ChartsContext); if (skipError) { - // TODO: Remove once store is used by all charts. // TODO: Remove once store is used by all charts. // This line is only for `useAxisEvents` which is in the surface of the Gauge. // But the Gauge don't have store yet because it does not need the interaction provider. diff --git a/packages/x-charts/src/themeAugmentation/props.d.ts b/packages/x-charts/src/themeAugmentation/props.d.ts index 0fe35a41d87d..ce49072968fb 100644 --- a/packages/x-charts/src/themeAugmentation/props.d.ts +++ b/packages/x-charts/src/themeAugmentation/props.d.ts @@ -8,14 +8,13 @@ import { LineChartProps } from '../LineChart/LineChart'; import { ScatterChartProps } from '../ScatterChart/ScatterChart'; import { PieChartProps } from '../PieChart/PieChart'; import { ChartsXAxisProps, ChartsYAxisProps } from '../models/axis'; -import { ChartSeriesType } from '../models/seriesType/config'; export interface ChartsComponentsPropsList { MuiChartsXAxis: ChartsXAxisProps; MuiChartsYAxis: ChartsYAxisProps; MuiChartsGrid: ChartsGridProps; MuiChartsLegend: ChartsLegendProps; - MuiChartsTooltip: ChartsTooltipProps; + MuiChartsTooltip: ChartsTooltipProps; MuiChartsSurface: ChartsSurfaceProps; // BarChart components diff --git a/scripts/x-charts-pro.exports.json b/scripts/x-charts-pro.exports.json index faae92e438c1..2404d9305ef6 100644 --- a/scripts/x-charts-pro.exports.json +++ b/scripts/x-charts-pro.exports.json @@ -60,7 +60,6 @@ { "name": "ChartsAxis", "kind": "Function" }, { "name": "ChartsAxisClasses", "kind": "Interface" }, { "name": "ChartsAxisClassKey", "kind": "TypeAlias" }, - { "name": "ChartsAxisContentProps", "kind": "TypeAlias" }, { "name": "ChartsAxisData", "kind": "TypeAlias" }, { "name": "ChartsAxisHighlight", "kind": "Function" }, { "name": "chartsAxisHighlightClasses", "kind": "Variable" }, @@ -71,6 +70,7 @@ { "name": "ChartsAxisHighlightType", "kind": "TypeAlias" }, { "name": "ChartsAxisProps", "kind": "Interface" }, { "name": "ChartsAxisTooltipContent", "kind": "Function" }, + { "name": "ChartsAxisTooltipContentProps", "kind": "Interface" }, { "name": "ChartsClipPath", "kind": "Function" }, { "name": "ChartsClipPathProps", "kind": "TypeAlias" }, { "name": "ChartsColorPalette", "kind": "TypeAlias" }, @@ -80,7 +80,6 @@ { "name": "ChartsGridClasses", "kind": "Interface" }, { "name": "ChartsGridClassKey", "kind": "TypeAlias" }, { "name": "ChartsGridProps", "kind": "Interface" }, - { "name": "ChartsItemContentProps", "kind": "Interface" }, { "name": "ChartsItemTooltipContent", "kind": "Function" }, { "name": "ChartsItemTooltipContentProps", "kind": "Interface" }, { "name": "ChartsLegend", "kind": "Function" }, @@ -106,12 +105,12 @@ { "name": "chartsTooltipClasses", "kind": "Variable" }, { "name": "ChartsTooltipClasses", "kind": "Interface" }, { "name": "ChartsTooltipClassKey", "kind": "TypeAlias" }, + { "name": "ChartsTooltipContainer", "kind": "Function" }, + { "name": "ChartsTooltipContainerProps", "kind": "Interface" }, { "name": "ChartsTooltipMark", "kind": "Variable" }, { "name": "ChartsTooltipPaper", "kind": "Variable" }, { "name": "ChartsTooltipProps", "kind": "Interface" }, { "name": "ChartsTooltipRow", "kind": "Variable" }, - { "name": "ChartsTooltipSlotProps", "kind": "Interface" }, - { "name": "ChartsTooltipSlots", "kind": "Interface" }, { "name": "ChartsTooltipTable", "kind": "Variable" }, { "name": "ChartsVoronoiHandler", "kind": "Function" }, { "name": "ChartsVoronoiHandlerProps", "kind": "TypeAlias" }, @@ -130,10 +129,7 @@ { "name": "DEFAULT_MARGINS", "kind": "Variable" }, { "name": "DEFAULT_X_AXIS_KEY", "kind": "Variable" }, { "name": "DEFAULT_Y_AXIS_KEY", "kind": "Variable" }, - { "name": "DefaultChartsAxisTooltipContent", "kind": "Function" }, - { "name": "DefaultChartsItemTooltipContent", "kind": "Function" }, { "name": "DefaultChartsLegend", "kind": "Function" }, - { "name": "DefaultHeatmapTooltip", "kind": "Function" }, { "name": "DefaultizedBarSeriesType", "kind": "Interface" }, { "name": "DefaultizedCartesianSeriesType", "kind": "TypeAlias" }, { "name": "DefaultizedLineSeriesType", "kind": "Interface" }, @@ -178,6 +174,8 @@ { "name": "HeatmapClasses", "kind": "Interface" }, { "name": "HeatmapClassKey", "kind": "TypeAlias" }, { "name": "HeatmapPlot", "kind": "Function" }, + { "name": "HeatmapTooltip", "kind": "Function" }, + { "name": "HeatmapTooltipProps", "kind": "Interface" }, { "name": "HighlightedContext", "kind": "Variable" }, { "name": "HighlightedProvider", "kind": "Function" }, { "name": "HighlightedProviderProps", "kind": "TypeAlias" }, @@ -264,7 +262,6 @@ { "name": "PiePlotSlots", "kind": "Interface" }, { "name": "PieSeriesType", "kind": "Interface" }, { "name": "PieValueType", "kind": "TypeAlias" }, - { "name": "PopperProps", "kind": "TypeAlias" }, { "name": "PropsFromSlot", "kind": "TypeAlias" }, { "name": "referenceLineClasses", "kind": "Variable" }, { "name": "ScaleName", "kind": "TypeAlias" }, diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index eb38124c022f..4081f5bdcb11 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -58,7 +58,6 @@ { "name": "ChartsAxis", "kind": "Function" }, { "name": "ChartsAxisClasses", "kind": "Interface" }, { "name": "ChartsAxisClassKey", "kind": "TypeAlias" }, - { "name": "ChartsAxisContentProps", "kind": "TypeAlias" }, { "name": "ChartsAxisData", "kind": "TypeAlias" }, { "name": "ChartsAxisHighlight", "kind": "Function" }, { "name": "chartsAxisHighlightClasses", "kind": "Variable" }, @@ -69,6 +68,7 @@ { "name": "ChartsAxisHighlightType", "kind": "TypeAlias" }, { "name": "ChartsAxisProps", "kind": "Interface" }, { "name": "ChartsAxisTooltipContent", "kind": "Function" }, + { "name": "ChartsAxisTooltipContentProps", "kind": "Interface" }, { "name": "ChartsClipPath", "kind": "Function" }, { "name": "ChartsClipPathProps", "kind": "TypeAlias" }, { "name": "ChartsColorPalette", "kind": "TypeAlias" }, @@ -78,7 +78,6 @@ { "name": "ChartsGridClasses", "kind": "Interface" }, { "name": "ChartsGridClassKey", "kind": "TypeAlias" }, { "name": "ChartsGridProps", "kind": "Interface" }, - { "name": "ChartsItemContentProps", "kind": "Interface" }, { "name": "ChartsItemTooltipContent", "kind": "Function" }, { "name": "ChartsItemTooltipContentProps", "kind": "Interface" }, { "name": "ChartsLegend", "kind": "Function" }, @@ -104,12 +103,12 @@ { "name": "chartsTooltipClasses", "kind": "Variable" }, { "name": "ChartsTooltipClasses", "kind": "Interface" }, { "name": "ChartsTooltipClassKey", "kind": "TypeAlias" }, + { "name": "ChartsTooltipContainer", "kind": "Function" }, + { "name": "ChartsTooltipContainerProps", "kind": "Interface" }, { "name": "ChartsTooltipMark", "kind": "Variable" }, { "name": "ChartsTooltipPaper", "kind": "Variable" }, { "name": "ChartsTooltipProps", "kind": "Interface" }, { "name": "ChartsTooltipRow", "kind": "Variable" }, - { "name": "ChartsTooltipSlotProps", "kind": "Interface" }, - { "name": "ChartsTooltipSlots", "kind": "Interface" }, { "name": "ChartsTooltipTable", "kind": "Variable" }, { "name": "ChartsVoronoiHandler", "kind": "Function" }, { "name": "ChartsVoronoiHandlerProps", "kind": "TypeAlias" }, @@ -128,8 +127,6 @@ { "name": "DEFAULT_MARGINS", "kind": "Variable" }, { "name": "DEFAULT_X_AXIS_KEY", "kind": "Variable" }, { "name": "DEFAULT_Y_AXIS_KEY", "kind": "Variable" }, - { "name": "DefaultChartsAxisTooltipContent", "kind": "Function" }, - { "name": "DefaultChartsItemTooltipContent", "kind": "Function" }, { "name": "DefaultChartsLegend", "kind": "Function" }, { "name": "DefaultizedBarSeriesType", "kind": "Interface" }, { "name": "DefaultizedCartesianSeriesType", "kind": "TypeAlias" }, @@ -253,7 +250,6 @@ { "name": "PiePlotSlots", "kind": "Interface" }, { "name": "PieSeriesType", "kind": "Interface" }, { "name": "PieValueType", "kind": "TypeAlias" }, - { "name": "PopperProps", "kind": "TypeAlias" }, { "name": "PropsFromSlot", "kind": "TypeAlias" }, { "name": "referenceLineClasses", "kind": "Variable" }, { "name": "ScaleName", "kind": "TypeAlias" },