From d17274585a14f9e1ec2ef94f6229a9bdfdad6502 Mon Sep 17 00:00:00 2001 From: Jose C Quintas Jr Date: Mon, 18 Nov 2024 13:22:44 +0100 Subject: [PATCH 1/7] [charts] Decouple `ChartDataProvider` and `ChartsSurface` (#15375) --- docs/pages/x/api/charts/charts-surface.json | 6 +- .../charts/charts-surface/charts-surface.json | 4 +- .../src/BarChartPro/BarChartPro.tsx | 6 -- .../ChartContainerPro/ChartContainerPro.tsx | 19 ++-- .../useChartContainerProProps.ts | 10 +- packages/x-charts-pro/src/Heatmap/Heatmap.tsx | 6 -- .../src/LineChartPro/LineChartPro.tsx | 6 -- .../src/ScatterChartPro/ScatterChartPro.tsx | 6 -- .../ChartDataProviderPro.tsx | 28 ++---- .../useChartDataProviderProProps.ts | 13 +-- packages/x-charts/src/BarChart/BarChart.tsx | 6 -- .../src/ChartContainer/ChartContainer.tsx | 38 ++------ .../src/ChartContainer/ResizableContainer.tsx | 38 +++++++- .../ChartContainer/useChartContainerProps.ts | 47 ++++------ .../src/ChartsSurface/ChartsSurface.test.tsx | 13 ++- .../src/ChartsSurface/ChartsSurface.tsx | 75 +++++---------- packages/x-charts/src/Gauge/Gauge.tsx | 6 -- .../x-charts/src/Gauge/GaugeContainer.tsx | 91 +++++++++---------- packages/x-charts/src/LineChart/LineChart.tsx | 6 -- packages/x-charts/src/PieChart/PieChart.tsx | 6 -- .../src/ScatterChart/ScatterChart.tsx | 6 -- .../src/SparkLineChart/SparkLineChart.tsx | 6 -- .../ChartDataProvider.test.tsx | 4 + .../ChartDataProvider/ChartDataProvider.tsx | 78 ++++++---------- .../useChartDataProviderProps.ts | 34 ++----- .../DrawingAreaProvider/DrawingArea.types.ts | 2 +- .../DrawingAreaProvider.tsx | 4 +- .../src/context/SizeProvider/Size.types.ts | 42 +++++++++ .../src/context/SizeProvider/SizeContext.ts | 18 ++++ .../src/context/SizeProvider/SizeProvider.tsx | 32 +++++++ .../src/context/SizeProvider/index.ts | 4 + .../useChartContainerDimensions.ts | 12 ++- .../src/context/SizeProvider/useSize.ts | 12 +++ .../context/SvgRefProvider/SvgRef.types.ts | 1 - .../context/SvgRefProvider/SvgRefProvider.tsx | 4 +- packages/x-charts/src/context/index.ts | 2 + .../x-charts/src/hooks/useSvgRef.test.tsx | 4 +- packages/x-charts/src/internals/index.ts | 2 +- scripts/x-charts-pro.exports.json | 2 + scripts/x-charts.exports.json | 2 + 40 files changed, 339 insertions(+), 362 deletions(-) create mode 100644 packages/x-charts/src/context/SizeProvider/Size.types.ts create mode 100644 packages/x-charts/src/context/SizeProvider/SizeContext.ts create mode 100644 packages/x-charts/src/context/SizeProvider/SizeProvider.tsx create mode 100644 packages/x-charts/src/context/SizeProvider/index.ts rename packages/x-charts/src/{ChartContainer => context/SizeProvider}/useChartContainerDimensions.ts (93%) create mode 100644 packages/x-charts/src/context/SizeProvider/useSize.ts diff --git a/docs/pages/x/api/charts/charts-surface.json b/docs/pages/x/api/charts/charts-surface.json index 3d1687d649b3..ae4ebc5a067c 100644 --- a/docs/pages/x/api/charts/charts-surface.json +++ b/docs/pages/x/api/charts/charts-surface.json @@ -1,9 +1,5 @@ { - "props": { - "height": { "type": { "name": "number" }, "required": true }, - "width": { "type": { "name": "number" }, "required": true }, - "disableAxisListener": { "type": { "name": "bool" }, "default": "false" } - }, + "props": { "disableAxisListener": { "type": { "name": "bool" }, "default": "false" } }, "name": "ChartsSurface", "imports": [ "import { ChartsSurface } from '@mui/x-charts/ChartsSurface';", diff --git a/docs/translations/api-docs/charts/charts-surface/charts-surface.json b/docs/translations/api-docs/charts/charts-surface/charts-surface.json index a82c8a537f11..40b01b75badb 100644 --- a/docs/translations/api-docs/charts/charts-surface/charts-surface.json +++ b/docs/translations/api-docs/charts/charts-surface/charts-surface.json @@ -3,9 +3,7 @@ "propDescriptions": { "disableAxisListener": { "description": "If true, the charts will not listen to the mouse move event. It might break interactive features, but will improve performance." - }, - "height": { "description": "The height of the chart in px." }, - "width": { "description": "The width of the chart in px." } + } }, "classDescriptions": {} } diff --git a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx index 2e29e6aa5309..cf06bc9b1cd9 100644 --- a/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx +++ b/packages/x-charts-pro/src/BarChartPro/BarChartPro.tsx @@ -303,12 +303,6 @@ BarChartPro.propTypes = { * @default null */ topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * The width of the chart in px. If not defined, it takes the width of the parent element. */ diff --git a/packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx b/packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx index 4dbbc461d9ee..a007a28485a5 100644 --- a/packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx +++ b/packages/x-charts-pro/src/ChartContainerPro/ChartContainerPro.tsx @@ -5,6 +5,7 @@ import type {} from '../typeOverloads'; import { Watermark } from '@mui/x-license/Watermark'; import { ChartContainerProps } from '@mui/x-charts/ChartContainer'; import { ResizableContainer } from '@mui/x-charts/internals'; +import { ChartsSurface } from '@mui/x-charts'; import { getReleaseInfo } from '../internals/utils/releaseInfo'; import { ChartDataProviderPro } from '../context/ChartDataProviderPro'; import { ZoomProps } from '../context/ZoomProvider'; @@ -18,14 +19,16 @@ const ChartContainerPro = React.forwardRef(function ChartContainerPro( props: ChartContainerProProps, ref: React.Ref, ) { - const { chartDataProviderProProps, resizableChartContainerProps, hasIntrinsicSize } = + const { chartDataProviderProProps, children, resizableContainerProps, chartsSurfaceProps } = useChartContainerProProps(props, ref); return ( - - {hasIntrinsicSize ? : null} - - + + + {children} + + + ); }); @@ -119,12 +122,6 @@ ChartContainerPro.propTypes = { PropTypes.object, ]), title: PropTypes.string, - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * The width of the chart in px. If not defined, it takes the width of the parent element. */ diff --git a/packages/x-charts-pro/src/ChartContainerPro/useChartContainerProProps.ts b/packages/x-charts-pro/src/ChartContainerPro/useChartContainerProProps.ts index f9ffc08e4c88..aac56a291a32 100644 --- a/packages/x-charts-pro/src/ChartContainerPro/useChartContainerProProps.ts +++ b/packages/x-charts-pro/src/ChartContainerPro/useChartContainerProProps.ts @@ -1,5 +1,6 @@ 'use client'; import { useChartContainerProps, UseChartContainerPropsReturnValue } from '@mui/x-charts/internals'; +import * as React from 'react'; import type { ChartDataProviderProProps } from '../context/ChartDataProviderPro'; import type { ChartContainerProProps } from './ChartContainerPro'; @@ -13,7 +14,7 @@ export type UseChartContainerProPropsReturnValue = Omit< export const useChartContainerProProps = ( props: ChartContainerProProps, ref: React.Ref, -) => { +): UseChartContainerProPropsReturnValue => { const { zoom, onZoomChange, ...baseProps } = props; const chartDataProviderProProps: Pick = { @@ -21,7 +22,7 @@ export const useChartContainerProProps = ( onZoomChange, }; - const { chartDataProviderProps, resizableChartContainerProps, hasIntrinsicSize } = + const { chartDataProviderProps, chartsSurfaceProps, resizableContainerProps, children } = useChartContainerProps(baseProps, ref); return { @@ -29,7 +30,8 @@ export const useChartContainerProProps = ( ...chartDataProviderProps, ...chartDataProviderProProps, }, - resizableChartContainerProps, - hasIntrinsicSize, + resizableContainerProps, + chartsSurfaceProps, + children, }; }; diff --git a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx index 1309081c80ae..fa6afbe1c682 100644 --- a/packages/x-charts-pro/src/Heatmap/Heatmap.tsx +++ b/packages/x-charts-pro/src/Heatmap/Heatmap.tsx @@ -341,12 +341,6 @@ Heatmap.propTypes = { * @default null */ topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * The width of the chart in px. If not defined, it takes the width of the parent element. */ diff --git a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx index 45e81701d82f..45b21e15c2eb 100644 --- a/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx +++ b/packages/x-charts-pro/src/LineChartPro/LineChartPro.tsx @@ -375,12 +375,6 @@ LineChartPro.propTypes = { * @default null */ topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * The width of the chart in px. If not defined, it takes the width of the parent element. */ diff --git a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx index 6d7af5278ac6..5e50274d373c 100644 --- a/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx +++ b/packages/x-charts-pro/src/ScatterChartPro/ScatterChartPro.tsx @@ -236,12 +236,6 @@ ScatterChartPro.propTypes = { * @default null */ topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * Defines the maximal distance between a scatter point and the pointer that triggers the interaction. * If `undefined`, the radius is assumed to be infinite. diff --git a/packages/x-charts-pro/src/context/ChartDataProviderPro/ChartDataProviderPro.tsx b/packages/x-charts-pro/src/context/ChartDataProviderPro/ChartDataProviderPro.tsx index 8746fc061af0..91ca02d3f8cd 100644 --- a/packages/x-charts-pro/src/context/ChartDataProviderPro/ChartDataProviderPro.tsx +++ b/packages/x-charts-pro/src/context/ChartDataProviderPro/ChartDataProviderPro.tsx @@ -3,15 +3,14 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { ChartDataProviderProps, - ChartsAxesGradients, DrawingAreaProvider, InteractionProvider, PluginProvider, SeriesProvider, AnimationProvider, SvgRefProvider, + SizeProvider, } from '@mui/x-charts/internals'; -import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; import { HighlightedProvider, ZAxisContextProvider } from '@mui/x-charts/context'; import { useLicenseVerifier } from '@mui/x-license/useLicenseVerifier'; import { getReleaseInfo } from '../../internals/utils/releaseInfo'; @@ -23,10 +22,7 @@ const releaseInfo = getReleaseInfo(); export interface ChartDataProviderProProps extends ChartDataProviderProps, ZoomProps {} -const ChartDataProviderPro = React.forwardRef(function ChartDataProviderPro( - props: ChartDataProviderProProps, - ref: React.Ref, -) { +function ChartDataProviderPro(props: ChartDataProviderProProps) { const { zoomProviderProps, drawingAreaProviderProps, @@ -34,18 +30,17 @@ const ChartDataProviderPro = React.forwardRef(function ChartDataProviderPro( zAxisContextProps, highlightedProviderProps, cartesianProviderProps, - chartsSurfaceProps, + sizeProviderProps, pluginProviderProps, animationProviderProps, - svgRefProviderProps, children, - } = useChartContainerProProps(props, ref); + } = useChartContainerProProps(props); useLicenseVerifier('x-charts-pro', releaseInfo); return ( - - + + @@ -54,10 +49,7 @@ const ChartDataProviderPro = React.forwardRef(function ChartDataProviderPro( - - - {children} - + {children} @@ -66,10 +58,10 @@ const ChartDataProviderPro = React.forwardRef(function ChartDataProviderPro( - - + + ); -}); +} ChartDataProviderPro.propTypes = { // ----------------------------- Warning -------------------------------- diff --git a/packages/x-charts-pro/src/context/ChartDataProviderPro/useChartDataProviderProProps.ts b/packages/x-charts-pro/src/context/ChartDataProviderPro/useChartDataProviderProProps.ts index 27ff5c906ba7..39e6726455b1 100644 --- a/packages/x-charts-pro/src/context/ChartDataProviderPro/useChartDataProviderProProps.ts +++ b/packages/x-charts-pro/src/context/ChartDataProviderPro/useChartDataProviderProProps.ts @@ -3,10 +3,7 @@ import { useChartDataProviderProps } from '@mui/x-charts/internals'; import { ZoomProviderProps } from '../ZoomProvider'; import type { ChartDataProviderProProps } from './ChartDataProviderPro'; -export const useChartContainerProProps = ( - props: ChartDataProviderProProps, - ref: React.Ref, -) => { +export const useChartContainerProProps = (props: ChartDataProviderProProps) => { const { zoom, onZoomChange, ...baseProps } = props; const { @@ -16,13 +13,12 @@ export const useChartContainerProProps = ( cartesianProviderProps, zAxisContextProps, highlightedProviderProps, - chartsSurfaceProps, + sizeProviderProps, pluginProviderProps, animationProviderProps, - svgRefProviderProps, xAxis, yAxis, - } = useChartDataProviderProps(baseProps, ref); + } = useChartDataProviderProps(baseProps); const zoomProviderProps: Omit = { zoom, @@ -40,8 +36,7 @@ export const useChartContainerProProps = ( cartesianProviderProps, zAxisContextProps, highlightedProviderProps, - chartsSurfaceProps, + sizeProviderProps, animationProviderProps, - svgRefProviderProps, }; }; diff --git a/packages/x-charts/src/BarChart/BarChart.tsx b/packages/x-charts/src/BarChart/BarChart.tsx index 9087c3a9c252..9a0fb4abebb2 100644 --- a/packages/x-charts/src/BarChart/BarChart.tsx +++ b/packages/x-charts/src/BarChart/BarChart.tsx @@ -321,12 +321,6 @@ BarChart.propTypes = { * @default null */ topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * 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/ChartContainer/ChartContainer.tsx b/packages/x-charts/src/ChartContainer/ChartContainer.tsx index 54b013ad2235..0f34ea4c88a7 100644 --- a/packages/x-charts/src/ChartContainer/ChartContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ChartContainer.tsx @@ -4,39 +4,23 @@ import PropTypes from 'prop-types'; import { ChartDataProvider, ChartDataProviderProps } from '../context/ChartDataProvider'; import { ResizableContainer } from './ResizableContainer'; import { useChartContainerProps } from './useChartContainerProps'; +import { ChartsSurface, ChartsSurfaceProps } from '../ChartsSurface'; -export interface ChartContainerProps extends Omit { - /** - * The width of the chart in px. If not defined, it takes the width of the parent element. - */ - width?: number; - /** - * The height of the chart in px. If not defined, it takes the height of the parent element. - */ - height?: number; - /** - * The chart will try to wait for the parent container to resolve its size - * before it renders for the first time. - * - * This can be useful in some scenarios where the chart appear to grow after - * the first render, like when used inside a grid. - * - * @default false - */ - resolveSizeBeforeRender?: boolean; -} +export interface ChartContainerProps extends ChartDataProviderProps, ChartsSurfaceProps {} const ChartContainer = React.forwardRef(function ChartContainer( props: ChartContainerProps, ref: React.Ref, ) { - const { hasIntrinsicSize, chartDataProviderProps, resizableChartContainerProps } = + const { chartDataProviderProps, children, resizableContainerProps, chartsSurfaceProps } = useChartContainerProps(props, ref); return ( - - {hasIntrinsicSize ? : null} - + + + {children} + + ); }); @@ -124,12 +108,6 @@ ChartContainer.propTypes = { PropTypes.object, ]), title: PropTypes.string, - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * 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/ChartContainer/ResizableContainer.tsx b/packages/x-charts/src/ChartContainer/ResizableContainer.tsx index 30c9099a5caf..aacc203af003 100644 --- a/packages/x-charts/src/ChartContainer/ResizableContainer.tsx +++ b/packages/x-charts/src/ChartContainer/ResizableContainer.tsx @@ -1,15 +1,18 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; import { styled } from '@mui/material/styles'; -import type { ChartContainerProps } from './ChartContainer'; +import { useSize } from '../context/SizeProvider'; +import type { SizeContextState } from '../context/SizeProvider'; /** * Wrapping div that take the shape of its parent. * * @ignore - do not document. */ -export const ResizableContainer = styled('div', { +export const ResizableContainerRoot = styled('div', { name: 'MuiResponsiveChart', slot: 'Container', -})<{ ownerState: Pick }>(({ ownerState }) => ({ +})<{ ownerState: Partial> }>(({ ownerState }) => ({ width: ownerState.width ?? '100%', height: ownerState.height ?? '100%', display: 'flex', @@ -24,3 +27,32 @@ export const ResizableContainer = styled('div', { height: '100%', }, })); + +/** + * Wrapping div that take the shape of its parent. + * + * @ignore - do not document. + */ +function ResizableContainer(props: { children: React.ReactNode }) { + const { inHeight, inWidth, hasIntrinsicSize, containerRef } = useSize(); + + return ( + + {hasIntrinsicSize && props.children} + + ); +} + +ResizableContainer.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + children: PropTypes.node, +} as any; + +export { ResizableContainer }; diff --git a/packages/x-charts/src/ChartContainer/useChartContainerProps.ts b/packages/x-charts/src/ChartContainer/useChartContainerProps.ts index 62930f3985ee..8fa2a647f20d 100644 --- a/packages/x-charts/src/ChartContainer/useChartContainerProps.ts +++ b/packages/x-charts/src/ChartContainer/useChartContainerProps.ts @@ -1,15 +1,14 @@ 'use client'; +import * as React from 'react'; +import { ChartsSurfaceProps } from '../ChartsSurface'; import { ChartDataProviderProps } from '../context/ChartDataProvider'; import type { ChartContainerProps } from './ChartContainer'; -import { useChartContainerDimensions } from './useChartContainerDimensions'; export type UseChartContainerPropsReturnValue = { - hasIntrinsicSize: boolean; chartDataProviderProps: ChartDataProviderProps; - resizableChartContainerProps: { - ownerState: { width: ChartContainerProps['width']; height: ChartContainerProps['height'] }; - ref: React.Ref; - }; + chartsSurfaceProps: ChartsSurfaceProps & { ref: React.Ref }; + resizableContainerProps: any; + children: React.ReactNode; }; export const useChartContainerProps = ( @@ -19,7 +18,6 @@ export const useChartContainerProps = ( const { width, height, - resolveSizeBeforeRender, margin, children, series, @@ -32,7 +30,6 @@ export const useChartContainerProps = ( plugins, sx, title, - viewBox, xAxis, yAxis, zAxis, @@ -40,44 +37,36 @@ export const useChartContainerProps = ( ...other } = props; - const { - containerRef, - width: dWidth, - height: dHeight, - } = useChartContainerDimensions(width, height, resolveSizeBeforeRender); + const resizableContainerProps = other; - const resizableChartContainerProps = { - ...other, - ownerState: { width, height }, - ref: containerRef, + const chartsSurfaceProps: ChartsSurfaceProps & { ref: React.Ref } = { + title, + desc, + sx, + disableAxisListener, + ref, }; - const chartDataProviderProps = { + const chartDataProviderProps: ChartDataProviderProps = { margin, - children, series, colors, dataset, - desc, - disableAxisListener, highlightedItem, onHighlightChange, plugins, - sx, - title, - viewBox, xAxis, yAxis, zAxis, skipAnimation, - width: dWidth, - height: dHeight, - ref, + width, + height, }; return { - hasIntrinsicSize: Boolean(dWidth && dHeight), chartDataProviderProps, - resizableChartContainerProps, + resizableContainerProps, + chartsSurfaceProps, + children, }; }; diff --git a/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx b/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx index d052d17b1367..f9bd7b41068c 100644 --- a/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx +++ b/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx @@ -3,6 +3,7 @@ import { createRenderer } from '@mui/internal-test-utils'; import { ChartsSurface } from '@mui/x-charts/ChartsSurface'; import { expect } from 'chai'; import { SvgRefProvider } from '../context/SvgRefProvider'; +import { SizeProvider } from '../context/SizeProvider'; describe('', () => { // JSDOM doesn't implement SVGElement @@ -16,11 +17,13 @@ describe('', () => { const ref = React.createRef(); render( - - - - - , + + + + + + + , ); expect(ref.current instanceof SVGElement, 'ref is a SVGElement').to.equal(true); diff --git a/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx b/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx index 270872e5705b..9939f798d1b3 100644 --- a/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx +++ b/packages/x-charts/src/ChartsSurface/ChartsSurface.tsx @@ -4,24 +4,11 @@ import PropTypes from 'prop-types'; import * as React from 'react'; import useForkRef from '@mui/utils/useForkRef'; import { useAxisEvents } from '../hooks/useAxisEvents'; +import { ChartsAxesGradients } from '../internals/components/ChartsAxesGradients'; +import { useDrawingArea } from '../hooks'; import { useSurfaceRef } from '../context/SvgRefProvider'; -type ViewBox = { - x?: number; - y?: number; - width?: number; - height?: number; -}; export interface ChartsSurfaceProps { - /** - * The width of the chart in px. - */ - width: number; - /** - * The height of the chart in px. - */ - height: number; - viewBox?: ViewBox; className?: string; title?: string; desc?: string; @@ -35,7 +22,7 @@ export interface ChartsSurfaceProps { disableAxisListener?: boolean; } -const ChartChartsSurfaceStyles = styled('svg', { +const ChartsSurfaceStyles = styled('svg', { name: 'MuiChartsSurface', slot: 'Root', })(() => ({ @@ -48,37 +35,39 @@ const ChartsSurface = React.forwardRef(functi inProps: ChartsSurfaceProps, ref: React.Ref, ) { - const props = useThemeProps({ props: inProps, name: 'MuiChartsSurface' }); - const { - children, - width, - height, - viewBox, - disableAxisListener = false, - className, - title, - desc, - ...other - } = props; - const svgView = { width, height, x: 0, y: 0, ...viewBox }; + const { width, height, left, right, top, bottom } = useDrawingArea(); const surfaceRef = useSurfaceRef(); const handleRef = useForkRef(surfaceRef, ref); + const themeProps = useThemeProps({ props: inProps, name: 'MuiChartsSurface' }); + + const { children, disableAxisListener = false, className, title, desc, ...other } = themeProps; + + const svgWidth = width + left + right; + const svgHeight = height + top + bottom; + + const svgView = { + width: svgWidth, + height: svgHeight, + x: 0, + y: 0, + }; useAxisEvents(disableAxisListener); return ( - - {title} - {desc} + {title && {title}} + {desc && {desc}} + {children} - + ); }); @@ -96,26 +85,12 @@ ChartsSurface.propTypes = { * @default false */ disableAxisListener: PropTypes.bool, - /** - * The height of the chart in px. - */ - height: PropTypes.number.isRequired, sx: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object, ]), title: PropTypes.string, - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), - /** - * The width of the chart in px. - */ - width: PropTypes.number.isRequired, } as any; export { ChartsSurface }; diff --git a/packages/x-charts/src/Gauge/Gauge.tsx b/packages/x-charts/src/Gauge/Gauge.tsx index 01a4fd2827e1..c169d1251f9e 100644 --- a/packages/x-charts/src/Gauge/Gauge.tsx +++ b/packages/x-charts/src/Gauge/Gauge.tsx @@ -135,12 +135,6 @@ Gauge.propTypes = { * @default 0 */ valueMin: PropTypes.number, - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * 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/Gauge/GaugeContainer.tsx b/packages/x-charts/src/Gauge/GaugeContainer.tsx index e25066c0e618..6126367e056c 100644 --- a/packages/x-charts/src/Gauge/GaugeContainer.tsx +++ b/packages/x-charts/src/Gauge/GaugeContainer.tsx @@ -2,16 +2,15 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { styled } from '@mui/material/styles'; -import useForkRef from '@mui/utils/useForkRef'; -import { useChartContainerDimensions } from '../ChartContainer/useChartContainerDimensions'; import { ChartsSurface, ChartsSurfaceProps } from '../ChartsSurface'; import { DrawingAreaProvider, DrawingAreaProviderProps } from '../context/DrawingAreaProvider'; import { GaugeProvider, GaugeProviderProps } from './GaugeProvider'; +import { SizeProvider, useSize } from '../context/SizeProvider'; import { SvgRefProvider } from '../context/SvgRefProvider'; export interface GaugeContainerProps extends Omit, - Omit, + Pick, Omit { /** * The width of the chart in px. If not defined, it takes the width of the parent element. @@ -24,7 +23,7 @@ export interface GaugeContainerProps children?: React.ReactNode; } -const ResizableContainer = styled('div', { +const ResizableContainerRoot = styled('div', { name: 'MuiGauge', slot: 'Container', })<{ ownerState: Pick }>(({ ownerState, theme }) => ({ @@ -46,6 +45,20 @@ const ResizableContainer = styled('div', { }, })); +function ResizableContainer(props: any) { + const { inHeight, inWidth, hasIntrinsicSize, containerRef } = useSize(); + + return ( + + {hasIntrinsicSize && props.children} + + ); +} + const GaugeContainer = React.forwardRef(function GaugeContainer( props: GaugeContainerProps, ref: React.Ref, @@ -69,56 +82,44 @@ const GaugeContainer = React.forwardRef(function GaugeContainer( children, ...other } = props; - const { containerRef, width, height } = useChartContainerDimensions(inWidth, inHeight); - - const svgRef = React.useRef(null); - const chartSurfaceRef = useForkRef(ref, svgRef); return ( - - {width && height ? ( - - + + + - - - - - ) : null} - + + + + + ); }); @@ -215,12 +216,6 @@ GaugeContainer.propTypes = { * @default 0 */ valueMin: PropTypes.number, - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * 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/LineChart/LineChart.tsx b/packages/x-charts/src/LineChart/LineChart.tsx index 3364ba4ad9a0..8da4a8e59f1d 100644 --- a/packages/x-charts/src/LineChart/LineChart.tsx +++ b/packages/x-charts/src/LineChart/LineChart.tsx @@ -357,12 +357,6 @@ LineChart.propTypes = { * @default null */ topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * 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/PieChart/PieChart.tsx b/packages/x-charts/src/PieChart/PieChart.tsx index 3e712091a1c5..28c41b7bfd44 100644 --- a/packages/x-charts/src/PieChart/PieChart.tsx +++ b/packages/x-charts/src/PieChart/PieChart.tsx @@ -259,12 +259,6 @@ PieChart.propTypes = { slots: PropTypes.object, trigger: PropTypes.oneOf(['axis', 'item', 'none']), }), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * 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/ScatterChart.tsx b/packages/x-charts/src/ScatterChart/ScatterChart.tsx index 713508a1219a..951ed860ef70 100644 --- a/packages/x-charts/src/ScatterChart/ScatterChart.tsx +++ b/packages/x-charts/src/ScatterChart/ScatterChart.tsx @@ -311,12 +311,6 @@ ScatterChart.propTypes = { * @default null */ topAxis: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * Defines the maximal distance between a scatter point and the pointer that triggers the interaction. * If `undefined`, the radius is assumed to be infinite. diff --git a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx index fb75f3df563d..c08f0a2942b4 100644 --- a/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx +++ b/packages/x-charts/src/SparkLineChart/SparkLineChart.tsx @@ -375,12 +375,6 @@ SparkLineChart.propTypes = { * @default (value: number | null) => (value === null ? '' : value.toString()) */ valueFormatter: PropTypes.func, - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** * 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/context/ChartDataProvider/ChartDataProvider.test.tsx b/packages/x-charts/src/context/ChartDataProvider/ChartDataProvider.test.tsx index ac81b3cfc7d0..ca0355c21029 100644 --- a/packages/x-charts/src/context/ChartDataProvider/ChartDataProvider.test.tsx +++ b/packages/x-charts/src/context/ChartDataProvider/ChartDataProvider.test.tsx @@ -13,6 +13,10 @@ describe('', () => { testComponentPropWith: 'div', refInstanceof: window.SVGSVGElement, skip: [ + 'mergeClassName', + 'propsSpread', + 'rootClass', + 'refForwarding', 'componentProp', 'componentsProp', 'slotPropsProp', diff --git a/packages/x-charts/src/context/ChartDataProvider/ChartDataProvider.tsx b/packages/x-charts/src/context/ChartDataProvider/ChartDataProvider.tsx index 4393c89d6c09..2f4e5e5d1e34 100644 --- a/packages/x-charts/src/context/ChartDataProvider/ChartDataProvider.tsx +++ b/packages/x-charts/src/context/ChartDataProvider/ChartDataProvider.tsx @@ -5,25 +5,20 @@ import { MakeOptional } from '@mui/x-internals/types'; import { DrawingAreaProvider, DrawingAreaProviderProps } from '../DrawingAreaProvider'; import { SeriesProvider, SeriesProviderProps } from '../SeriesProvider'; import { InteractionProvider } from '../InteractionProvider'; -import { ChartsSurface, ChartsSurfaceProps } from '../../ChartsSurface'; import { CartesianProvider, CartesianProviderProps } from '../CartesianProvider'; -import { ChartsAxesGradients } from '../../internals/components/ChartsAxesGradients'; -import { - HighlightedProvider, - HighlightedProviderProps, - ZAxisContextProvider, - ZAxisContextProviderProps, -} from '..'; import { PluginProvider, PluginProviderProps } from '../PluginProvider'; import { useChartDataProviderProps } from './useChartDataProviderProps'; import { AxisConfig, ChartsXAxisProps, ChartsYAxisProps, ScaleName } from '../../models/axis'; import { AnimationProvider, AnimationProviderProps } from '../AnimationProvider'; +import { ZAxisContextProvider, ZAxisContextProviderProps } from '../ZAxisContextProvider'; +import { HighlightedProvider, HighlightedProviderProps } from '../HighlightedProvider'; +import { SizeProvider, SizeProviderProps } from '../SizeProvider'; import { SvgRefProvider } from '../SvgRefProvider'; export type ChartDataProviderProps = Omit< - ChartsSurfaceProps & + SizeProviderProps & Omit & - Omit & + Pick & Pick & ZAxisContextProviderProps & HighlightedProviderProps & @@ -46,10 +41,7 @@ export type ChartDataProviderProps = Omit< children?: React.ReactNode; }; -const ChartDataProvider = React.forwardRef(function ChartDataProvider( - props: ChartDataProviderProps, - ref: React.Ref, -) { +function ChartDataProvider(props: ChartDataProviderProps) { const { children, drawingAreaProviderProps, @@ -57,15 +49,14 @@ const ChartDataProvider = React.forwardRef(function ChartDataProvider( cartesianProviderProps, zAxisContextProps, highlightedProviderProps, - chartsSurfaceProps, pluginProviderProps, animationProviderProps, - svgRefProviderProps, - } = useChartDataProviderProps(props, ref); + sizeProviderProps, + } = useChartDataProviderProps(props); return ( - - + + @@ -73,10 +64,7 @@ const ChartDataProvider = React.forwardRef(function ChartDataProvider( - - - {children} - + {children} @@ -84,10 +72,10 @@ const ChartDataProvider = React.forwardRef(function ChartDataProvider( - - + + ); -}); +} ChartDataProvider.propTypes = { // ----------------------------- Warning -------------------------------- @@ -95,7 +83,6 @@ ChartDataProvider.propTypes = { // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- children: PropTypes.node, - className: PropTypes.string, /** * Color palette used to colorize multiple series. * @default blueberryTwilightPalette @@ -105,17 +92,10 @@ ChartDataProvider.propTypes = { * An array of objects that can be used to populate series and axes data using their `dataKey` property. */ dataset: PropTypes.arrayOf(PropTypes.object), - desc: PropTypes.string, /** - * If `true`, the charts will not listen to the mouse move event. - * It might break interactive features, but will improve performance. - * @default false - */ - disableAxisListener: PropTypes.bool, - /** - * The height of the chart in px. + * The height of the chart in px. If not defined, it takes the height of the parent element. */ - height: PropTypes.number.isRequired, + height: PropTypes.number, /** * The item currently highlighted. Turns highlighting into a controlled prop. */ @@ -146,6 +126,16 @@ ChartDataProvider.propTypes = { * If not provided, the container supports line, bar, scatter and pie charts. */ plugins: PropTypes.arrayOf(PropTypes.object), + /** + * The chart will try to wait for the parent container to resolve its size + * before it renders for the first time. + * + * This can be useful in some scenarios where the chart appear to grow after + * the first render, like when used inside a grid. + * + * @default false + */ + resolveSizeBeforeRender: PropTypes.bool, /** * The array of series to display. * Each type of series has its own specificity. @@ -157,22 +147,10 @@ ChartDataProvider.propTypes = { * If unset or `false`, the animations respects the user's `prefers-reduced-motion` setting. */ skipAnimation: PropTypes.bool, - sx: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), - PropTypes.func, - PropTypes.object, - ]), - title: PropTypes.string, - viewBox: PropTypes.shape({ - height: PropTypes.number, - width: PropTypes.number, - x: PropTypes.number, - y: PropTypes.number, - }), /** - * The width of the chart in px. + * The width of the chart in px. If not defined, it takes the width of the parent element. */ - width: PropTypes.number.isRequired, + width: PropTypes.number, /** * The configuration of the x-axes. * If not provided, a default axis config is used. diff --git a/packages/x-charts/src/context/ChartDataProvider/useChartDataProviderProps.ts b/packages/x-charts/src/context/ChartDataProvider/useChartDataProviderProps.ts index caf45f17b7c8..a3c77fe7801f 100644 --- a/packages/x-charts/src/context/ChartDataProvider/useChartDataProviderProps.ts +++ b/packages/x-charts/src/context/ChartDataProvider/useChartDataProviderProps.ts @@ -1,21 +1,16 @@ 'use client'; -import * as React from 'react'; import type { DrawingAreaProviderProps } from '../DrawingAreaProvider'; import type { CartesianProviderProps } from '../CartesianProvider'; import type { SeriesProviderProps } from '../SeriesProvider'; import type { ZAxisContextProviderProps } from '../ZAxisContextProvider'; import type { ChartDataProviderProps } from './ChartDataProvider'; -import { HighlightedProviderProps } from '..'; -import { ChartsSurfaceProps } from '../../ChartsSurface'; +import { HighlightedProviderProps } from '../HighlightedProvider'; import { useDefaultizeAxis } from './useDefaultizeAxis'; import { PluginProviderProps } from '../PluginProvider'; import { AnimationProviderProps } from '../AnimationProvider'; -import { SvgRefProviderProps } from '../SvgRefProvider'; +import { SizeProviderProps } from '../SizeProvider'; -export const useChartDataProviderProps = ( - props: ChartDataProviderProps, - ref: React.Ref, -) => { +export const useChartDataProviderProps = (props: ChartDataProviderProps) => { const { width, height, @@ -26,27 +21,17 @@ export const useChartDataProviderProps = ( zAxis, colors, dataset, - sx, - title, - desc, - disableAxisListener, highlightedItem, onHighlightChange, plugins, children, skipAnimation, - ...other + resolveSizeBeforeRender, } = props; const [defaultizedXAxis, defaultizedYAxis] = useDefaultizeAxis(xAxis, yAxis, dataset); - const svgRefProviderProps: Omit = { - svgRef: ref, - }; - const drawingAreaProviderProps: Omit = { - width, - height, margin, }; @@ -80,14 +65,10 @@ export const useChartDataProviderProps = ( onHighlightChange, }; - const chartsSurfaceProps: ChartsSurfaceProps = { - ...other, + const sizeProviderProps: Omit = { width, height, - sx, - title, - desc, - disableAxisListener, + resolveSizeBeforeRender, }; return { @@ -97,11 +78,10 @@ export const useChartDataProviderProps = ( cartesianProviderProps, zAxisContextProps, highlightedProviderProps, - chartsSurfaceProps, pluginProviderProps, animationProviderProps, - svgRefProviderProps, xAxis: defaultizedXAxis, yAxis: defaultizedYAxis, + sizeProviderProps, }; }; diff --git a/packages/x-charts/src/context/DrawingAreaProvider/DrawingArea.types.ts b/packages/x-charts/src/context/DrawingAreaProvider/DrawingArea.types.ts index 98469323d98c..58ab5b5a7d3f 100644 --- a/packages/x-charts/src/context/DrawingAreaProvider/DrawingArea.types.ts +++ b/packages/x-charts/src/context/DrawingAreaProvider/DrawingArea.types.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { LayoutConfig } from '../../models'; -export interface DrawingAreaProviderProps extends LayoutConfig { +export interface DrawingAreaProviderProps extends Pick { children: React.ReactNode; } diff --git a/packages/x-charts/src/context/DrawingAreaProvider/DrawingAreaProvider.tsx b/packages/x-charts/src/context/DrawingAreaProvider/DrawingAreaProvider.tsx index 6357c5125929..1735812357df 100644 --- a/packages/x-charts/src/context/DrawingAreaProvider/DrawingAreaProvider.tsx +++ b/packages/x-charts/src/context/DrawingAreaProvider/DrawingAreaProvider.tsx @@ -4,9 +4,11 @@ import useId from '@mui/utils/useId'; import useChartDimensions from '../../hooks/useChartDimensions'; import { DrawingAreaProviderProps, DrawingAreaState } from './DrawingArea.types'; import { DrawingAreaContext } from './DrawingAreaContext'; +import { useSize } from '../SizeProvider'; export function DrawingAreaProvider(props: DrawingAreaProviderProps) { - const { width, height, margin, children } = props; + const { margin, children } = props; + const { width, height } = useSize(); const drawingArea = useChartDimensions(width, height, margin); const chartId = useId(); diff --git a/packages/x-charts/src/context/SizeProvider/Size.types.ts b/packages/x-charts/src/context/SizeProvider/Size.types.ts new file mode 100644 index 000000000000..ea93098aa2cc --- /dev/null +++ b/packages/x-charts/src/context/SizeProvider/Size.types.ts @@ -0,0 +1,42 @@ +import * as React from 'react'; + +export interface SizeProviderProps { + /** + * The width of the chart in px. If not defined, it takes the width of the parent element. + */ + width?: number; + /** + * The height of the chart in px. If not defined, it takes the height of the parent element. + */ + height?: number; + /** + * The chart will try to wait for the parent container to resolve its size + * before it renders for the first time. + * + * This can be useful in some scenarios where the chart appear to grow after + * the first render, like when used inside a grid. + * + * @default false + */ + resolveSizeBeforeRender?: boolean; + children: React.ReactNode; +} + +export interface SizeContextState extends Required> { + /** + * The ref of the container element that the chart is rendered in. + */ + containerRef: React.RefObject; + /** + * If the chart has a defined size. + */ + hasIntrinsicSize: boolean; + /** + * The input height of the chart in px. + */ + inHeight?: number; + /** + * The input width of the chart in px. + */ + inWidth?: number; +} diff --git a/packages/x-charts/src/context/SizeProvider/SizeContext.ts b/packages/x-charts/src/context/SizeProvider/SizeContext.ts new file mode 100644 index 000000000000..f9c4b22b7a9c --- /dev/null +++ b/packages/x-charts/src/context/SizeProvider/SizeContext.ts @@ -0,0 +1,18 @@ +import * as React from 'react'; + +import { Initializable } from '../context.types'; +import { SizeContextState } from './Size.types'; + +export const SizeContext = React.createContext>({ + isInitialized: false, + data: { + hasIntrinsicSize: false, + containerRef: null as any, + height: 0, + width: 0, + }, +}); + +if (process.env.NODE_ENV !== 'production') { + SizeContext.displayName = 'SizeContext'; +} diff --git a/packages/x-charts/src/context/SizeProvider/SizeProvider.tsx b/packages/x-charts/src/context/SizeProvider/SizeProvider.tsx new file mode 100644 index 000000000000..7b704a92931b --- /dev/null +++ b/packages/x-charts/src/context/SizeProvider/SizeProvider.tsx @@ -0,0 +1,32 @@ +'use client'; +import * as React from 'react'; +import { SizeContext } from './SizeContext'; +import { SizeProviderProps } from './Size.types'; +import { useChartContainerDimensions } from './useChartContainerDimensions'; + +/** + * The size provider. + * + * This differs from the DrawingProvider in that it provides the full size of the container. + * + * This provider is also responsible for resolving the size of the container before rendering and if the parent size changes. + */ +function SizeProvider(props: SizeProviderProps) { + const dimensions = useChartContainerDimensions( + props.width, + props.height, + props.resolveSizeBeforeRender, + ); + + const value = React.useMemo( + () => ({ + isInitialized: true, + data: dimensions, + }), + [dimensions], + ); + + return {props.children}; +} + +export { SizeProvider }; diff --git a/packages/x-charts/src/context/SizeProvider/index.ts b/packages/x-charts/src/context/SizeProvider/index.ts new file mode 100644 index 000000000000..dfeb24e47f33 --- /dev/null +++ b/packages/x-charts/src/context/SizeProvider/index.ts @@ -0,0 +1,4 @@ +export * from './SizeProvider'; +export * from './SizeContext'; +export * from './useSize'; +export * from './Size.types'; diff --git a/packages/x-charts/src/ChartContainer/useChartContainerDimensions.ts b/packages/x-charts/src/context/SizeProvider/useChartContainerDimensions.ts similarity index 93% rename from packages/x-charts/src/ChartContainer/useChartContainerDimensions.ts rename to packages/x-charts/src/context/SizeProvider/useChartContainerDimensions.ts index 56c5f6c602f5..e22bd75bdadf 100644 --- a/packages/x-charts/src/ChartContainer/useChartContainerDimensions.ts +++ b/packages/x-charts/src/context/SizeProvider/useChartContainerDimensions.ts @@ -112,5 +112,15 @@ export const useChartContainerDimensions = ( } } - return { containerRef: rootRef, width: inWidth ?? width, height: inHeight ?? height }; + const finalWidth = inWidth ?? width; + const finalHeight = inHeight ?? height; + + return { + containerRef: rootRef, + width: finalWidth, + height: finalHeight, + hasIntrinsicSize: Boolean(finalWidth && finalHeight), + inWidth, + inHeight, + }; }; diff --git a/packages/x-charts/src/context/SizeProvider/useSize.ts b/packages/x-charts/src/context/SizeProvider/useSize.ts new file mode 100644 index 000000000000..4e7ebb951300 --- /dev/null +++ b/packages/x-charts/src/context/SizeProvider/useSize.ts @@ -0,0 +1,12 @@ +'use client'; +import * as React from 'react'; +import { SizeContext } from './SizeContext'; +import { SizeContextState } from './Size.types'; + +/** + * Returns the size of the chart. And the ref of the container element that the chart is rendered in. + */ +export const useSize = (): SizeContextState => { + const { data } = React.useContext(SizeContext); + return data; +}; diff --git a/packages/x-charts/src/context/SvgRefProvider/SvgRef.types.ts b/packages/x-charts/src/context/SvgRefProvider/SvgRef.types.ts index 05086bb263e5..92449792410f 100644 --- a/packages/x-charts/src/context/SvgRefProvider/SvgRef.types.ts +++ b/packages/x-charts/src/context/SvgRefProvider/SvgRef.types.ts @@ -2,7 +2,6 @@ import * as React from 'react'; export interface SvgRefProviderProps { children: React.ReactNode; - svgRef?: React.Ref; } export type SvgRefState = { diff --git a/packages/x-charts/src/context/SvgRefProvider/SvgRefProvider.tsx b/packages/x-charts/src/context/SvgRefProvider/SvgRefProvider.tsx index 2fb16cca48cf..fec512d29a82 100644 --- a/packages/x-charts/src/context/SvgRefProvider/SvgRefProvider.tsx +++ b/packages/x-charts/src/context/SvgRefProvider/SvgRefProvider.tsx @@ -5,9 +5,9 @@ import { SvgRefProviderProps } from './SvgRef.types'; import { SvgRefContext } from './SvgRefContext'; export function SvgRefProvider(props: SvgRefProviderProps) { - const { svgRef: inRef, children } = props; + const { children } = props; const svgRef = React.useRef(null); - const surfaceRef = useForkRef(inRef, svgRef); + const surfaceRef = useForkRef(svgRef); const refValue = React.useMemo( () => ({ isInitialized: true, data: { svgRef, surfaceRef } }), diff --git a/packages/x-charts/src/context/index.ts b/packages/x-charts/src/context/index.ts index a5cb93cdb90d..c95a0ef9fb67 100644 --- a/packages/x-charts/src/context/index.ts +++ b/packages/x-charts/src/context/index.ts @@ -1,3 +1,5 @@ export * from './HighlightedProvider'; export { ZAxisContextProvider } from './ZAxisContextProvider'; export type { ZAxisContextProviderProps } from './ZAxisContextProvider'; +export { ChartDataProvider } from './ChartDataProvider'; +export type { ChartDataProviderProps } from './ChartDataProvider'; diff --git a/packages/x-charts/src/hooks/useSvgRef.test.tsx b/packages/x-charts/src/hooks/useSvgRef.test.tsx index 60ba1fb07500..e6d16c2beab9 100644 --- a/packages/x-charts/src/hooks/useSvgRef.test.tsx +++ b/packages/x-charts/src/hooks/useSvgRef.test.tsx @@ -50,10 +50,8 @@ describe('useSvgRef', () => { it('should not throw an error when parent context is present', async () => { function RenderDrawingProvider() { - const ref = React.useRef(null); - return ( - + diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index fd233b5553d2..c96a644c9b58 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -1,7 +1,6 @@ // Components export * from './components/ChartsAxesGradients'; -export * from '../ChartContainer/useChartContainerDimensions'; export * from '../ChartContainer/ResizableContainer'; // hooks @@ -36,6 +35,7 @@ export * from '../context/AnimationProvider'; export type * from '../context/context.types'; export { getAxisExtremum } from '../context/CartesianProvider/getAxisExtremum'; export * from '../context/ChartDataProvider'; +export * from '../context/SizeProvider'; export * from '../context/SvgRefProvider'; // series configuration diff --git a/scripts/x-charts-pro.exports.json b/scripts/x-charts-pro.exports.json index d324d776f238..ca4a94f205c2 100644 --- a/scripts/x-charts-pro.exports.json +++ b/scripts/x-charts-pro.exports.json @@ -55,6 +55,8 @@ { "name": "CartesianSeriesType", "kind": "TypeAlias" }, { "name": "ChartContainerPro", "kind": "Variable" }, { "name": "ChartContainerProProps", "kind": "Interface" }, + { "name": "ChartDataProvider", "kind": "Function" }, + { "name": "ChartDataProviderProps", "kind": "TypeAlias" }, { "name": "ChartsAxis", "kind": "Function" }, { "name": "ChartsAxisClasses", "kind": "Interface" }, { "name": "ChartsAxisClassKey", "kind": "TypeAlias" }, diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index 696f6fbe2270..ced333367ebc 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -53,6 +53,8 @@ { "name": "CartesianSeriesType", "kind": "TypeAlias" }, { "name": "ChartContainer", "kind": "Variable" }, { "name": "ChartContainerProps", "kind": "Interface" }, + { "name": "ChartDataProvider", "kind": "Function" }, + { "name": "ChartDataProviderProps", "kind": "TypeAlias" }, { "name": "ChartsAxis", "kind": "Function" }, { "name": "ChartsAxisClasses", "kind": "Interface" }, { "name": "ChartsAxisClassKey", "kind": "TypeAlias" }, From e1516813513fb296bb115eed2e296759485fc33e Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:46:44 +0100 Subject: [PATCH 2/7] [charts] Fix key generation for the ChartsGrid (#15463) Co-authored-by: Jose C Quintas Jr --- packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx | 4 ++-- packages/x-charts/src/ChartsGrid/ChartsVerticalGrid.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx b/packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx index 85ab5f0dadfc..648a9de08cb6 100644 --- a/packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx +++ b/packages/x-charts/src/ChartsGrid/ChartsHorizontalGrid.tsx @@ -23,9 +23,9 @@ export function ChartsGridHorizontal(props: ChartsGridHorizontalProps) { return ( - {yTicks.map(({ formattedValue, offset }) => ( + {yTicks.map(({ value, offset }) => ( - {xTicks.map(({ formattedValue, offset }) => ( + {xTicks.map(({ value, offset }) => ( Date: Mon, 18 Nov 2024 15:35:55 +0200 Subject: [PATCH 3/7] Bump @docsearch/react to ^3.8.0 (#15450) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docs/package.json | 2 +- pnpm-lock.yaml | 54 +++++++++++++++++++++++------------------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/package.json b/docs/package.json index d5fba1fa2d17..a2aa363bf7bc 100644 --- a/docs/package.json +++ b/docs/package.json @@ -22,7 +22,7 @@ "@babel/core": "^7.26.0", "@babel/runtime": "^7.26.0", "@babel/runtime-corejs2": "^7.26.0", - "@docsearch/react": "^3.7.0", + "@docsearch/react": "^3.8.0", "@emotion/cache": "^11.13.1", "@emotion/react": "^11.13.3", "@emotion/server": "^11.11.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f23b14f2636..028442018628 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -414,8 +414,8 @@ importers: specifier: ^7.26.0 version: 7.26.0 '@docsearch/react': - specifier: ^3.7.0 - version: 3.7.0(@algolia/client-search@5.12.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0) + specifier: ^3.8.0 + version: 3.8.0(@algolia/client-search@5.12.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0) '@emotion/cache': specifier: ^11.13.1 version: 11.13.1 @@ -1712,22 +1712,22 @@ packages: '@adobe/css-tools@4.4.0': resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} - '@algolia/autocomplete-core@1.17.6': - resolution: {integrity: sha512-lkDoW4I7h2kKlIgf3pUt1LqvxyYKkVyiypoGLlUnhPSnCpmeOwudM6rNq6YYsCmdQtnDQoW5lUNNuj6ASg3qeg==} + '@algolia/autocomplete-core@1.17.7': + resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==} - '@algolia/autocomplete-plugin-algolia-insights@1.17.6': - resolution: {integrity: sha512-17NnaacuFzSWVuZu4NKzVeaFIe9Abpw8w+/gjc7xhZFtqj+GadufzodIdchwiB2eM2cDdiR3icW7gbNTB3K2YA==} + '@algolia/autocomplete-plugin-algolia-insights@1.17.7': + resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==} peerDependencies: search-insights: '>= 1 < 3' - '@algolia/autocomplete-preset-algolia@1.17.6': - resolution: {integrity: sha512-Cvg5JENdSCMuClwhJ1ON1/jSuojaYMiUW2KePm18IkdCzPJj/NXojaOxw58RFtQFpJgfVW8h2E8mEoDtLlMdeA==} + '@algolia/autocomplete-preset-algolia@1.17.7': + resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==} peerDependencies: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' - '@algolia/autocomplete-shared@1.17.6': - resolution: {integrity: sha512-aq/3V9E00Tw2GC/PqgyPGXtqJUlVc17v4cn1EUhSc+O/4zd04Uwb3UmPm8KDaYQQOrkt1lwvCj2vG2wRE5IKhw==} + '@algolia/autocomplete-shared@1.17.7': + resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==} peerDependencies: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' @@ -2454,11 +2454,11 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@docsearch/css@3.7.0': - resolution: {integrity: sha512-1OorbTwi1eeDmr0v5t+ckSRlt1zM5GHjm92iIl3kUu7im3GHuP+csf6E0WBg8pdXQczTWP9J9+o9n+Vg6DH5cQ==} + '@docsearch/css@3.8.0': + resolution: {integrity: sha512-pieeipSOW4sQ0+bE5UFC51AOZp9NGxg89wAlZ1BAQFaiRAGK1IKUaPQ0UGZeNctJXyqZ1UvBtOQh2HH+U5GtmA==} - '@docsearch/react@3.7.0': - resolution: {integrity: sha512-8e6tdDfkYoxafEEPuX5eE1h9cTkLvhe4KgoFkO5JCddXSQONnN1FHcDZRI4r8894eMpbYq6rdJF0dVYh8ikwNQ==} + '@docsearch/react@3.8.0': + resolution: {integrity: sha512-WnFK720+iwTVt94CxY3u+FgX6exb3BfN5kE9xUY6uuAH/9W/UFboBZFLlrw/zxFRHoHZCOXRtOylsXF+6LHI+Q==} peerDependencies: '@types/react': '>= 16.8.0 < 19.0.0' react: '>= 16.8.0 < 19.0.0' @@ -10395,30 +10395,30 @@ snapshots: '@adobe/css-tools@4.4.0': {} - '@algolia/autocomplete-core@1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0)': + '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0)': dependencies: - '@algolia/autocomplete-plugin-algolia-insights': 1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0) - '@algolia/autocomplete-shared': 1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) + '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - search-insights - '@algolia/autocomplete-plugin-algolia-insights@1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0)': + '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0)': dependencies: - '@algolia/autocomplete-shared': 1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) search-insights: 2.13.0 transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - '@algolia/autocomplete-preset-algolia@1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)': + '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)': dependencies: - '@algolia/autocomplete-shared': 1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) + '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) '@algolia/client-search': 5.12.0 algoliasearch: 5.12.0 - '@algolia/autocomplete-shared@1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)': + '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)': dependencies: '@algolia/client-search': 5.12.0 algoliasearch: 5.12.0 @@ -11389,13 +11389,13 @@ snapshots: '@discoveryjs/json-ext@0.5.7': {} - '@docsearch/css@3.7.0': {} + '@docsearch/css@3.8.0': {} - '@docsearch/react@3.7.0(@algolia/client-search@5.12.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0)': + '@docsearch/react@3.8.0(@algolia/client-search@5.12.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.13.0)': dependencies: - '@algolia/autocomplete-core': 1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0) - '@algolia/autocomplete-preset-algolia': 1.17.6(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) - '@docsearch/css': 3.7.0 + '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0)(search-insights@2.13.0) + '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.12.0)(algoliasearch@5.12.0) + '@docsearch/css': 3.8.0 algoliasearch: 5.12.0 optionalDependencies: '@types/react': 18.3.12 From 2d413f3ea60c98b4a91b158cc76674cf813606d1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:36:29 +0200 Subject: [PATCH 4/7] Bump Vite & Vitest to 2.1.5 (#15444) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 161 ++++++++++++++------------- test/performance-charts/package.json | 6 +- 2 files changed, 84 insertions(+), 83 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 028442018628..12dfa325544c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1644,7 +1644,7 @@ importers: devDependencies: '@codspeed/vitest-plugin': specifier: ^3.1.1 - version: 3.1.1(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.4) + version: 3.1.1(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.5) '@emotion/react': specifier: ^11.13.3 version: 11.13.3(@types/react@18.3.12)(react@18.3.1) @@ -1670,11 +1670,11 @@ importers: specifier: ^3.7.1 version: 3.7.1(@swc/helpers@0.5.5)(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0)) '@vitest/browser': - specifier: 2.1.4 - version: 2.1.4(@types/node@20.17.6)(playwright@1.48.2)(typescript@5.6.3)(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.4) + specifier: 2.1.5 + version: 2.1.5(@types/node@20.17.6)(playwright@1.48.2)(typescript@5.6.3)(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.5) '@vitest/ui': - specifier: 2.1.4 - version: 2.1.4(vitest@2.1.4) + specifier: 2.1.5 + version: 2.1.5(vitest@2.1.5) jsdom: specifier: ^24.1.3 version: 24.1.3 @@ -1685,8 +1685,8 @@ importers: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) vitest: - specifier: 2.1.4 - version: 2.1.4(@types/node@20.17.6)(@vitest/browser@2.1.4)(@vitest/ui@2.1.4)(jsdom@24.1.3)(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) + specifier: 2.1.5 + version: 2.1.5(@types/node@20.17.6)(@vitest/browser@2.1.5)(@vitest/ui@2.1.5)(jsdom@24.1.3)(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) packages: @@ -3079,8 +3079,8 @@ packages: resolution: {integrity: sha512-DPnl5lPX4v49eVxEbJnAizrpMdMTBz1qykZrAbBul9rfgk531v8oAt+Pm6O/rpAleRombNM7FJb5rYGzBJatOQ==} engines: {node: '>=18.0.0'} - '@mswjs/interceptors@0.36.10': - resolution: {integrity: sha512-GXrJgakgJW3DWKueebkvtYgGKkxA7s0u5B0P5syJM5rvQUnrpLPigvci8Hukl7yEM+sU06l+er2Fgvx/gmiRgg==} + '@mswjs/interceptors@0.37.0': + resolution: {integrity: sha512-lDiHQMCBV9qz8c7+zxaNFQtWWaSogTYkqJ3Pg+FGYYC76nsfSxkMQ0df8fojyz16E+w4vp57NLjN2muNG7LugQ==} engines: {node: '>=18'} '@mui/base@5.0.0-beta.40': @@ -4400,12 +4400,12 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 - '@vitest/browser@2.1.4': - resolution: {integrity: sha512-89SrvShW6kWzmEYtBj5k1gBq88emoC2qrngw5hE1vNpRFteQ5/1URbKIVww391rIALTpzhhCt5yJt5tjLPZxYw==} + '@vitest/browser@2.1.5': + resolution: {integrity: sha512-JrpnxvkrjlBrF7oXbK/YytWVYfJIzWYeDKppANlUaisBKwDso+yXlWocAJrANx8gUxyirF355Yx80S+SKQqayg==} peerDependencies: playwright: '*' safaridriver: '*' - vitest: 2.1.4 + vitest: 2.1.5 webdriverio: '*' peerDependenciesMeta: playwright: @@ -4415,11 +4415,11 @@ packages: webdriverio: optional: true - '@vitest/expect@2.1.4': - resolution: {integrity: sha512-DOETT0Oh1avie/D/o2sgMHGrzYUFFo3zqESB2Hn70z6QB1HrS2IQ9z5DfyTqU8sg4Bpu13zZe9V4+UTNQlUeQA==} + '@vitest/expect@2.1.5': + resolution: {integrity: sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==} - '@vitest/mocker@2.1.4': - resolution: {integrity: sha512-Ky/O1Lc0QBbutJdW0rqLeFNbuLEyS+mIPiNdlVlp2/yhJ0SbyYqObS5IHdhferJud8MbbwMnexg4jordE5cCoQ==} + '@vitest/mocker@2.1.5': + resolution: {integrity: sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==} peerDependencies: msw: ^2.4.9 vite: ^5.0.0 @@ -4429,25 +4429,25 @@ packages: vite: optional: true - '@vitest/pretty-format@2.1.4': - resolution: {integrity: sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==} + '@vitest/pretty-format@2.1.5': + resolution: {integrity: sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==} - '@vitest/runner@2.1.4': - resolution: {integrity: sha512-sKRautINI9XICAMl2bjxQM8VfCMTB0EbsBc/EDFA57V6UQevEKY/TOPOF5nzcvCALltiLfXWbq4MaAwWx/YxIA==} + '@vitest/runner@2.1.5': + resolution: {integrity: sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==} - '@vitest/snapshot@2.1.4': - resolution: {integrity: sha512-3Kab14fn/5QZRog5BPj6Rs8dc4B+mim27XaKWFWHWA87R56AKjHTGcBFKpvZKDzC4u5Wd0w/qKsUIio3KzWW4Q==} + '@vitest/snapshot@2.1.5': + resolution: {integrity: sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==} - '@vitest/spy@2.1.4': - resolution: {integrity: sha512-4JOxa+UAizJgpZfaCPKK2smq9d8mmjZVPMt2kOsg/R8QkoRzydHH1qHxIYNvr1zlEaFj4SXiaaJWxq/LPLKaLg==} + '@vitest/spy@2.1.5': + resolution: {integrity: sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==} - '@vitest/ui@2.1.4': - resolution: {integrity: sha512-Zd9e5oU063c+j9N9XzGJagCLNvG71x/2tOme3Js4JEZKX55zsgxhJwUgLI8hkN6NjMLpdJO8d7nVUUuPGAA58Q==} + '@vitest/ui@2.1.5': + resolution: {integrity: sha512-ERgKkDMTfngrZip6VG5h8L9B5D0AH/4+bga4yR1UzGH7c2cxv3LWogw2Dvuwr9cP3/iKDHYys7kIFLDKpxORTg==} peerDependencies: - vitest: 2.1.4 + vitest: 2.1.5 - '@vitest/utils@2.1.4': - resolution: {integrity: sha512-MXDnZn0Awl2S86PSNIim5PWXgIAx8CIkzu35mBdSApUip6RFOGXBCf3YFyeEu8n1IHk4bWD46DeYFu9mQlFIRg==} + '@vitest/utils@2.1.5': + resolution: {integrity: sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==} '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} @@ -7989,8 +7989,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.6.2: - resolution: {integrity: sha512-RdRgPvjfuzMIACkWv7VOVAeSRYMU3ofokLv1w0RsbFX960qnj/tFEyOFXY0G2GTUd9trA6rHuHciM/FKpBp6/A==} + msw@2.6.5: + resolution: {integrity: sha512-PnlnTpUlOrj441kYQzzFhzMzMCGFT6a2jKUBG7zSpLkYS5oh8Arrbc0dL8/rNAtxaoBy0EVs2mFqj2qdmWK7lQ==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -9380,8 +9380,8 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - std-env@3.7.0: - resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} stream-browserify@3.0.0: resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} @@ -10002,8 +10002,8 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite-node@2.1.4: - resolution: {integrity: sha512-kqa9v+oi4HwkG6g8ufRnb5AeplcRw8jUF6/7/Qz1qRQOXHImG8YnLbB+LLszENwFnoBl9xIf9nVdCFzNd7GQEg==} + vite-node@2.1.5: + resolution: {integrity: sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -10035,15 +10035,15 @@ packages: terser: optional: true - vitest@2.1.4: - resolution: {integrity: sha512-eDjxbVAJw1UJJCHr5xr/xM86Zx+YxIEXGAR+bmnEID7z9qWfoxpHw0zdobz+TQAFOLT+nEXz3+gx6nUJ7RgmlQ==} + vitest@2.1.5: + resolution: {integrity: sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^20.17.6 - '@vitest/browser': 2.1.4 - '@vitest/ui': 2.1.4 + '@vitest/browser': 2.1.5 + '@vitest/ui': 2.1.5 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -11377,11 +11377,11 @@ snapshots: transitivePeerDependencies: - debug - '@codspeed/vitest-plugin@3.1.1(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.4)': + '@codspeed/vitest-plugin@3.1.1(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.5)': dependencies: '@codspeed/core': 3.1.1 vite: 5.3.4(@types/node@20.17.6)(terser@5.27.0) - vitest: 2.1.4(@types/node@20.17.6)(@vitest/browser@2.1.4)(@vitest/ui@2.1.4)(jsdom@24.1.3)(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) + vitest: 2.1.5(@types/node@20.17.6)(@vitest/browser@2.1.5)(@vitest/ui@2.1.5)(jsdom@24.1.3)(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) transitivePeerDependencies: - debug @@ -11984,7 +11984,7 @@ snapshots: - supports-color - typescript - '@mswjs/interceptors@0.36.10': + '@mswjs/interceptors@0.37.0': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -13535,17 +13535,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/browser@2.1.4(@types/node@20.17.6)(playwright@1.48.2)(typescript@5.6.3)(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.4)': + '@vitest/browser@2.1.5(@types/node@20.17.6)(playwright@1.48.2)(typescript@5.6.3)(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.5)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) - '@vitest/mocker': 2.1.4(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0)) - '@vitest/utils': 2.1.4 + '@vitest/mocker': 2.1.5(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0)) + '@vitest/utils': 2.1.5 magic-string: 0.30.12 - msw: 2.6.2(@types/node@20.17.6)(typescript@5.6.3) + msw: 2.6.5(@types/node@20.17.6)(typescript@5.6.3) sirv: 3.0.0 tinyrainbow: 1.2.0 - vitest: 2.1.4(@types/node@20.17.6)(@vitest/browser@2.1.4)(@vitest/ui@2.1.4)(jsdom@24.1.3)(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) + vitest: 2.1.5(@types/node@20.17.6)(@vitest/browser@2.1.5)(@vitest/ui@2.1.5)(jsdom@24.1.3)(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) ws: 8.18.0 optionalDependencies: playwright: 1.48.2 @@ -13556,55 +13556,55 @@ snapshots: - utf-8-validate - vite - '@vitest/expect@2.1.4': + '@vitest/expect@2.1.5': dependencies: - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 + '@vitest/spy': 2.1.5 + '@vitest/utils': 2.1.5 chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.4(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))': + '@vitest/mocker@2.1.5(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))': dependencies: - '@vitest/spy': 2.1.4 + '@vitest/spy': 2.1.5 estree-walker: 3.0.3 magic-string: 0.30.12 optionalDependencies: - msw: 2.6.2(@types/node@20.17.6)(typescript@5.6.3) + msw: 2.6.5(@types/node@20.17.6)(typescript@5.6.3) vite: 5.3.4(@types/node@20.17.6)(terser@5.27.0) - '@vitest/pretty-format@2.1.4': + '@vitest/pretty-format@2.1.5': dependencies: tinyrainbow: 1.2.0 - '@vitest/runner@2.1.4': + '@vitest/runner@2.1.5': dependencies: - '@vitest/utils': 2.1.4 + '@vitest/utils': 2.1.5 pathe: 1.1.2 - '@vitest/snapshot@2.1.4': + '@vitest/snapshot@2.1.5': dependencies: - '@vitest/pretty-format': 2.1.4 + '@vitest/pretty-format': 2.1.5 magic-string: 0.30.12 pathe: 1.1.2 - '@vitest/spy@2.1.4': + '@vitest/spy@2.1.5': dependencies: tinyspy: 3.0.2 - '@vitest/ui@2.1.4(vitest@2.1.4)': + '@vitest/ui@2.1.5(vitest@2.1.5)': dependencies: - '@vitest/utils': 2.1.4 + '@vitest/utils': 2.1.5 fflate: 0.8.2 flatted: 3.3.1 pathe: 1.1.2 sirv: 3.0.0 tinyglobby: 0.2.10 tinyrainbow: 1.2.0 - vitest: 2.1.4(@types/node@20.17.6)(@vitest/browser@2.1.4)(@vitest/ui@2.1.4)(jsdom@24.1.3)(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) + vitest: 2.1.5(@types/node@20.17.6)(@vitest/browser@2.1.5)(@vitest/ui@2.1.5)(jsdom@24.1.3)(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0) - '@vitest/utils@2.1.4': + '@vitest/utils@2.1.5': dependencies: - '@vitest/pretty-format': 2.1.4 + '@vitest/pretty-format': 2.1.5 loupe: 3.1.2 tinyrainbow: 1.2.0 @@ -17888,13 +17888,13 @@ snapshots: ms@2.1.3: {} - msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3): + msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3): dependencies: '@bundled-es-modules/cookie': 2.0.1 '@bundled-es-modules/statuses': 1.0.1 '@bundled-es-modules/tough-cookie': 0.1.6 '@inquirer/confirm': 5.0.1(@types/node@20.17.6) - '@mswjs/interceptors': 0.36.10 + '@mswjs/interceptors': 0.37.0 '@open-draft/deferred-promise': 2.2.0 '@open-draft/until': 2.1.0 '@types/cookie': 0.6.0 @@ -19521,7 +19521,7 @@ snapshots: statuses@2.0.1: {} - std-env@3.7.0: {} + std-env@3.8.0: {} stream-browserify@3.0.0: dependencies: @@ -20147,10 +20147,11 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.2 - vite-node@2.1.4(@types/node@20.17.6)(terser@5.27.0): + vite-node@2.1.5(@types/node@20.17.6)(terser@5.27.0): dependencies: cac: 6.7.14 debug: 4.3.7(supports-color@8.1.1) + es-module-lexer: 1.5.4 pathe: 1.1.2 vite: 5.3.4(@types/node@20.17.6)(terser@5.27.0) transitivePeerDependencies: @@ -20173,32 +20174,32 @@ snapshots: fsevents: 2.3.3 terser: 5.27.0 - vitest@2.1.4(@types/node@20.17.6)(@vitest/browser@2.1.4)(@vitest/ui@2.1.4)(jsdom@24.1.3)(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0): + vitest@2.1.5(@types/node@20.17.6)(@vitest/browser@2.1.5)(@vitest/ui@2.1.5)(jsdom@24.1.3)(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(terser@5.27.0): dependencies: - '@vitest/expect': 2.1.4 - '@vitest/mocker': 2.1.4(msw@2.6.2(@types/node@20.17.6)(typescript@5.6.3))(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0)) - '@vitest/pretty-format': 2.1.4 - '@vitest/runner': 2.1.4 - '@vitest/snapshot': 2.1.4 - '@vitest/spy': 2.1.4 - '@vitest/utils': 2.1.4 + '@vitest/expect': 2.1.5 + '@vitest/mocker': 2.1.5(msw@2.6.5(@types/node@20.17.6)(typescript@5.6.3))(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0)) + '@vitest/pretty-format': 2.1.5 + '@vitest/runner': 2.1.5 + '@vitest/snapshot': 2.1.5 + '@vitest/spy': 2.1.5 + '@vitest/utils': 2.1.5 chai: 5.1.2 debug: 4.3.7(supports-color@8.1.1) expect-type: 1.1.0 magic-string: 0.30.12 pathe: 1.1.2 - std-env: 3.7.0 + std-env: 3.8.0 tinybench: 2.9.0 tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 vite: 5.3.4(@types/node@20.17.6)(terser@5.27.0) - vite-node: 2.1.4(@types/node@20.17.6)(terser@5.27.0) + vite-node: 2.1.5(@types/node@20.17.6)(terser@5.27.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.17.6 - '@vitest/browser': 2.1.4(@types/node@20.17.6)(playwright@1.48.2)(typescript@5.6.3)(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.4) - '@vitest/ui': 2.1.4(vitest@2.1.4) + '@vitest/browser': 2.1.5(@types/node@20.17.6)(playwright@1.48.2)(typescript@5.6.3)(vite@5.3.4(@types/node@20.17.6)(terser@5.27.0))(vitest@2.1.5) + '@vitest/ui': 2.1.5(vitest@2.1.5) jsdom: 24.1.3 transitivePeerDependencies: - less diff --git a/test/performance-charts/package.json b/test/performance-charts/package.json index bb79214b2c07..330b0cb2b671 100644 --- a/test/performance-charts/package.json +++ b/test/performance-charts/package.json @@ -16,11 +16,11 @@ "@testing-library/user-event": "^14.5.2", "@vitejs/plugin-react": "^4.3.3", "@vitejs/plugin-react-swc": "^3.7.1", - "@vitest/browser": "2.1.4", - "@vitest/ui": "2.1.4", + "@vitest/browser": "2.1.5", + "@vitest/ui": "2.1.5", "jsdom": "^24.1.3", "react": "^18.3.1", "react-dom": "^18.3.1", - "vitest": "2.1.4" + "vitest": "2.1.5" } } From 0da596eddc89cbf65ac5eb44c2d7d0bf5f243133 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Mon, 18 Nov 2024 15:53:37 +0100 Subject: [PATCH 5/7] [charts] Move interaction state in store (#15426) Signed-off-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Co-authored-by: Jose C Quintas Jr --- packages/x-charts/package.json | 5 +- .../ChartsAxisHighlight.tsx | 150 +----------------- .../ChartsAxisHighlight.types.ts | 6 + .../ChartsAxisHighlightPath.ts | 37 +++++ .../ChartsXAxisHighlight.tsx | 69 ++++++++ .../ChartsYAxisHighlight.tsx | 71 +++++++++ .../chartsAxisHighlightClasses.ts | 18 +++ .../x-charts/src/ChartsAxisHighlight/index.ts | 3 + .../ChartsOnAxisClickHandler.tsx | 12 +- .../src/ChartsSurface/ChartsSurface.test.tsx | 5 +- .../ChartsAxisTooltipContent.tsx | 2 +- .../ChartsItemTooltipContent.tsx | 2 +- .../src/ChartsTooltip/ChartsTooltip.tsx | 16 +- .../src/ChartsTooltip/useAxisTooltip.tsx | 49 ++++-- .../src/ChartsTooltip/useItemTooltip.tsx | 8 +- packages/x-charts/src/ChartsTooltip/utils.tsx | 2 +- .../ChartsVoronoiHandler.tsx | 40 +++-- .../src/LineChart/CircleMarkElement.tsx | 9 +- .../src/LineChart/LineHighlightPlot.tsx | 10 +- .../x-charts/src/LineChart/MarkElement.tsx | 10 +- .../x-charts/src/ScatterChart/Scatter.tsx | 9 +- .../src/context/InteractionProvider.tsx | 127 +-------------- .../src/context/InteractionSelectors.ts | 46 ++++++ packages/x-charts/src/hooks/useAxisEvents.ts | 39 ++++- .../src/hooks/useInteractionItemProps.ts | 36 ++++- .../src/internals/plugins/models/index.ts | 39 +++++ .../src/internals/plugins/utils/ChartStore.ts | 35 ++++ .../src/internals/plugins/utils/selectors.ts | 50 ++++++ packages/x-charts/src/internals/useCharts.ts | 25 +++ .../x-charts/src/internals/useSelector.ts | 23 +++ packages/x-charts/src/internals/useStore.ts | 27 ++++ pnpm-lock.yaml | 9 ++ scripts/x-charts-pro.exports.json | 1 + scripts/x-charts.exports.json | 1 + 34 files changed, 658 insertions(+), 333 deletions(-) create mode 100644 packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.types.ts create mode 100644 packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlightPath.ts create mode 100644 packages/x-charts/src/ChartsAxisHighlight/ChartsXAxisHighlight.tsx create mode 100644 packages/x-charts/src/ChartsAxisHighlight/ChartsYAxisHighlight.tsx create mode 100644 packages/x-charts/src/ChartsAxisHighlight/chartsAxisHighlightClasses.ts create mode 100644 packages/x-charts/src/context/InteractionSelectors.ts create mode 100644 packages/x-charts/src/internals/plugins/models/index.ts create mode 100644 packages/x-charts/src/internals/plugins/utils/ChartStore.ts create mode 100644 packages/x-charts/src/internals/plugins/utils/selectors.ts create mode 100644 packages/x-charts/src/internals/useCharts.ts create mode 100644 packages/x-charts/src/internals/useSelector.ts create mode 100644 packages/x-charts/src/internals/useStore.ts diff --git a/packages/x-charts/package.json b/packages/x-charts/package.json index f4f1fa97de31..f04c575f7cf4 100644 --- a/packages/x-charts/package.json +++ b/packages/x-charts/package.json @@ -46,7 +46,9 @@ "@react-spring/rafz": "^9.7.5", "@react-spring/web": "^9.7.5", "clsx": "^2.1.1", - "prop-types": "^15.8.1" + "prop-types": "^15.8.1", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.0.0" }, "peerDependencies": { "@emotion/react": "^11.9.0", @@ -71,6 +73,7 @@ "@react-spring/core": "^9.7.5", "@react-spring/shared": "^9.7.5", "@types/prop-types": "^15.7.13", + "@types/use-sync-external-store": "^0.0.6", "csstype": "^3.1.3", "rimraf": "^6.0.1" }, diff --git a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx index 5712979e916c..a53bfafff95f 100644 --- a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx +++ b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.tsx @@ -2,29 +2,10 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; -import generateUtilityClass from '@mui/utils/generateUtilityClass'; -import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; -import { styled } from '@mui/material/styles'; -import { InteractionContext } from '../context/InteractionProvider'; -import { useCartesianContext } from '../context/CartesianProvider'; -import { getValueToPositionMapper } from '../hooks/useScale'; -import { isBandScale } from '../internals/isBandScale'; - -export interface ChartsAxisHighlightClasses { - /** Styles applied to the root element. */ - root: string; -} - -export type ChartsAxisHighlightClassKey = keyof ChartsAxisHighlightClasses; - -export function getAxisHighlightUtilityClass(slot: string) { - return generateUtilityClass('MuiChartsAxisHighlight', slot); -} - -export const chartsAxisHighlightClasses: ChartsAxisHighlightClasses = generateUtilityClasses( - 'MuiChartsAxisHighlight', - ['root'], -); +import { getAxisHighlightUtilityClass } from './chartsAxisHighlightClasses'; +import ChartsYHighlight from './ChartsYAxisHighlight'; +import ChartsXHighlight from './ChartsXAxisHighlight'; +import { ChartsAxisHighlightProps } from './ChartsAxisHighlight.types'; const useUtilityClasses = () => { const slots = { @@ -34,47 +15,6 @@ const useUtilityClasses = () => { return composeClasses(slots, getAxisHighlightUtilityClass); }; -export const ChartsAxisHighlightPath = styled('path', { - name: 'MuiChartsAxisHighlight', - slot: 'Root', - overridesResolver: (_, styles) => styles.root, -})<{ ownerState: { axisHighlight: AxisHighlight } }>(({ theme }) => ({ - pointerEvents: 'none', - variants: [ - { - props: { - axisHighlight: 'band', - }, - style: { - fill: 'white', - fillOpacity: 0.1, - ...theme.applyStyles('light', { - fill: 'gray', - }), - }, - }, - { - props: { - axisHighlight: 'line', - }, - style: { - strokeDasharray: '5 2', - stroke: '#ffffff', - ...theme.applyStyles('light', { - stroke: '#000000', - }), - }, - }, - ], -})); - -type AxisHighlight = 'none' | 'line' | 'band'; - -export type ChartsAxisHighlightProps = { - x?: AxisHighlight; - y?: AxisHighlight; -}; - /** * Demos: * @@ -86,88 +26,12 @@ export type ChartsAxisHighlightProps = { */ function ChartsAxisHighlight(props: ChartsAxisHighlightProps) { const { x: xAxisHighlight, y: yAxisHighlight } = props; - const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); - const classes = useUtilityClasses(); - - const USED_X_AXIS_ID = xAxisIds[0]; - const USED_Y_AXIS_ID = yAxisIds[0]; - - const xScale = xAxis[USED_X_AXIS_ID].scale; - const yScale = yAxis[USED_Y_AXIS_ID].scale; - - const { axis } = React.useContext(InteractionContext); - - const getXPosition = getValueToPositionMapper(xScale); - const getYPosition = getValueToPositionMapper(yScale); - - const axisX = axis.x; - const axisY = axis.y; - - const isBandScaleX = xAxisHighlight === 'band' && axisX !== null && isBandScale(xScale); - const isBandScaleY = yAxisHighlight === 'band' && axisY !== null && isBandScale(yScale); - - if (process.env.NODE_ENV !== 'production') { - const isXError = isBandScaleX && xScale(axisX.value) === undefined; - const isYError = isBandScaleY && yScale(axisY.value) === undefined; - - if (isXError || isYError) { - console.error( - [ - `MUI X: The position value provided for the axis is not valid for the current scale.`, - `This probably means something is wrong with the data passed to the chart.`, - `The ChartsAxisHighlight component will not be displayed.`, - ].join('\n'), - ); - } - } + const classes = useUtilityClasses(); return ( - {isBandScaleX && xScale(axisX.value) !== undefined && ( - - )} - - {isBandScaleY && yScale(axisY.value) !== undefined && ( - - )} - - {xAxisHighlight === 'line' && axis.x !== null && ( - - )} - - {yAxisHighlight === 'line' && axis.y !== null && ( - - )} + {xAxisHighlight && } + {yAxisHighlight && } ); } diff --git a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.types.ts b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.types.ts new file mode 100644 index 000000000000..de1b75d43438 --- /dev/null +++ b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlight.types.ts @@ -0,0 +1,6 @@ +export type ChartsAxisHighlightType = 'none' | 'line' | 'band'; + +export type ChartsAxisHighlightProps = { + x?: ChartsAxisHighlightType; + y?: ChartsAxisHighlightType; +}; diff --git a/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlightPath.ts b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlightPath.ts new file mode 100644 index 000000000000..d015d2b5d15c --- /dev/null +++ b/packages/x-charts/src/ChartsAxisHighlight/ChartsAxisHighlightPath.ts @@ -0,0 +1,37 @@ +'use client'; +import { styled } from '@mui/material/styles'; +import { ChartsAxisHighlightType } from './ChartsAxisHighlight.types'; + +export const ChartsAxisHighlightPath = styled('path', { + name: 'MuiChartsAxisHighlight', + slot: 'Root', + overridesResolver: (_, styles) => styles.root, +})<{ ownerState: { axisHighlight: ChartsAxisHighlightType } }>(({ theme }) => ({ + pointerEvents: 'none', + variants: [ + { + props: { + axisHighlight: 'band', + }, + style: { + fill: 'white', + fillOpacity: 0.1, + ...theme.applyStyles('light', { + fill: 'gray', + }), + }, + }, + { + props: { + axisHighlight: 'line', + }, + style: { + strokeDasharray: '5 2', + stroke: '#ffffff', + ...theme.applyStyles('light', { + stroke: '#000000', + }), + }, + }, + ], +})); diff --git a/packages/x-charts/src/ChartsAxisHighlight/ChartsXAxisHighlight.tsx b/packages/x-charts/src/ChartsAxisHighlight/ChartsXAxisHighlight.tsx new file mode 100644 index 000000000000..d828547af94e --- /dev/null +++ b/packages/x-charts/src/ChartsAxisHighlight/ChartsXAxisHighlight.tsx @@ -0,0 +1,69 @@ +'use client'; +import * as React from 'react'; +import { getValueToPositionMapper, useXScale } from '../hooks/useScale'; +import { isBandScale } from '../internals/isBandScale'; +import { useSelector } from '../internals/useSelector'; +import { useStore } from '../internals/useStore'; +import { selectorChartsInteractionXAxis } from '../context/InteractionSelectors'; +import { useDrawingArea } from '../hooks'; +import { ChartsAxisHighlightType } from './ChartsAxisHighlight.types'; +import { ChartsAxisHighlightClasses } from './chartsAxisHighlightClasses'; +import { ChartsAxisHighlightPath } from './ChartsAxisHighlightPath'; + +/** + * @ignore - internal component. + */ +export default function ChartsXHighlight(props: { + type: ChartsAxisHighlightType; + classes: ChartsAxisHighlightClasses; +}) { + const { type, classes } = props; + + const { top, height } = useDrawingArea(); + + const xScale = useXScale(); + + const store = useStore(); + const axisX = useSelector(store, selectorChartsInteractionXAxis); + + const getXPosition = getValueToPositionMapper(xScale); + + const isBandScaleX = type === 'band' && axisX !== null && isBandScale(xScale); + + if (process.env.NODE_ENV !== 'production') { + const isError = isBandScaleX && xScale(axisX.value) === undefined; + + if (isError) { + console.error( + [ + `MUI X: The position value provided for the axis is not valid for the current scale.`, + `This probably means something is wrong with the data passed to the chart.`, + `The ChartsAxisHighlight component will not be displayed.`, + ].join('\n'), + ); + } + } + + return ( + + {isBandScaleX && xScale(axisX.value) !== undefined && ( + + )} + + {type === 'line' && axisX !== null && ( + + )} + + ); +} diff --git a/packages/x-charts/src/ChartsAxisHighlight/ChartsYAxisHighlight.tsx b/packages/x-charts/src/ChartsAxisHighlight/ChartsYAxisHighlight.tsx new file mode 100644 index 000000000000..ce996fb544df --- /dev/null +++ b/packages/x-charts/src/ChartsAxisHighlight/ChartsYAxisHighlight.tsx @@ -0,0 +1,71 @@ +'use client'; +import * as React from 'react'; +import { getValueToPositionMapper, useYScale } from '../hooks/useScale'; +import { isBandScale } from '../internals/isBandScale'; +import { useSelector } from '../internals/useSelector'; +import { useStore } from '../internals/useStore'; +import { selectorChartsInteractionYAxis } from '../context/InteractionSelectors'; +import { useDrawingArea } from '../hooks'; +import { ChartsAxisHighlightType } from './ChartsAxisHighlight.types'; +import { ChartsAxisHighlightClasses } from './chartsAxisHighlightClasses'; +import { ChartsAxisHighlightPath } from './ChartsAxisHighlightPath'; + +/** + * @ignore - internal component. + */ +export default function ChartsYHighlight(props: { + type: ChartsAxisHighlightType; + classes: ChartsAxisHighlightClasses; +}) { + const { type, classes } = props; + + const { left, width } = useDrawingArea(); + + const yScale = useYScale(); + + const store = useStore(); + const axisY = useSelector(store, selectorChartsInteractionYAxis); + + const getYPosition = getValueToPositionMapper(yScale); + + const isBandScaleY = type === 'band' && axisY !== null && isBandScale(yScale); + + if (process.env.NODE_ENV !== 'production') { + const isError = isBandScaleY && yScale(axisY.value) === undefined; + + if (isError) { + console.error( + [ + `MUI X: The position value provided for the axis is not valid for the current scale.`, + `This probably means something is wrong with the data passed to the chart.`, + `The ChartsAxisHighlight component will not be displayed.`, + ].join('\n'), + ); + } + } + + return ( + + {isBandScaleY && yScale(axisY.value) !== undefined && ( + + )} + + {type === 'line' && axisY !== null && ( + + )} + + ); +} diff --git a/packages/x-charts/src/ChartsAxisHighlight/chartsAxisHighlightClasses.ts b/packages/x-charts/src/ChartsAxisHighlight/chartsAxisHighlightClasses.ts new file mode 100644 index 000000000000..7d62c32d82fa --- /dev/null +++ b/packages/x-charts/src/ChartsAxisHighlight/chartsAxisHighlightClasses.ts @@ -0,0 +1,18 @@ +import generateUtilityClass from '@mui/utils/generateUtilityClass'; +import generateUtilityClasses from '@mui/utils/generateUtilityClasses'; + +export interface ChartsAxisHighlightClasses { + /** Styles applied to the root element. */ + root: string; +} + +export type ChartsAxisHighlightClassKey = keyof ChartsAxisHighlightClasses; + +export function getAxisHighlightUtilityClass(slot: string) { + return generateUtilityClass('MuiChartsAxisHighlight', slot); +} + +export const chartsAxisHighlightClasses: ChartsAxisHighlightClasses = generateUtilityClasses( + 'MuiChartsAxisHighlight', + ['root'], +); diff --git a/packages/x-charts/src/ChartsAxisHighlight/index.ts b/packages/x-charts/src/ChartsAxisHighlight/index.ts index 14c071e360be..653afd1cfd87 100644 --- a/packages/x-charts/src/ChartsAxisHighlight/index.ts +++ b/packages/x-charts/src/ChartsAxisHighlight/index.ts @@ -1 +1,4 @@ export * from './ChartsAxisHighlight'; +export * from './chartsAxisHighlightClasses'; +export * from './ChartsAxisHighlight.types'; +export * from './ChartsAxisHighlightPath'; diff --git a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx index 8c26ff5650e6..a5a7d65b0ab7 100644 --- a/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx +++ b/packages/x-charts/src/ChartsOnAxisClickHandler/ChartsOnAxisClickHandler.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { InteractionContext } from '../context/InteractionProvider'; +import { useStore } from '../internals/useStore'; import { useSeries } from '../hooks/useSeries'; import { useSvgRef } from '../hooks'; import { useCartesianContext } from '../context/CartesianProvider'; @@ -27,7 +27,8 @@ function ChartsOnAxisClickHandler(props: ChartsOnAxisClickHandlerProps) { const svgRef = useSvgRef(); const series = useSeries(); - const { axis } = React.useContext(InteractionContext); + const store = useStore(); + const { xAxisIds, xAxis, yAxisIds, yAxis } = useCartesianContext(); React.useEffect(() => { @@ -39,9 +40,10 @@ function ChartsOnAxisClickHandler(props: ChartsOnAxisClickHandlerProps) { const handleMouseClick = (event: MouseEvent) => { event.preventDefault(); - const isXaxis = axis.x && axis.x.index !== -1; + const { x: axisX, y: axisY } = store.value.interaction.axis; + const isXaxis = axisX && axisX.index !== -1; const USED_AXIS_ID = isXaxis ? xAxisIds[0] : yAxisIds[0]; - const dataIndex = isXaxis ? axis.x && axis.x.index : axis.y && axis.y.index; + const dataIndex = isXaxis ? axisX && axisX.index : axisY && axisY.index; if (dataIndex == null) { return; @@ -72,7 +74,7 @@ function ChartsOnAxisClickHandler(props: ChartsOnAxisClickHandlerProps) { return () => { element.removeEventListener('click', handleMouseClick); }; - }, [axis.x, axis.y, onAxisClick, series, svgRef, xAxis, xAxisIds, yAxis, yAxisIds]); + }, [onAxisClick, series, store, svgRef, xAxis, xAxisIds, yAxis, yAxisIds]); // eslint-disable-next-line react/jsx-no-useless-fragment return ; diff --git a/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx b/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx index f9bd7b41068c..8a61ef8212f6 100644 --- a/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx +++ b/packages/x-charts/src/ChartsSurface/ChartsSurface.test.tsx @@ -19,7 +19,10 @@ describe('', () => { render( - + diff --git a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx index 28b6f6f833e0..ed4f1a6608b4 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsAxisTooltipContent.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { SxProps, Theme } from '@mui/material/styles'; import useSlotProps from '@mui/utils/useSlotProps'; -import { AxisInteractionData } from '../context/InteractionProvider'; +import { AxisInteractionData } from '../internals/plugins/models'; import { useCartesianContext } from '../context/CartesianProvider'; import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; import { AxisDefaultized } from '../models/axis'; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx index 30140400a948..8d374db974f7 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsItemTooltipContent.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { SxProps, Theme } from '@mui/material/styles'; import useSlotProps from '@mui/utils/useSlotProps'; -import { ItemInteractionData } from '../context/InteractionProvider'; +import { ItemInteractionData } from '../internals/plugins/models'; import { ChartSeriesDefaultized, ChartSeriesType } from '../models/seriesType/config'; import { ChartsTooltipClasses } from './chartsTooltipClasses'; import { DefaultChartsItemTooltipContent } from './DefaultChartsItemTooltipContent'; diff --git a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx index 560a83ccc9a4..544dac733866 100644 --- a/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/ChartsTooltip.tsx @@ -7,17 +7,19 @@ 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 { - AxisInteractionData, - InteractionContext, - ItemInteractionData, -} from '../context/InteractionProvider'; 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'; export type PopperProps = BasePopperProps & { /** @@ -137,7 +139,9 @@ function ChartsTooltip(inProps: ChartsTooltipProps const positionRef = useLazyRef(() => ({ x: 0, y: 0 })); - const { item, axis } = React.useContext(InteractionContext); + const store = useStore(); + const item = useSelector(store, selectorChartsInteractionItem); + const axis = useSelector(store, selectorChartsInteractionAxis); const displayedData = trigger === 'item' ? item : axis; diff --git a/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx b/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx index 109665b90e5d..aff76dca6187 100644 --- a/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/useAxisTooltip.tsx @@ -1,6 +1,5 @@ 'use client'; import * as React from 'react'; -import { AxisInteractionData, InteractionContext } from '../context/InteractionProvider'; import { useSeries } from '../hooks/useSeries'; import { useCartesianContext } from '../context/CartesianProvider'; import { ZAxisContext } from '../context/ZAxisContextProvider'; @@ -10,6 +9,15 @@ import { CartesianChartSeriesType, ChartsSeriesConfig } from '../models/seriesTy import { getLabel } from '../internals/getLabel'; import { isCartesianSeriesType } from '../internals/isCartesian'; import { utcFormatter } from './utils'; +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, @@ -30,26 +38,35 @@ interface SeriesItem { } export function useAxisTooltip(): null | UseAxisTooltipReturnValue { - const { axis } = React.useContext(InteractionContext); + const defaultXAxis = useXAxis(); + const defaultYAxis = useYAxis(); + + 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, + ); + const series = useSeries(); - const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); + const { xAxis, yAxis } = useCartesianContext(); + const { zAxis, zAxisIds } = React.useContext(ZAxisContext); const colorProcessors = useColorProcessor(); - // By default use the x-axis - const isXaxis = axis.x !== null && axis.x.index !== -1; - - const axisData = isXaxis ? axis.x && axis.x : axis.y && axis.y; - if (axisData === null) { return null; } const { index: dataIndex, value: axisValue } = axisData; - const USED_AXIS_ID = isXaxis ? xAxisIds[0] : yAxisIds[0]; - const usedAxis = isXaxis ? xAxis[USED_AXIS_ID] : yAxis[USED_AXIS_ID]; + const USED_AXIS_ID = xAxisHasData ? defaultXAxis.id : defaultYAxis.id; + const usedAxis = xAxisHasData ? defaultXAxis : defaultYAxis; const relevantSeries = Object.keys(series) .filter(isCartesianSeriesType) @@ -64,20 +81,20 @@ export function useAxisTooltip(): null | UseAxisTooltipReturnValue { const providedXAxisId = seriesToAdd.xAxisId; const providedYAxisId = seriesToAdd.yAxisId; - const axisKey = isXaxis ? providedXAxisId : providedYAxisId; + const axisKey = xAxisHasData ? providedXAxisId : providedYAxisId; // Test if the series uses the default axis if (axisKey === undefined || axisKey === USED_AXIS_ID) { - const xAxisId = providedXAxisId ?? xAxisIds[0]; - const yAxisId = providedYAxisId ?? yAxisIds[0]; - const zAxisId = (seriesToAdd as any).zAxisId ?? zAxisIds[0]; + const xAxisId = providedXAxisId ?? defaultXAxis.id; + const yAxisId = providedYAxisId ?? defaultYAxis.id; + const zAxisId = 'zAxisId' in seriesToAdd ? seriesToAdd.zAxisId : zAxisIds[0]; const color = colorProcessors[seriesType]?.( seriesToAdd, xAxis[xAxisId], yAxis[yAxisId], - zAxisId && zAxis[zAxisId], + zAxisId ? zAxis[zAxisId] : undefined, )(dataIndex) ?? ''; const value = seriesToAdd.data[dataIndex] ?? null; @@ -107,7 +124,7 @@ export function useAxisTooltip(): null | UseAxisTooltipReturnValue { const axisFormattedValue = axisFormatter(axisValue, { location: 'tooltip' }); return { - identifier: axis as AxisInteractionData, + identifier: axis, seriesItems: relevantSeries, axisValue, axisFormattedValue, diff --git a/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx b/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx index a3ab97c287b1..96023ae1b272 100644 --- a/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx +++ b/packages/x-charts/src/ChartsTooltip/useItemTooltip.tsx @@ -1,6 +1,5 @@ 'use client'; import * as React from 'react'; -import { InteractionContext, ItemInteractionData } from '../context/InteractionProvider'; import { useSeries } from '../hooks/useSeries'; import { useCartesianContext } from '../context/CartesianProvider'; import { ZAxisContext } from '../context/ZAxisContextProvider'; @@ -12,6 +11,10 @@ import { } from '../models/seriesType/config'; import { getLabel } from '../internals/getLabel'; import { CommonSeriesType } from '../models/seriesType/common'; +import { selectorChartsInteractionItem } from '../context/InteractionSelectors'; +import { useSelector } from '../internals/useSelector'; +import { useStore } from '../internals/useStore'; +import { ItemInteractionData } from '../internals/plugins/models'; export interface UseItemTooltipReturnValue { identifier: ItemInteractionData; @@ -22,7 +25,8 @@ export interface UseItemTooltipReturnValue { } export function useItemTooltip(): null | UseItemTooltipReturnValue { - const { item } = React.useContext(InteractionContext); + const stroe = useStore(); + const item = useSelector(stroe, 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 227c7f58e24e..6964b5ef3e45 100644 --- a/packages/x-charts/src/ChartsTooltip/utils.tsx +++ b/packages/x-charts/src/ChartsTooltip/utils.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { AxisInteractionData, ItemInteractionData } from '../context/InteractionProvider'; +import { AxisInteractionData, ItemInteractionData } from '../internals/plugins/models'; import { ChartSeriesType } from '../models/seriesType/config'; import { useSvgRef } from '../hooks'; diff --git a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx index ad1dea102fc6..f0169fb95025 100644 --- a/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx +++ b/packages/x-charts/src/ChartsVoronoiHandler/ChartsVoronoiHandler.tsx @@ -3,9 +3,9 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { Delaunay } from '@mui/x-charts-vendor/d3-delaunay'; import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; -import { InteractionContext } from '../context/InteractionProvider'; import { useCartesianContext } from '../context/CartesianProvider'; import { getValueToPositionMapper } from '../hooks/useScale'; +import { useStore } from '../internals/useStore'; import { getSVGPoint } from '../internals/getSVGPoint'; import { ScatterItemIdentifier } from '../models'; import { SeriesId } from '../models/seriesType/common'; @@ -34,7 +34,7 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { const svgRef = useSvgRef(); const drawingArea = useDrawingArea(); const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); - const { dispatch } = React.useContext(InteractionContext); + const store = useStore(); const { series, seriesOrder } = useScatterSeries() ?? {}; const voronoiRef = React.useRef>({}); @@ -47,11 +47,18 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { const defaultYAxisId = yAxisIds[0]; useEnhancedEffect(() => { - dispatch({ type: 'updateVoronoiUsage', useVoronoiInteraction: true }); + store.update((prev) => ({ + ...prev, + interaction: { ...prev.interaction, useVoronoiInteraction: true }, + })); + return () => { - dispatch({ type: 'updateVoronoiUsage', useVoronoiInteraction: false }); + store.update((prev) => ({ + ...prev, + interaction: { ...prev.interaction, useVoronoiInteraction: false }, + })); }; - }, [dispatch]); + }, [store]); useEnhancedEffect(() => { // This effect generate and store the Delaunay object that's used to map coordinate to closest point. @@ -153,7 +160,10 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { } const handleMouseLeave = () => { - dispatch({ type: 'exitChart' }); + store.update((prev) => ({ + ...prev, + interaction: { ...prev.interaction, axis: { x: null, y: null }, item: null }, + })); clearHighlighted(); }; @@ -161,19 +171,29 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { const closestPoint = getClosestPoint(event); if (closestPoint === 'outside-chart') { - dispatch({ type: 'exitChart' }); + store.update((prev) => ({ + ...prev, + interaction: { ...prev.interaction, axis: { x: null, y: null }, item: null }, + })); clearHighlighted(); return; } if (closestPoint === 'outside-voronoi-max-radius' || closestPoint === 'no-point-found') { - dispatch({ type: 'leaveItem', data: { type: 'scatter' } }); + store.update((prev) => ({ + ...prev, + interaction: { ...prev.interaction, item: null }, + })); clearHighlighted(); return; } const { seriesId, dataIndex } = closestPoint; - dispatch({ type: 'enterItem', data: { type: 'scatter', seriesId, dataIndex } }); + store.update((prev) => ({ + ...prev, + interaction: { ...prev.interaction, item: { type: 'scatter', seriesId, dataIndex } }, + })); + setHighlighted({ seriesId, dataIndex, @@ -205,7 +225,6 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { }; }, [ svgRef, - dispatch, yAxis, xAxis, voronoiMaxRadius, @@ -213,6 +232,7 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) { setHighlighted, clearHighlighted, drawingArea, + store, ]); // eslint-disable-next-line react/jsx-no-useless-fragment diff --git a/packages/x-charts/src/LineChart/CircleMarkElement.tsx b/packages/x-charts/src/LineChart/CircleMarkElement.tsx index 584c15bab4d8..ddc1608cc44c 100644 --- a/packages/x-charts/src/LineChart/CircleMarkElement.tsx +++ b/packages/x-charts/src/LineChart/CircleMarkElement.tsx @@ -4,10 +4,12 @@ import PropTypes from 'prop-types'; import { useTheme } from '@mui/material/styles'; import { warnOnce } from '@mui/x-internals/warning'; import { animated, useSpring } from '@react-spring/web'; -import { InteractionContext } from '../context/InteractionProvider'; import { useInteractionItemProps } from '../hooks/useInteractionItemProps'; import { useItemHighlighted } from '../context'; import { MarkElementOwnerState, useUtilityClasses } from './markElementClasses'; +import { useSelector } from '../internals/useSelector'; +import { selectorChartsInteractionXAxis } from '../context/InteractionSelectors'; +import { useStore } from '../internals/useStore'; export type CircleMarkElementProps = Omit & Omit, 'ref' | 'id'> & { @@ -66,13 +68,14 @@ function CircleMarkElement(props: CircleMarkElementProps) { const { isFaded, isHighlighted } = useItemHighlighted({ seriesId: id, }); - const { axis } = React.useContext(InteractionContext); + const store = useStore(); + const xAxisIdentifier = useSelector(store, selectorChartsInteractionXAxis); const position = useSpring({ to: { x, y }, immediate: skipAnimation }); const ownerState = { id, classes: innerClasses, - isHighlighted: axis.x?.index === dataIndex || isHighlighted, + isHighlighted: xAxisIdentifier?.index === dataIndex || isHighlighted, isFaded, color, }; diff --git a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx index a5911052eb10..7c6e30437bd0 100644 --- a/packages/x-charts/src/LineChart/LineHighlightPlot.tsx +++ b/packages/x-charts/src/LineChart/LineHighlightPlot.tsx @@ -5,11 +5,13 @@ import { SlotComponentPropsFromProps } from '@mui/x-internals/types'; import { useCartesianContext } from '../context/CartesianProvider'; import { LineHighlightElement, LineHighlightElementProps } from './LineHighlightElement'; import { getValueToPositionMapper } from '../hooks/useScale'; -import { InteractionContext } from '../context/InteractionProvider'; import { DEFAULT_X_AXIS_KEY } from '../constants'; 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; @@ -48,9 +50,11 @@ function LineHighlightPlot(props: LineHighlightPlotProps) { const seriesData = useLineSeries(); const axisData = useCartesianContext(); const drawingArea = useDrawingArea(); - const { axis } = React.useContext(InteractionContext); + const store = useStore(); + const xAxisIdentifier = useSelector(store, selectorChartsInteractionXAxis); + + const highlightedIndex = xAxisIdentifier?.index; - const highlightedIndex = axis.x?.index; if (highlightedIndex === undefined) { return null; } diff --git a/packages/x-charts/src/LineChart/MarkElement.tsx b/packages/x-charts/src/LineChart/MarkElement.tsx index 93a77ca25e25..a3d9d6f93857 100644 --- a/packages/x-charts/src/LineChart/MarkElement.tsx +++ b/packages/x-charts/src/LineChart/MarkElement.tsx @@ -5,10 +5,12 @@ import { styled } from '@mui/material/styles'; import { symbol as d3Symbol, symbolsFill as d3SymbolsFill } from '@mui/x-charts-vendor/d3-shape'; import { animated, to, useSpring } from '@react-spring/web'; import { getSymbol } from '../internals/getSymbol'; -import { InteractionContext } from '../context/InteractionProvider'; import { useInteractionItemProps } from '../hooks/useInteractionItemProps'; import { useItemHighlighted } from '../context'; import { MarkElementOwnerState, useUtilityClasses } from './markElementClasses'; +import { selectorChartsInteractionXAxis } from '../context/InteractionSelectors'; +import { useSelector } from '../internals/useSelector'; +import { useStore } from '../internals/useStore'; const MarkElementPath = styled(animated.path, { name: 'MuiMarkElement', @@ -65,13 +67,15 @@ function MarkElement(props: MarkElementProps) { const { isFaded, isHighlighted } = useItemHighlighted({ seriesId: id, }); - const { axis } = React.useContext(InteractionContext); + + const store = useStore(); + const xAxisIdentifier = useSelector(store, selectorChartsInteractionXAxis); const position = useSpring({ to: { x, y }, immediate: skipAnimation }); const ownerState = { id, classes: innerClasses, - isHighlighted: axis.x?.index === dataIndex || isHighlighted, + isHighlighted: xAxisIdentifier?.index === dataIndex || isHighlighted, isFaded, color, }; diff --git a/packages/x-charts/src/ScatterChart/Scatter.tsx b/packages/x-charts/src/ScatterChart/Scatter.tsx index 74aea129dc00..b6a95e703587 100644 --- a/packages/x-charts/src/ScatterChart/Scatter.tsx +++ b/packages/x-charts/src/ScatterChart/Scatter.tsx @@ -8,10 +8,12 @@ import { } from '../models/seriesType/scatter'; import { getValueToPositionMapper } from '../hooks/useScale'; import { useInteractionItemProps } from '../hooks/useInteractionItemProps'; -import { InteractionContext } from '../context/InteractionProvider'; 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; @@ -46,9 +48,10 @@ function Scatter(props: ScatterProps) { const drawingArea = useDrawingArea(); - const { useVoronoiInteraction } = React.useContext(InteractionContext); + const store = useStore(); + const isVoronoiEnabled = useSelector(store, selectorChartsInteractionIsVoronoiEnabled); - const skipInteractionHandlers = useVoronoiInteraction || series.disableHover; + const skipInteractionHandlers = isVoronoiEnabled || series.disableHover; const getInteractionItemProps = useInteractionItemProps(skipInteractionHandlers); const { isFaded, isHighlighted } = useHighlighted(); diff --git a/packages/x-charts/src/context/InteractionProvider.tsx b/packages/x-charts/src/context/InteractionProvider.tsx index 80c4658bfc1f..f31eac1c155d 100644 --- a/packages/x-charts/src/context/InteractionProvider.tsx +++ b/packages/x-charts/src/context/InteractionProvider.tsx @@ -1,132 +1,19 @@ 'use client'; import * as React from 'react'; -import { ChartItemIdentifier, ChartSeriesType } from '../models/seriesType/config'; +import { useCharts } from '../internals/useCharts'; +import { ChartStore } from '../internals/plugins/utils/ChartStore'; -export interface InteractionProviderProps { - children: React.ReactNode; -} - -export type ItemInteractionData = ChartItemIdentifier; - -export type AxisInteractionData = { - x: null | { - value: number | Date | string; - // Set to -1 if no index. - index: number; - }; - y: null | { - value: number | Date | string; - // Set to -1 if no index. - index: number; - }; -}; - -type InteractionActions = - | { - type: 'enterItem'; - data: ItemInteractionData; - } - | { - type: 'leaveItem'; - data: Partial>; - } - | { - type: 'exitChart'; - } - | { - type: 'updateVoronoiUsage'; - useVoronoiInteraction: boolean; - } - | { - type: 'updateAxis'; - data: AxisInteractionData; - }; - -type InteractionState = { - /** - * The item currently interacting. - */ - item: null | ItemInteractionData; - /** - * The x- and y-axes currently interacting. - */ - axis: AxisInteractionData; - /** - * Set to `true` when `VoronoiHandler` is active. - * Used to prevent collision with mouseEnter events. - */ - useVoronoiInteraction: boolean; - dispatch: React.Dispatch; -}; - -export const InteractionContext = React.createContext({ - item: null, - axis: { x: null, y: null }, - useVoronoiInteraction: false, - dispatch: () => null, -}); +export const ChartsContext = React.createContext<{ store: ChartStore } | null>(null); if (process.env.NODE_ENV !== 'production') { - InteractionContext.displayName = 'InteractionContext'; + ChartsContext.displayName = 'ChartsContext'; } -const dataReducer: React.Reducer, InteractionActions> = ( - prevState, - action, -) => { - switch (action.type) { - case 'enterItem': - return { ...prevState, item: action.data }; - - case 'exitChart': - if (prevState.item === null && prevState.axis.x === null && prevState.axis.y === null) { - return prevState; - } - return { ...prevState, axis: { x: null, y: null }, item: null }; - - case 'updateVoronoiUsage': - return { ...prevState, useVoronoiInteraction: action.useVoronoiInteraction }; - - case 'leaveItem': - if ( - prevState.item === null || - (Object.keys(action.data) as (keyof ItemInteractionData)[]).some( - (key) => action.data[key] !== prevState.item![key], - ) - ) { - // The item is already something else - return prevState; - } - return { ...prevState, item: null }; - - case 'updateAxis': - if (action.data.x === prevState.axis.x && action.data.y === prevState.axis.y) { - return prevState; - } - return { ...prevState, axis: action.data }; - - default: - return prevState; - } -}; - -function InteractionProvider(props: InteractionProviderProps) { +function InteractionProvider(props: React.PropsWithChildren) { const { children } = props; - const [data, dispatch] = React.useReducer(dataReducer, { - item: null, - axis: { x: null, y: null }, - useVoronoiInteraction: false, - }); - - const value = React.useMemo( - () => ({ - ...data, - dispatch, - }), - [data], - ); - return {children}; + const { contextValue } = useCharts(); + return {children}; } export { InteractionProvider }; diff --git a/packages/x-charts/src/context/InteractionSelectors.ts b/packages/x-charts/src/context/InteractionSelectors.ts new file mode 100644 index 000000000000..c911baeae216 --- /dev/null +++ b/packages/x-charts/src/context/InteractionSelectors.ts @@ -0,0 +1,46 @@ +import { ChartState } from '../internals/plugins/models'; +import { createSelector } from '../internals/plugins/utils/selectors'; + +function selectInteraction(state: ChartState) { + return state.interaction; +} + +export const selectorChartsInteractionItem = createSelector( + selectInteraction, + (interaction) => interaction.item, +); + +export const selectorChartsInteractionAxis = createSelector( + selectInteraction, + (interaction) => interaction.axis, +); + +export const selectorChartsInteractionXAxis = createSelector( + selectInteraction, + (interaction) => interaction.axis.x, +); + +export const selectorChartsInteractionYAxis = createSelector( + selectInteraction, + (interaction) => interaction.axis.y, +); + +export const selectorChartsInteractionItemIsDefined = createSelector( + selectorChartsInteractionItem, + (item) => item !== null, +); + +export const selectorChartsInteractionXAxisIsDefined = createSelector( + selectorChartsInteractionXAxis, + (x) => x !== null, +); + +export const selectorChartsInteractionYAxisIsDefined = createSelector( + selectorChartsInteractionYAxis, + (y) => y !== null, +); + +export const selectorChartsInteractionIsVoronoiEnabled = createSelector( + selectInteraction, + (interaction) => interaction.isVoronoiEnabled, +); diff --git a/packages/x-charts/src/hooks/useAxisEvents.ts b/packages/x-charts/src/hooks/useAxisEvents.ts index f3973f3fb393..2860ba00e32e 100644 --- a/packages/x-charts/src/hooks/useAxisEvents.ts +++ b/packages/x-charts/src/hooks/useAxisEvents.ts @@ -1,12 +1,12 @@ 'use client'; import * as React from 'react'; -import { InteractionContext } from '../context/InteractionProvider'; import { useCartesianContext } from '../context/CartesianProvider'; import { isBandScale } from '../internals/isBandScale'; import { AxisDefaultized } from '../models/axis'; import { getSVGPoint } from '../internals/getSVGPoint'; import { useSvgRef } from './useSvgRef'; import { useDrawingArea } from './useDrawingArea'; +import { useStore } from '../internals/useStore'; function getAsANumber(value: number | Date) { return value instanceof Date ? value.getTime() : value; @@ -15,7 +15,8 @@ export const useAxisEvents = (disableAxisListener: boolean) => { const svgRef = useSvgRef(); const drawingArea = useDrawingArea(); const { xAxis, yAxis, xAxisIds, yAxisIds } = useCartesianContext(); - const { dispatch } = React.useContext(InteractionContext); + + const store = useStore(disableAxisListener); const usedXAxis = xAxisIds[0]; const usedYAxis = yAxisIds[0]; @@ -29,7 +30,7 @@ export const useAxisEvents = (disableAxisListener: boolean) => { React.useEffect(() => { const element = svgRef.current; - if (element === null || disableAxisListener) { + if (element === null || disableAxisListener || !store) { return () => {}; } @@ -100,7 +101,11 @@ export const useAxisEvents = (disableAxisListener: boolean) => { x: -1, y: -1, }; - dispatch({ type: 'exitChart' }); + + store.update((prev) => ({ + ...prev, + interaction: { item: null, axis: { x: null, y: null } }, + })); }; const handleMove = (event: MouseEvent | TouchEvent) => { @@ -112,7 +117,10 @@ export const useAxisEvents = (disableAxisListener: boolean) => { if (!drawingArea.isPointInside(svgPoint, { targetElement: event.target as SVGElement })) { if (mousePosition.current.isInChart) { - dispatch({ type: 'exitChart' }); + store.update((prev) => ({ + ...prev, + interaction: { item: null, axis: { x: null, y: null } }, + })); mousePosition.current.isInChart = false; } return; @@ -121,7 +129,24 @@ export const useAxisEvents = (disableAxisListener: boolean) => { const newStateX = getNewAxisState(xAxis[usedXAxis], svgPoint.x); const newStateY = getNewAxisState(yAxis[usedYAxis], svgPoint.y); - dispatch({ type: 'updateAxis', data: { x: newStateX, y: newStateY } }); + store.update((prev) => ({ + ...prev, + interaction: { + ...prev.interaction, + axis: { + // A bit verbose, but prevent losing the x value if only y got modified. + ...prev.interaction.axis, + ...(prev.interaction.axis.x?.index !== newStateX?.index || + prev.interaction.axis.x?.value !== newStateX?.value + ? { x: newStateX } + : {}), + ...(prev.interaction.axis.y?.index !== newStateY?.index || + prev.interaction.axis.y?.value !== newStateY?.value + ? { y: newStateY } + : {}), + }, + }, + })); }; const handleDown = (event: PointerEvent) => { @@ -147,5 +172,5 @@ export const useAxisEvents = (disableAxisListener: boolean) => { element.removeEventListener('pointercancel', handleOut); element.removeEventListener('pointerleave', handleOut); }; - }, [svgRef, dispatch, usedYAxis, yAxis, usedXAxis, xAxis, disableAxisListener, drawingArea]); + }, [svgRef, store, usedYAxis, yAxis, usedXAxis, xAxis, disableAxisListener, drawingArea]); }; diff --git a/packages/x-charts/src/hooks/useInteractionItemProps.ts b/packages/x-charts/src/hooks/useInteractionItemProps.ts index 49a6e5e70c90..7474425fe650 100644 --- a/packages/x-charts/src/hooks/useInteractionItemProps.ts +++ b/packages/x-charts/src/hooks/useInteractionItemProps.ts @@ -1,11 +1,11 @@ 'use client'; import * as React from 'react'; -import { InteractionContext } from '../context/InteractionProvider'; import { SeriesItemIdentifier } from '../models'; import { useHighlighted } from '../context'; +import { useStore } from '../internals/useStore'; export const useInteractionItemProps = (skip?: boolean) => { - const { dispatch: dispatchInteraction } = React.useContext(InteractionContext); + const store = useStore(); const { setHighlighted, clearHighlighted } = useHighlighted(); if (skip) { @@ -18,10 +18,13 @@ export const useInteractionItemProps = (skip?: boolean) => { } }; const onPointerEnter = () => { - dispatchInteraction({ - type: 'enterItem', - data, - }); + store.update((prev) => ({ + ...prev, + interaction: { + ...prev.interaction, + item: data, + }, + })); setHighlighted({ seriesId: data.seriesId, dataIndex: data.dataIndex, @@ -29,7 +32,26 @@ export const useInteractionItemProps = (skip?: boolean) => { }; const onPointerLeave = (event: React.PointerEvent) => { event.currentTarget.releasePointerCapture(event.pointerId); - dispatchInteraction({ type: 'leaveItem', data }); + + store.update((prev) => { + const prevItem = prev.interaction.item; + if ( + prevItem === null || + Object.keys(data).some( + (key) => data[key as keyof typeof data] !== prevItem[key as keyof typeof prevItem], + ) + ) { + // The item is already something else, no need to clean it. + return prev; + } + return { + ...prev, + interaction: { + ...prev.interaction, + item: null, + }, + }; + }); clearHighlighted(); }; return { diff --git a/packages/x-charts/src/internals/plugins/models/index.ts b/packages/x-charts/src/internals/plugins/models/index.ts new file mode 100644 index 000000000000..ba5ae5bd5f5f --- /dev/null +++ b/packages/x-charts/src/internals/plugins/models/index.ts @@ -0,0 +1,39 @@ +import { ChartItemIdentifier, ChartSeriesType } from '../../../models/seriesType/config'; + +export type ItemInteractionData = ChartItemIdentifier; + +export type AxisInteractionData = { + x: null | { + value: number | Date | string; + // Set to -1 if no index. + index: number; + }; + y: null | { + value: number | Date | string; + // Set to -1 if no index. + index: number; + }; +}; + +type InteractionState = { + /** + * The item currently interacting. + */ + item: null | ItemInteractionData; + /** + * The x- and y-axes currently interacting. + */ + axis: AxisInteractionData; + /** + * Set to `true` when `VoronoiHandler` is active. + * Used to prevent collision with mouseEnter events. + */ + isVoronoiEnabled?: boolean; +}; + +export type ChartStateCacheKey = { id: number }; + +export type ChartState = { + interaction: InteractionState; + cacheKey: ChartStateCacheKey; +}; diff --git a/packages/x-charts/src/internals/plugins/utils/ChartStore.ts b/packages/x-charts/src/internals/plugins/utils/ChartStore.ts new file mode 100644 index 000000000000..f4cdbc2324d9 --- /dev/null +++ b/packages/x-charts/src/internals/plugins/utils/ChartStore.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 ChartStore { + 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/plugins/utils/selectors.ts b/packages/x-charts/src/internals/plugins/utils/selectors.ts new file mode 100644 index 000000000000..a91ac4a1a0fa --- /dev/null +++ b/packages/x-charts/src/internals/plugins/utils/selectors.ts @@ -0,0 +1,50 @@ +import { lruMemoize, createSelectorCreator, CreateSelectorFunction } from 'reselect'; +import { ChartState, ChartStateCacheKey } from '../models'; + +const reselectCreateSelector = createSelectorCreator({ + memoize: lruMemoize, + memoizeOptions: { + maxSize: 1, + equalityCheck: Object.is, + }, +}); + +const cache = new WeakMap< + ChartStateCacheKey, + Map, any> +>(); + +export type ChartsRootSelector = (state: ChartState) => ChartState[keyof ChartState]; + +export type ChartsSelector = (state: TState, args: TArgs) => TResult; + +/** + * Method wrapping reselect's createSelector to provide caching for chart instances. + * + */ +export const createSelector = ((...createSelectorArgs: any) => { + const selector: ChartsSelector = (state, selectorArgs) => { + const cacheKey = state.cacheKey; + + // If there is no cache for the current chart instance, create one. + let cacheForCurrentChartInstance = cache.get(cacheKey); + if (!cacheForCurrentChartInstance) { + cacheForCurrentChartInstance = new Map(); + cache.set(cacheKey, cacheForCurrentChartInstance); + } + + // If there is a cached selector, execute it. + const cachedSelector = cacheForCurrentChartInstance.get(createSelectorArgs); + if (cachedSelector) { + return cachedSelector(state, selectorArgs); + } + + // Otherwise, create a new selector and cache it and execute it. + const fn = reselectCreateSelector(...createSelectorArgs); + cacheForCurrentChartInstance.set(createSelectorArgs, fn); + + return fn(state, selectorArgs); + }; + + return selector; +}) as unknown as CreateSelectorFunction; diff --git a/packages/x-charts/src/internals/useCharts.ts b/packages/x-charts/src/internals/useCharts.ts new file mode 100644 index 000000000000..dddafa853ba8 --- /dev/null +++ b/packages/x-charts/src/internals/useCharts.ts @@ -0,0 +1,25 @@ +import * as React from 'react'; +import { ChartStore } from './plugins/utils/ChartStore'; +import { ChartState } from './plugins/models'; + +let globalId = 0; + +export function useCharts() { + const storeRef = React.useRef(null); + if (storeRef.current == null) { + // eslint-disable-next-line react-compiler/react-compiler + globalId += 1; + const initialState: ChartState = { + interaction: { + item: null, + axis: { x: null, y: null }, + }, + cacheKey: { id: globalId }, + }; + storeRef.current = new ChartStore(initialState); + } + + const contextValue = React.useMemo(() => ({ store: storeRef.current as ChartStore }), []); + + return { contextValue }; +} diff --git a/packages/x-charts/src/internals/useSelector.ts b/packages/x-charts/src/internals/useSelector.ts new file mode 100644 index 000000000000..b4940ae5c8d3 --- /dev/null +++ b/packages/x-charts/src/internals/useSelector.ts @@ -0,0 +1,23 @@ +import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector'; +import { ChartState } from './plugins/models'; +import { ChartsSelector } from './plugins/utils/selectors'; +import { ChartStore } from './plugins/utils/ChartStore'; + +const defaultCompare = Object.is; + +export const useSelector = ( + store: ChartStore, + selector: ChartsSelector, + args: TArgs = undefined as TArgs, + equals: (a: TValue, b: TValue) => boolean = defaultCompare, +): TValue => { + const selectorWithArgs = (state: ChartState) => selector(state, args); + + return useSyncExternalStoreWithSelector( + store.subscribe, + store.getSnapshot, + store.getSnapshot, + selectorWithArgs, + equals, + ); +}; diff --git a/packages/x-charts/src/internals/useStore.ts b/packages/x-charts/src/internals/useStore.ts new file mode 100644 index 000000000000..17e6d3b6316f --- /dev/null +++ b/packages/x-charts/src/internals/useStore.ts @@ -0,0 +1,27 @@ +import * as React from 'react'; +import { ChartsContext } from '../context/InteractionProvider'; +import { ChartStore } from './plugins/utils/ChartStore'; + +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. + // Will be fixed when every thing move to the store since every component will have access to it. + // @ts-ignore + return charts?.store; + } + if (!charts) { + throw new Error( + [ + 'MUI X: Could not find the charts context.', + 'It looks like you rendered your component outside of a ChartsContainer parent component.', + ].join('\n'), + ); + } + + return charts.store; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 12dfa325544c..94b2fc4488a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -769,6 +769,12 @@ importers: react-dom: specifier: ^17.0.0 || ^18.0.0 version: 18.3.1(react@18.3.1) + reselect: + specifier: ^5.1.1 + version: 5.1.1 + use-sync-external-store: + specifier: ^1.0.0 + version: 1.2.2(react@18.3.1) devDependencies: '@mui/internal-test-utils': specifier: ^1.0.20 @@ -788,6 +794,9 @@ importers: '@types/prop-types': specifier: ^15.7.13 version: 15.7.13 + '@types/use-sync-external-store': + specifier: ^0.0.6 + version: 0.0.6 csstype: specifier: ^3.1.3 version: 3.1.3 diff --git a/scripts/x-charts-pro.exports.json b/scripts/x-charts-pro.exports.json index ca4a94f205c2..faae92e438c1 100644 --- a/scripts/x-charts-pro.exports.json +++ b/scripts/x-charts-pro.exports.json @@ -68,6 +68,7 @@ { "name": "ChartsAxisHighlightClassKey", "kind": "TypeAlias" }, { "name": "ChartsAxisHighlightPath", "kind": "Variable" }, { "name": "ChartsAxisHighlightProps", "kind": "TypeAlias" }, + { "name": "ChartsAxisHighlightType", "kind": "TypeAlias" }, { "name": "ChartsAxisProps", "kind": "Interface" }, { "name": "ChartsAxisTooltipContent", "kind": "Function" }, { "name": "ChartsClipPath", "kind": "Function" }, diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json index ced333367ebc..eb38124c022f 100644 --- a/scripts/x-charts.exports.json +++ b/scripts/x-charts.exports.json @@ -66,6 +66,7 @@ { "name": "ChartsAxisHighlightClassKey", "kind": "TypeAlias" }, { "name": "ChartsAxisHighlightPath", "kind": "Variable" }, { "name": "ChartsAxisHighlightProps", "kind": "TypeAlias" }, + { "name": "ChartsAxisHighlightType", "kind": "TypeAlias" }, { "name": "ChartsAxisProps", "kind": "Interface" }, { "name": "ChartsAxisTooltipContent", "kind": "Function" }, { "name": "ChartsClipPath", "kind": "Function" }, From 09a70a742e7a1b2f7a5d3b55e4b45c09f826cbda Mon Sep 17 00:00:00 2001 From: Rajat Date: Mon, 18 Nov 2024 21:28:50 +0530 Subject: [PATCH 6/7] [DataGrid] Add prop to override search input props in `GridColumnsManagement` (#15347) Co-authored-by: Kenan Yusuf --- docs/data/data-grid/localization/data.json | 140 +++++++++--------- .../x/api/data-grid/data-grid-premium.json | 6 + docs/pages/x/api/data-grid/data-grid-pro.json | 6 + docs/pages/x/api/data-grid/data-grid.json | 6 + .../data-grid-premium/data-grid-premium.json | 4 + .../data-grid-pro/data-grid-pro.json | 4 + .../data-grid/data-grid/data-grid.json | 4 + .../GridColumnsManagement.tsx | 59 +++++++- .../x-data-grid/src/constants/gridClasses.ts | 5 + .../src/constants/localeTextConstants.ts | 1 + packages/x-data-grid/src/locales/arSD.ts | 1 + packages/x-data-grid/src/locales/beBY.ts | 1 + packages/x-data-grid/src/locales/bgBG.ts | 1 + packages/x-data-grid/src/locales/csCZ.ts | 1 + packages/x-data-grid/src/locales/daDK.ts | 1 + packages/x-data-grid/src/locales/deDE.ts | 1 + packages/x-data-grid/src/locales/elGR.ts | 1 + packages/x-data-grid/src/locales/esES.ts | 1 + packages/x-data-grid/src/locales/faIR.ts | 1 + packages/x-data-grid/src/locales/fiFI.ts | 1 + packages/x-data-grid/src/locales/frFR.ts | 1 + packages/x-data-grid/src/locales/heIL.ts | 1 + packages/x-data-grid/src/locales/hrHR.ts | 1 + packages/x-data-grid/src/locales/huHU.ts | 1 + packages/x-data-grid/src/locales/isIS.ts | 1 + packages/x-data-grid/src/locales/itIT.ts | 1 + packages/x-data-grid/src/locales/jaJP.ts | 1 + packages/x-data-grid/src/locales/koKR.ts | 1 + packages/x-data-grid/src/locales/nbNO.ts | 1 + packages/x-data-grid/src/locales/nlNL.ts | 1 + packages/x-data-grid/src/locales/nnNO.ts | 1 + packages/x-data-grid/src/locales/plPL.ts | 1 + packages/x-data-grid/src/locales/ptBR.ts | 1 + packages/x-data-grid/src/locales/ptPT.ts | 1 + packages/x-data-grid/src/locales/roRO.ts | 1 + packages/x-data-grid/src/locales/ruRU.ts | 1 + packages/x-data-grid/src/locales/skSK.ts | 1 + packages/x-data-grid/src/locales/svSE.ts | 1 + packages/x-data-grid/src/locales/trTR.ts | 1 + packages/x-data-grid/src/locales/ukUA.ts | 1 + packages/x-data-grid/src/locales/urPK.ts | 1 + packages/x-data-grid/src/locales/viVN.ts | 1 + packages/x-data-grid/src/locales/zhCN.ts | 1 + packages/x-data-grid/src/locales/zhHK.ts | 1 + packages/x-data-grid/src/locales/zhTW.ts | 1 + .../src/models/api/gridLocaleTextApi.ts | 1 + .../src/tests/toolbar.DataGrid.test.tsx | 2 +- 47 files changed, 200 insertions(+), 73 deletions(-) diff --git a/docs/data/data-grid/localization/data.json b/docs/data/data-grid/localization/data.json index 6fa9ffcd38dd..e6d0c4013ace 100644 --- a/docs/data/data-grid/localization/data.json +++ b/docs/data/data-grid/localization/data.json @@ -3,280 +3,280 @@ "languageTag": "ar-SD", "importName": "arSD", "localeName": "Arabic (Sudan)", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/arSD.ts" }, { "languageTag": "be-BY", "importName": "beBY", "localeName": "Belarusian", - "missingKeysCount": 34, - "totalKeysCount": 122, + "missingKeysCount": 35, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/beBY.ts" }, { "languageTag": "bg-BG", "importName": "bgBG", "localeName": "Bulgarian", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/bgBG.ts" }, { "languageTag": "zh-HK", "importName": "zhHK", "localeName": "Chinese (Hong Kong)", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/zhHK.ts" }, { "languageTag": "zh-CN", "importName": "zhCN", "localeName": "Chinese (Simplified)", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/zhCN.ts" }, { "languageTag": "zh-TW", "importName": "zhTW", "localeName": "Chinese (Taiwan)", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/zhTW.ts" }, { "languageTag": "hr-HR", "importName": "hrHR", "localeName": "Croatian", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/hrHR.ts" }, { "languageTag": "cs-CZ", "importName": "csCZ", "localeName": "Czech", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/csCZ.ts" }, { "languageTag": "da-DK", "importName": "daDK", "localeName": "Danish", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/daDK.ts" }, { "languageTag": "nl-NL", "importName": "nlNL", "localeName": "Dutch", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/nlNL.ts" }, { "languageTag": "fi-FI", "importName": "fiFI", "localeName": "Finnish", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/fiFI.ts" }, { "languageTag": "fr-FR", "importName": "frFR", "localeName": "French", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/frFR.ts" }, { "languageTag": "de-DE", "importName": "deDE", "localeName": "German", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/deDE.ts" }, { "languageTag": "el-GR", "importName": "elGR", "localeName": "Greek", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/elGR.ts" }, { "languageTag": "he-IL", "importName": "heIL", "localeName": "Hebrew", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/heIL.ts" }, { "languageTag": "hu-HU", "importName": "huHU", "localeName": "Hungarian", - "missingKeysCount": 6, - "totalKeysCount": 122, + "missingKeysCount": 7, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/huHU.ts" }, { "languageTag": "is-IS", "importName": "isIS", "localeName": "Icelandic", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/isIS.ts" }, { "languageTag": "it-IT", "importName": "itIT", "localeName": "Italian", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/itIT.ts" }, { "languageTag": "ja-JP", "importName": "jaJP", "localeName": "Japanese", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/jaJP.ts" }, { "languageTag": "ko-KR", "importName": "koKR", "localeName": "Korean", - "missingKeysCount": 35, - "totalKeysCount": 122, + "missingKeysCount": 36, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/koKR.ts" }, { "languageTag": "nb-NO", "importName": "nbNO", "localeName": "Norwegian (Bokmål)", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/nbNO.ts" }, { "languageTag": "nn-NO", "importName": "nnNO", "localeName": "Norwegian (Nynorsk)", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/nnNO.ts" }, { "languageTag": "fa-IR", "importName": "faIR", "localeName": "Persian", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/faIR.ts" }, { "languageTag": "pl-PL", "importName": "plPL", "localeName": "Polish", - "missingKeysCount": 11, - "totalKeysCount": 122, + "missingKeysCount": 12, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/plPL.ts" }, { "languageTag": "pt-PT", "importName": "ptPT", "localeName": "Portuguese", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/ptPT.ts" }, { "languageTag": "pt-BR", "importName": "ptBR", "localeName": "Portuguese (Brazil)", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/ptBR.ts" }, { "languageTag": "ro-RO", "importName": "roRO", "localeName": "Romanian", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/roRO.ts" }, { "languageTag": "ru-RU", "importName": "ruRU", "localeName": "Russian", - "missingKeysCount": 4, - "totalKeysCount": 122, + "missingKeysCount": 5, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/ruRU.ts" }, { "languageTag": "sk-SK", "importName": "skSK", "localeName": "Slovak", - "missingKeysCount": 5, - "totalKeysCount": 122, + "missingKeysCount": 6, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/skSK.ts" }, { "languageTag": "es-ES", "importName": "esES", "localeName": "Spanish", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/esES.ts" }, { "languageTag": "sv-SE", "importName": "svSE", "localeName": "Swedish", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/svSE.ts" }, { "languageTag": "tr-TR", "importName": "trTR", "localeName": "Turkish", - "missingKeysCount": 2, - "totalKeysCount": 122, + "missingKeysCount": 3, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/trTR.ts" }, { "languageTag": "uk-UA", "importName": "ukUA", "localeName": "Ukrainian", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/ukUA.ts" }, { "languageTag": "ur-PK", "importName": "urPK", "localeName": "Urdu (Pakistan)", - "missingKeysCount": 8, - "totalKeysCount": 122, + "missingKeysCount": 9, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/urPK.ts" }, { "languageTag": "vi-VN", "importName": "viVN", "localeName": "Vietnamese", - "missingKeysCount": 0, - "totalKeysCount": 122, + "missingKeysCount": 1, + "totalKeysCount": 123, "githubLink": "https://github.com/mui/mui-x/blob/master/packages/x-data-grid/src/locales/viVN.ts" } ] diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index ded5c1bd3c90..ec134312c970 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -1476,6 +1476,12 @@ "description": "Styles applied to the columns management row element.", "isGlobal": false }, + { + "key": "columnsManagementSearchInput", + "className": "MuiDataGridPremium-columnsManagementSearchInput", + "description": "Styles applied to the columns management search input element.", + "isGlobal": false + }, { "key": "container--bottom", "className": "MuiDataGridPremium-container--bottom", diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index 42df3c139311..8fba87d57224 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -1390,6 +1390,12 @@ "description": "Styles applied to the columns management row element.", "isGlobal": false }, + { + "key": "columnsManagementSearchInput", + "className": "MuiDataGridPro-columnsManagementSearchInput", + "description": "Styles applied to the columns management search input element.", + "isGlobal": false + }, { "key": "container--bottom", "className": "MuiDataGridPro-container--bottom", diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 9994e0dc6317..caf8c0b7d035 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -1265,6 +1265,12 @@ "description": "Styles applied to the columns management row element.", "isGlobal": false }, + { + "key": "columnsManagementSearchInput", + "className": "MuiDataGrid-columnsManagementSearchInput", + "description": "Styles applied to the columns management search input element.", + "isGlobal": false + }, { "key": "container--bottom", "className": "MuiDataGrid-container--bottom", diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index 3b9442aa58e3..8879a0ba952c 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -923,6 +923,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the columns management row element" }, + "columnsManagementSearchInput": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the columns management search input element" + }, "container--bottom": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the bottom container" diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index c1d26982ac46..c56adbe4fb0b 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -861,6 +861,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the columns management row element" }, + "columnsManagementSearchInput": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the columns management search input element" + }, "container--bottom": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the bottom container" diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index d082ef5d495d..77ba99fb4030 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -741,6 +741,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the columns management row element" }, + "columnsManagementSearchInput": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the columns management search input element" + }, "container--bottom": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the bottom container" diff --git a/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx b/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx index 431736337d34..a5c15703ecb1 100644 --- a/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx +++ b/packages/x-data-grid/src/components/columnsManagement/GridColumnsManagement.tsx @@ -4,6 +4,8 @@ import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; import FormControlLabel from '@mui/material/FormControlLabel'; import { styled } from '@mui/material/styles'; +import TextField, { TextFieldProps } from '@mui/material/TextField'; +import { inputBaseClasses } from '@mui/material/InputBase'; import { gridColumnDefinitionsSelector, gridColumnVisibilityModelSelector, @@ -24,6 +26,7 @@ export interface GridColumnsManagementProps { */ sort?: 'asc' | 'desc'; searchPredicate?: (column: GridColDef, searchValue: string) => boolean; + searchInputProps?: Partial; /** * If `true`, the column search field will be focused automatically. * If `false`, the first column switch input will be focused automatically. @@ -66,6 +69,7 @@ const useUtilityClasses = (ownerState: OwnerState) => { const slots = { root: ['columnsManagement'], header: ['columnsManagementHeader'], + searchInput: ['columnsManagementSearchInput'], footer: ['columnsManagementFooter'], row: ['columnsManagementRow'], }; @@ -95,6 +99,7 @@ function GridColumnsManagement(props: GridColumnsManagementProps) { disableResetButton = false, toggleAllMode = 'all', getTogglableColumns, + searchInputProps, } = props; const isResetDisabled = React.useMemo( @@ -207,27 +212,59 @@ function GridColumnsManagement(props: GridColumnsManagementProps) { } return false; }; + const handleSearchReset = React.useCallback(() => { + setSearchValue(''); + searchInputRef.current!.focus(); + }, []); return ( - ), - sx: { pl: 1.5 }, + endAdornment: ( + + + + ), + }} + inputProps={{ + 'aria-label': apiRef.current.getLocaleText('columnsManagementSearchTitle'), }} + autoComplete="off" fullWidth {...rootProps.slotProps?.baseTextField} + {...searchInputProps} /> @@ -321,6 +358,7 @@ GridColumnsManagement.propTypes = { * @returns {GridColDef['field'][]} The list of togglable columns' field names. */ getTogglableColumns: PropTypes.func, + searchInputProps: PropTypes.object, searchPredicate: PropTypes.func, sort: PropTypes.oneOf(['asc', 'desc']), /** @@ -354,6 +392,23 @@ const GridColumnsManagementHeader = styled('div', { padding: theme.spacing(1.5, 3), })); +const SearchInput = styled(TextField, { + name: 'MuiDataGrid', + slot: 'ColumnsManagementSearchInput', + overridesResolver: (props, styles) => styles.columnsManagementSearchInput, +})<{ ownerState: OwnerState }>(({ theme }) => ({ + [`& .${inputBaseClasses.root}`]: { + padding: theme.spacing(0, 1.5, 0, 1.5), + }, + [`& .${inputBaseClasses.input}::-webkit-search-decoration, + & .${inputBaseClasses.input}::-webkit-search-cancel-button, + & .${inputBaseClasses.input}::-webkit-search-results-button, + & .${inputBaseClasses.input}::-webkit-search-results-decoration`]: { + /* clears the 'X' icon from Chrome */ + display: 'none', + }, +})); + const GridColumnsManagementFooter = styled('div', { name: 'MuiDataGrid', slot: 'ColumnsManagementFooter', diff --git a/packages/x-data-grid/src/constants/gridClasses.ts b/packages/x-data-grid/src/constants/gridClasses.ts index 06ce8915846a..9082fae28e0e 100644 --- a/packages/x-data-grid/src/constants/gridClasses.ts +++ b/packages/x-data-grid/src/constants/gridClasses.ts @@ -242,6 +242,10 @@ export interface GridClasses { * Styles applied to the columns management header element. */ columnsManagementHeader: string; + /** + * Styles applied to the columns management search input element. + */ + columnsManagementSearchInput: string; /** * Styles applied to the columns management footer element. */ @@ -720,6 +724,7 @@ export const gridClasses = generateUtilityClasses('MuiDataGrid', [ 'columnsManagement', 'columnsManagementRow', 'columnsManagementHeader', + 'columnsManagementSearchInput', 'columnsManagementFooter', 'container--top', 'container--bottom', diff --git a/packages/x-data-grid/src/constants/localeTextConstants.ts b/packages/x-data-grid/src/constants/localeTextConstants.ts index c0d29a97a0e9..395d73a7355b 100644 --- a/packages/x-data-grid/src/constants/localeTextConstants.ts +++ b/packages/x-data-grid/src/constants/localeTextConstants.ts @@ -41,6 +41,7 @@ export const GRID_DEFAULT_LOCALE_TEXT: GridLocaleText = { columnsManagementNoColumns: 'No columns', columnsManagementShowHideAllText: 'Show/Hide All', columnsManagementReset: 'Reset', + columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Add filter', diff --git a/packages/x-data-grid/src/locales/arSD.ts b/packages/x-data-grid/src/locales/arSD.ts index 5d3ebd5993e5..b9aadc4d34bb 100644 --- a/packages/x-data-grid/src/locales/arSD.ts +++ b/packages/x-data-grid/src/locales/arSD.ts @@ -43,6 +43,7 @@ const arSDGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'إضافة مرشِح', diff --git a/packages/x-data-grid/src/locales/beBY.ts b/packages/x-data-grid/src/locales/beBY.ts index bba9d37e0fbd..e11cb810e4cf 100644 --- a/packages/x-data-grid/src/locales/beBY.ts +++ b/packages/x-data-grid/src/locales/beBY.ts @@ -66,6 +66,7 @@ const beBYGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Дадаць фільтр', diff --git a/packages/x-data-grid/src/locales/bgBG.ts b/packages/x-data-grid/src/locales/bgBG.ts index 3c360f174e45..a27adce61ffa 100644 --- a/packages/x-data-grid/src/locales/bgBG.ts +++ b/packages/x-data-grid/src/locales/bgBG.ts @@ -42,6 +42,7 @@ const bgBGGrid: Partial = { columnsManagementNoColumns: 'Няма колони', columnsManagementShowHideAllText: 'Покажи/Скрий Всичко', columnsManagementReset: 'Нулирай', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Добави Филтър', diff --git a/packages/x-data-grid/src/locales/csCZ.ts b/packages/x-data-grid/src/locales/csCZ.ts index c5b26a3ce10e..18611554aa82 100644 --- a/packages/x-data-grid/src/locales/csCZ.ts +++ b/packages/x-data-grid/src/locales/csCZ.ts @@ -50,6 +50,7 @@ const csCZGrid: Partial = { columnsManagementNoColumns: 'Žádné sloupce', columnsManagementShowHideAllText: 'Zobrazit/skrýt vše', columnsManagementReset: 'Resetovat', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Přidat filtr', diff --git a/packages/x-data-grid/src/locales/daDK.ts b/packages/x-data-grid/src/locales/daDK.ts index dc305634c30e..d6094d42ce26 100644 --- a/packages/x-data-grid/src/locales/daDK.ts +++ b/packages/x-data-grid/src/locales/daDK.ts @@ -43,6 +43,7 @@ const daDKGrid: Partial = { columnsManagementNoColumns: 'Ingen søjler', columnsManagementShowHideAllText: 'Vis/Skjul Alle', columnsManagementReset: 'Nulstil', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Tilføj filter', diff --git a/packages/x-data-grid/src/locales/deDE.ts b/packages/x-data-grid/src/locales/deDE.ts index 31a9350cb5e1..48c894e57ecd 100644 --- a/packages/x-data-grid/src/locales/deDE.ts +++ b/packages/x-data-grid/src/locales/deDE.ts @@ -43,6 +43,7 @@ const deDEGrid: Partial = { columnsManagementNoColumns: 'Keine Spalten', columnsManagementShowHideAllText: 'Alle anzeigen/verbergen', columnsManagementReset: 'Zurücksetzen', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Filter hinzufügen', diff --git a/packages/x-data-grid/src/locales/elGR.ts b/packages/x-data-grid/src/locales/elGR.ts index dbd6bdc36f3d..ad0c394d99ef 100644 --- a/packages/x-data-grid/src/locales/elGR.ts +++ b/packages/x-data-grid/src/locales/elGR.ts @@ -43,6 +43,7 @@ const elGRGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Προσθήκη φίλτρου', diff --git a/packages/x-data-grid/src/locales/esES.ts b/packages/x-data-grid/src/locales/esES.ts index 51d21e31b688..87d6133d30a2 100644 --- a/packages/x-data-grid/src/locales/esES.ts +++ b/packages/x-data-grid/src/locales/esES.ts @@ -43,6 +43,7 @@ const esESGrid: Partial = { columnsManagementNoColumns: 'Sin columnas', columnsManagementShowHideAllText: 'Mostrar/Ocultar todas', columnsManagementReset: 'Restablecer', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Agregar filtro', diff --git a/packages/x-data-grid/src/locales/faIR.ts b/packages/x-data-grid/src/locales/faIR.ts index 41dbdd4ca402..6fc24b6f734e 100644 --- a/packages/x-data-grid/src/locales/faIR.ts +++ b/packages/x-data-grid/src/locales/faIR.ts @@ -43,6 +43,7 @@ const faIRGrid: Partial = { columnsManagementNoColumns: 'بدون سطر', columnsManagementShowHideAllText: 'نمایش/مخفی کردن همه', columnsManagementReset: 'بازنشانی', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'افزودن فیلتر', diff --git a/packages/x-data-grid/src/locales/fiFI.ts b/packages/x-data-grid/src/locales/fiFI.ts index d8fee01123fb..00391b62b18c 100644 --- a/packages/x-data-grid/src/locales/fiFI.ts +++ b/packages/x-data-grid/src/locales/fiFI.ts @@ -43,6 +43,7 @@ const fiFIGrid: Partial = { columnsManagementNoColumns: 'Ei sarakkeita näytettäväksi', columnsManagementShowHideAllText: 'Näytä/Piilota kaikki', columnsManagementReset: 'Palauta', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Lisää suodatin', diff --git a/packages/x-data-grid/src/locales/frFR.ts b/packages/x-data-grid/src/locales/frFR.ts index 96abb7fc40e9..e6928a00e57a 100644 --- a/packages/x-data-grid/src/locales/frFR.ts +++ b/packages/x-data-grid/src/locales/frFR.ts @@ -43,6 +43,7 @@ const frFRGrid: Partial = { columnsManagementNoColumns: 'Pas de colonnes', columnsManagementShowHideAllText: 'Afficher/masquer toutes', columnsManagementReset: 'Réinitialiser', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Ajouter un filtre', diff --git a/packages/x-data-grid/src/locales/heIL.ts b/packages/x-data-grid/src/locales/heIL.ts index 61556403a76a..7612d2a8cc39 100644 --- a/packages/x-data-grid/src/locales/heIL.ts +++ b/packages/x-data-grid/src/locales/heIL.ts @@ -43,6 +43,7 @@ const heILGrid: Partial = { columnsManagementNoColumns: 'אין עמודות', columnsManagementShowHideAllText: 'הצג/הסתר הכל', columnsManagementReset: 'אתחול', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'הוסף מסנן', diff --git a/packages/x-data-grid/src/locales/hrHR.ts b/packages/x-data-grid/src/locales/hrHR.ts index 26493db593d9..5999823e9d72 100644 --- a/packages/x-data-grid/src/locales/hrHR.ts +++ b/packages/x-data-grid/src/locales/hrHR.ts @@ -50,6 +50,7 @@ const hrHRGrid: Partial = { columnsManagementNoColumns: 'Nema stupaca', columnsManagementShowHideAllText: 'Prikaži/Sakrij sve', columnsManagementReset: 'Ponovno namjesti', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Dodaj filter', diff --git a/packages/x-data-grid/src/locales/huHU.ts b/packages/x-data-grid/src/locales/huHU.ts index f65c09cdba73..9d9d78e8a7f6 100644 --- a/packages/x-data-grid/src/locales/huHU.ts +++ b/packages/x-data-grid/src/locales/huHU.ts @@ -42,6 +42,7 @@ const huHUGrid: Partial = { columnsManagementNoColumns: 'Nincsenek oszlopok', columnsManagementShowHideAllText: 'Összes', columnsManagementReset: 'Visszavon', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Szűrő hozzáadása', diff --git a/packages/x-data-grid/src/locales/isIS.ts b/packages/x-data-grid/src/locales/isIS.ts index 307231873d9d..70f9c45d6119 100644 --- a/packages/x-data-grid/src/locales/isIS.ts +++ b/packages/x-data-grid/src/locales/isIS.ts @@ -43,6 +43,7 @@ const isISGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Bæta síu', diff --git a/packages/x-data-grid/src/locales/itIT.ts b/packages/x-data-grid/src/locales/itIT.ts index 2058096d6165..7291525a07b8 100644 --- a/packages/x-data-grid/src/locales/itIT.ts +++ b/packages/x-data-grid/src/locales/itIT.ts @@ -43,6 +43,7 @@ const itITGrid: Partial = { columnsManagementNoColumns: 'Nessuna colonna', columnsManagementShowHideAllText: 'Mostra/Nascondi Tutto', columnsManagementReset: 'Resetta', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Aggiungi un filtro', diff --git a/packages/x-data-grid/src/locales/jaJP.ts b/packages/x-data-grid/src/locales/jaJP.ts index 00f626c51187..fd2f69883cf8 100644 --- a/packages/x-data-grid/src/locales/jaJP.ts +++ b/packages/x-data-grid/src/locales/jaJP.ts @@ -42,6 +42,7 @@ const jaJPGrid: Partial = { columnsManagementNoColumns: 'カラムなし', columnsManagementShowHideAllText: 'すべて表示/非表示', columnsManagementReset: 'リセット', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'フィルター追加', diff --git a/packages/x-data-grid/src/locales/koKR.ts b/packages/x-data-grid/src/locales/koKR.ts index 671f6abd0520..bacd936d8fd3 100644 --- a/packages/x-data-grid/src/locales/koKR.ts +++ b/packages/x-data-grid/src/locales/koKR.ts @@ -42,6 +42,7 @@ const koKRGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: '필터 추가', diff --git a/packages/x-data-grid/src/locales/nbNO.ts b/packages/x-data-grid/src/locales/nbNO.ts index 9fa25b0cc4f8..70bd33fc7704 100644 --- a/packages/x-data-grid/src/locales/nbNO.ts +++ b/packages/x-data-grid/src/locales/nbNO.ts @@ -43,6 +43,7 @@ const nbNOGrid: Partial = { columnsManagementNoColumns: 'Ingen kolonner', columnsManagementShowHideAllText: 'Vis/skjul alle', columnsManagementReset: 'Nullstill', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Legg til filter', diff --git a/packages/x-data-grid/src/locales/nlNL.ts b/packages/x-data-grid/src/locales/nlNL.ts index ccc1f5378ab4..4f247c94b2d8 100644 --- a/packages/x-data-grid/src/locales/nlNL.ts +++ b/packages/x-data-grid/src/locales/nlNL.ts @@ -43,6 +43,7 @@ const nlNLGrid: Partial = { columnsManagementNoColumns: 'Geen kolommen', columnsManagementShowHideAllText: 'Toon/Verberg Alle', columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Filter toevoegen', diff --git a/packages/x-data-grid/src/locales/nnNO.ts b/packages/x-data-grid/src/locales/nnNO.ts index 58595a0a4456..e97a9692adb5 100644 --- a/packages/x-data-grid/src/locales/nnNO.ts +++ b/packages/x-data-grid/src/locales/nnNO.ts @@ -43,6 +43,7 @@ const nnNOGrid: Partial = { columnsManagementNoColumns: 'Ingen kolonner', columnsManagementShowHideAllText: 'Vis/skjul alle', columnsManagementReset: 'Nullstill', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Legg til filter', diff --git a/packages/x-data-grid/src/locales/plPL.ts b/packages/x-data-grid/src/locales/plPL.ts index af001de70617..772e84dd64e5 100644 --- a/packages/x-data-grid/src/locales/plPL.ts +++ b/packages/x-data-grid/src/locales/plPL.ts @@ -42,6 +42,7 @@ const plPLGrid: Partial = { columnsManagementNoColumns: 'Brak kolumn', columnsManagementShowHideAllText: 'Wyświetl/Ukryj wszystkie', columnsManagementReset: 'Resetuj', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Dodaj filtr', diff --git a/packages/x-data-grid/src/locales/ptBR.ts b/packages/x-data-grid/src/locales/ptBR.ts index 4dbd7b806024..a921b980bd90 100644 --- a/packages/x-data-grid/src/locales/ptBR.ts +++ b/packages/x-data-grid/src/locales/ptBR.ts @@ -43,6 +43,7 @@ const ptBRGrid: Partial = { columnsManagementNoColumns: 'Nenhuma coluna', columnsManagementShowHideAllText: 'Mostrar/Ocultar Todas', columnsManagementReset: 'Redefinir', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Adicionar filtro', diff --git a/packages/x-data-grid/src/locales/ptPT.ts b/packages/x-data-grid/src/locales/ptPT.ts index 1024917ed9c3..88fa81bdc1c0 100644 --- a/packages/x-data-grid/src/locales/ptPT.ts +++ b/packages/x-data-grid/src/locales/ptPT.ts @@ -43,6 +43,7 @@ const ptPTGrid: Partial = { columnsManagementNoColumns: 'Sem colunas', columnsManagementShowHideAllText: 'Mostrar/Ocultar Todas', columnsManagementReset: 'Repor', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Adicionar filtro', diff --git a/packages/x-data-grid/src/locales/roRO.ts b/packages/x-data-grid/src/locales/roRO.ts index 2a2db174eeac..cc49a4f52e6d 100644 --- a/packages/x-data-grid/src/locales/roRO.ts +++ b/packages/x-data-grid/src/locales/roRO.ts @@ -43,6 +43,7 @@ const roROGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Adăugare filtru', diff --git a/packages/x-data-grid/src/locales/ruRU.ts b/packages/x-data-grid/src/locales/ruRU.ts index 54a7b8514962..61a1613e8ecd 100644 --- a/packages/x-data-grid/src/locales/ruRU.ts +++ b/packages/x-data-grid/src/locales/ruRU.ts @@ -67,6 +67,7 @@ const ruRUGrid: Partial = { columnsManagementNoColumns: 'Нет столбцов', columnsManagementShowHideAllText: 'Показать/Скрыть Всё', columnsManagementReset: 'Сбросить', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Добавить фильтр', diff --git a/packages/x-data-grid/src/locales/skSK.ts b/packages/x-data-grid/src/locales/skSK.ts index f1d2f3be0513..bca93172c221 100644 --- a/packages/x-data-grid/src/locales/skSK.ts +++ b/packages/x-data-grid/src/locales/skSK.ts @@ -50,6 +50,7 @@ const skSKGrid: Partial = { columnsManagementNoColumns: 'Žiadne stĺpce', columnsManagementShowHideAllText: 'Zobraziť/Skryť všetko', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Pridať filter', diff --git a/packages/x-data-grid/src/locales/svSE.ts b/packages/x-data-grid/src/locales/svSE.ts index 20c42538304b..46c5a6f089c5 100644 --- a/packages/x-data-grid/src/locales/svSE.ts +++ b/packages/x-data-grid/src/locales/svSE.ts @@ -43,6 +43,7 @@ const svSEGrid: Partial = { columnsManagementNoColumns: 'Inga kolumner', columnsManagementShowHideAllText: 'Visa/Dölj alla', columnsManagementReset: 'Återställ', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Lägg till filter', diff --git a/packages/x-data-grid/src/locales/trTR.ts b/packages/x-data-grid/src/locales/trTR.ts index aac3da7f9772..07dd3ee608ec 100644 --- a/packages/x-data-grid/src/locales/trTR.ts +++ b/packages/x-data-grid/src/locales/trTR.ts @@ -42,6 +42,7 @@ const trTRGrid: Partial = { columnsManagementNoColumns: 'Kolon yok', columnsManagementShowHideAllText: 'Hepsini Göster/Gizle', columnsManagementReset: 'Sıfırla', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Filtre Ekle', diff --git a/packages/x-data-grid/src/locales/ukUA.ts b/packages/x-data-grid/src/locales/ukUA.ts index 456bf8b00f06..f04fa67e9b5d 100644 --- a/packages/x-data-grid/src/locales/ukUA.ts +++ b/packages/x-data-grid/src/locales/ukUA.ts @@ -67,6 +67,7 @@ const ukUAGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Додати фільтр', diff --git a/packages/x-data-grid/src/locales/urPK.ts b/packages/x-data-grid/src/locales/urPK.ts index 2001e0ea29d1..2ea1572123ca 100644 --- a/packages/x-data-grid/src/locales/urPK.ts +++ b/packages/x-data-grid/src/locales/urPK.ts @@ -43,6 +43,7 @@ const urPKGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'نیا فلٹر', diff --git a/packages/x-data-grid/src/locales/viVN.ts b/packages/x-data-grid/src/locales/viVN.ts index a76c4783b593..354f9db689d3 100644 --- a/packages/x-data-grid/src/locales/viVN.ts +++ b/packages/x-data-grid/src/locales/viVN.ts @@ -43,6 +43,7 @@ const viVNGrid: Partial = { columnsManagementNoColumns: 'Không có cột', columnsManagementShowHideAllText: 'Hiện/Ẩn Tất cả', columnsManagementReset: 'Đặt lại', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: 'Thêm bộ lọc', diff --git a/packages/x-data-grid/src/locales/zhCN.ts b/packages/x-data-grid/src/locales/zhCN.ts index 4badeddc8aef..74574df253b8 100644 --- a/packages/x-data-grid/src/locales/zhCN.ts +++ b/packages/x-data-grid/src/locales/zhCN.ts @@ -42,6 +42,7 @@ const zhCNGrid: Partial = { columnsManagementNoColumns: '没有列', columnsManagementShowHideAllText: '显示/隐藏所有', columnsManagementReset: '重置', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: '添加筛选器', diff --git a/packages/x-data-grid/src/locales/zhHK.ts b/packages/x-data-grid/src/locales/zhHK.ts index 3f53e6b7d9ee..0e73634398a0 100644 --- a/packages/x-data-grid/src/locales/zhHK.ts +++ b/packages/x-data-grid/src/locales/zhHK.ts @@ -43,6 +43,7 @@ const zhHKGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: '新增過濾器', diff --git a/packages/x-data-grid/src/locales/zhTW.ts b/packages/x-data-grid/src/locales/zhTW.ts index facba1f16343..0052bc700964 100644 --- a/packages/x-data-grid/src/locales/zhTW.ts +++ b/packages/x-data-grid/src/locales/zhTW.ts @@ -42,6 +42,7 @@ const zhTWGrid: Partial = { // columnsManagementNoColumns: 'No columns', // columnsManagementShowHideAllText: 'Show/Hide All', // columnsManagementReset: 'Reset', + // columnsManagementDeleteIconLabel: 'Clear', // Filter panel text filterPanelAddFilter: '增加篩選器', diff --git a/packages/x-data-grid/src/models/api/gridLocaleTextApi.ts b/packages/x-data-grid/src/models/api/gridLocaleTextApi.ts index b2ce738ff721..9573191b4756 100644 --- a/packages/x-data-grid/src/models/api/gridLocaleTextApi.ts +++ b/packages/x-data-grid/src/models/api/gridLocaleTextApi.ts @@ -53,6 +53,7 @@ export interface GridLocaleText { columnsManagementNoColumns: string; columnsManagementShowHideAllText: string; columnsManagementReset: string; + columnsManagementDeleteIconLabel: string; // Filter panel text filterPanelAddFilter: React.ReactNode; diff --git a/packages/x-data-grid/src/tests/toolbar.DataGrid.test.tsx b/packages/x-data-grid/src/tests/toolbar.DataGrid.test.tsx index 92cea1015317..5f35b8c50009 100644 --- a/packages/x-data-grid/src/tests/toolbar.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/toolbar.DataGrid.test.tsx @@ -154,7 +154,7 @@ describe(' - Toolbar', () => { fireEvent.click(screen.getByText('Columns')); - const searchInput = document.querySelector('input[type="text"]')!; + const searchInput = document.querySelector('input[type="search"]')!; fireEvent.change(searchInput, { target: { value: 'test' } }); expect(document.querySelector('[role="tooltip"] [name="id"]')).not.to.equal(null); From 3d25ecc2bd523385b6a246cd8a0d381071f6c236 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:59:15 +0100 Subject: [PATCH 7/7] [docs-infra] Fix version tooltip (#15468) --- docs/pages/_app.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/pages/_app.js b/docs/pages/_app.js index 8f1471a414c7..3bd2fdb0ca7b 100644 --- a/docs/pages/_app.js +++ b/docs/pages/_app.js @@ -222,6 +222,13 @@ function AppWrapper(props) { href: `${languagePrefix}${productIdSubpathMap[id]}/`, }; } + if (version === 'v7') { + // #default-branch-switch + return { + text: version, + href: `https://mui.com${languagePrefix}${productIdSubpathMap[id]}/`, + }; + } return { text: version, href: `https://${version}.mui.com${languagePrefix}${productIdSubpathMap[id]}/`, @@ -232,7 +239,7 @@ function AppWrapper(props) { metadata: '', name: 'MUI X', versions: [ - ...getVersionOptions('introduction', ['next', process.env.LIB_VERSION, 'v6', 'v5']), + ...getVersionOptions('introduction', [process.env.LIB_VERSION, 'v7', 'v6', 'v5']), { text: 'v4', href: `https://v4.mui.com${languagePrefix}/components/data-grid/` }, ], }; @@ -242,7 +249,7 @@ function AppWrapper(props) { metadata: 'MUI X', name: 'Data Grid', versions: [ - ...getVersionOptions('x-data-grid', ['next', process.env.DATA_GRID_VERSION, 'v6', 'v5']), + ...getVersionOptions('x-data-grid', [process.env.DATA_GRID_VERSION, 'v7', 'v6', 'v5']), { text: 'v4', href: `https://v4.mui.com${languagePrefix}/components/data-grid/` }, ], }; @@ -251,7 +258,7 @@ function AppWrapper(props) { metadata: 'MUI X', name: 'Date Pickers', versions: [ - ...getVersionOptions('x-date-pickers', ['next', process.env.DATE_PICKERS_VERSION, 'v6']), + ...getVersionOptions('x-date-pickers', [process.env.DATE_PICKERS_VERSION, 'v7', 'v6']), { text: 'v5', href: `https://v5.mui.com${languagePrefix}/x/react-date-pickers/getting-started/`, @@ -262,14 +269,14 @@ function AppWrapper(props) { productIdentifier = { metadata: 'MUI X', name: 'Charts', - versions: getVersionOptions('x-charts', ['next', process.env.CHARTS_VERSION, 'v6']), + versions: getVersionOptions('x-charts', [process.env.CHARTS_VERSION, 'v7', 'v6']), }; } else if (productId === 'x-tree-view') { productIdentifier = { metadata: 'MUI X', name: 'Tree View', versions: [ - ...getVersionOptions('x-tree-view', ['next', process.env.TREE_VIEW_VERSION]), + ...getVersionOptions('x-tree-view', [process.env.TREE_VIEW_VERSION, 'v7']), { text: 'v6', href: `https://v6.mui.com${languagePrefix}/x/react-tree-view/getting-started`,