diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx index 9e5ae7a6d0491..26eba1e27e52a 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.test.tsx @@ -4,11 +4,14 @@ import { describeConformance } from 'test/utils/describeConformance'; import { createTheme, ThemeProvider } from '@mui/material/styles'; import { ChartsLabelGradient } from '@mui/x-charts/ChartsLabel/ChartsLabelGradient'; import { labelGradientClasses } from '@mui/x-charts/ChartsLabel'; +import { expect } from 'chai'; +import { describeSkipIf, isJSDOM } from 'test/utils/skipIf'; +import RtlProvider from '@mui/system/RtlProvider'; describe('', () => { const { render } = createRenderer(); - describeConformance(, () => ({ + describeConformance(, () => ({ classes: labelGradientClasses, inheritComponent: 'div', render: (node) => @@ -16,7 +19,7 @@ describe('', () => { wrapper: ({ children }) => ( {children} - + ), }), @@ -28,6 +31,163 @@ describe('', () => { // SKIP skip: ['themeVariants', 'componentProp', 'componentsProp'], })); + + // JSDOM does not support SVGMatrix + describeSkipIf(isJSDOM)('rotation', () => { + const matrixToRotation = (element: SVGSVGElement | null) => { + if (!element) { + throw new Error('Svg element not found'); + } + + const matrix = new DOMMatrix(getComputedStyle(element).transform); + return (Math.atan2(matrix.b, matrix.a) * 180) / Math.PI; + }; + + describe('horizontal', () => { + it('should render a gradient in the correct orientation', () => { + const { container } = render(); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(0); + }); + + it('should reverse the gradient', () => { + const { container } = render(); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(180); + }); + + it('should rotate the gradient', () => { + const { container } = render(); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(90); + }); + + it('should reverse and rotate the gradient', () => { + const { container } = render( + , + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(-90); + }); + }); + + describe('vertical', () => { + it('should render a gradient in the correct orientation', () => { + const { container } = render( + , + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(-90); + }); + + it('should reverse the gradient', () => { + const { container } = render( + , + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(90); + }); + + it('should rotate the gradient', () => { + const { container } = render( + , + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(0); + }); + + it('should reverse and rotate the gradient', () => { + const { container } = render( + , + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(180); + }); + }); + + describe('RTL', () => { + describe('horizontal', () => { + it('should render a gradient in the correct orientation', () => { + const { container } = render(, { + wrapper: RtlWrapper, + }); + const svg = container.querySelector('svg'); + // Technically it is -180, but the browser will normalize it to 180 + expect(matrixToRotation(svg)).to.equal(180); + }); + + it('should reverse the gradient', () => { + const { container } = render( + , + { wrapper: RtlWrapper }, + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(0); + }); + + it('should rotate the gradient', () => { + const { container } = render( + , + { wrapper: RtlWrapper }, + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(90); + }); + + it('should reverse and rotate the gradient', () => { + const { container } = render( + , + { wrapper: RtlWrapper }, + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(-90); + }); + }); + + describe('vertical', () => { + it('should render a gradient in the correct orientation', () => { + const { container } = render( + , + { wrapper: RtlWrapper }, + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(-90); + }); + + it('should reverse the gradient', () => { + const { container } = render( + , + { wrapper: RtlWrapper }, + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(90); + }); + + it('should rotate the gradient', () => { + const { container } = render( + , + { wrapper: RtlWrapper }, + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(180); + }); + + it('should reverse and rotate the gradient', () => { + const { container } = render( + , + { wrapper: RtlWrapper }, + ); + const svg = container.querySelector('svg'); + expect(matrixToRotation(svg)).to.equal(0); + }); + }); + }); + }); }); function Gradient({ id }: any) { @@ -43,3 +203,11 @@ function Gradient({ id }: any) { ); } + +function RtlWrapper({ children }: any) { + return ( + +
{children}
+
+ ); +} diff --git a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx index c842ab1ad7d8e..7ec8c2fa024f5 100644 --- a/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx +++ b/packages/x-charts/src/ChartsLabel/ChartsLabelGradient.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { styled, SxProps, Theme } from '@mui/material/styles'; import clsx from 'clsx'; +import { useRtl } from '@mui/system/RtlProvider'; import { ChartsLabelGradientClasses, useUtilityClasses, @@ -43,32 +44,40 @@ export interface ChartsLabelGradientProps { sx?: SxProps; } +const applyRtl = (isRtl: boolean | undefined, value: number) => (isRtl ? value - 180 : value); + const getRotation = ( direction?: 'vertical' | 'horizontal', reverse?: boolean, rotate?: boolean, + isRtl?: boolean, ) => { if (!rotate && reverse) { - return direction === 'vertical' ? 90 : 180; + return direction === 'vertical' ? 90 : applyRtl(isRtl, 180); } if (rotate && !reverse) { - return direction === 'vertical' ? 0 : 90; + return direction === 'vertical' ? applyRtl(isRtl, 0) : 90; } if (rotate && reverse) { - return direction === 'vertical' ? 180 : -90; + return direction === 'vertical' ? applyRtl(isRtl, 180) : -90; } - return direction === 'vertical' ? -90 : 0; + return direction === 'vertical' ? -90 : applyRtl(isRtl, 0); }; const Root = styled('div', { name: 'MuiChartsLabelGradient', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: ChartsLabelGradientProps }>(({ ownerState }) => { - const rotation = getRotation(ownerState.direction, ownerState.reverse, ownerState.rotate); +})<{ ownerState: ChartsLabelGradientProps & { isRtl: boolean } }>(({ ownerState }) => { + const rotation = getRotation( + ownerState.direction, + ownerState.reverse, + ownerState.rotate, + ownerState.isRtl, + ); return { display: 'flex', @@ -118,11 +127,12 @@ const ChartsLabelGradient = consumeThemeProps( function ChartsLabelGradient(props: ChartsLabelGradientProps, ref: React.Ref) { const { gradientId, direction, classes, className, rotate, reverse, thickness, ...other } = props; + const isRtl = useRtl(); return (