Skip to content

Commit

Permalink
[material-ui] Prevent ownerState propagation for transition slots (m…
Browse files Browse the repository at this point in the history
…ui#44401)

Signed-off-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com>
Signed-off-by: Diego Andai <diego@mui.com>
Co-authored-by: Olivier Tassinari <olivier.tassinari@gmail.com>
Co-authored-by: Diego Andai <diego@mui.com>
  • Loading branch information
3 people authored Dec 19, 2024
1 parent 523b329 commit 3f851ce
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 20 deletions.
51 changes: 50 additions & 1 deletion packages/mui-material/src/Accordion/Accordion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import { expect } from 'chai';
import { spy } from 'sinon';
import { createRenderer, fireEvent, reactMajor } from '@mui/internal-test-utils';
import { createRenderer, fireEvent, reactMajor, screen } from '@mui/internal-test-utils';
import Accordion, { accordionClasses as classes } from '@mui/material/Accordion';
import Paper from '@mui/material/Paper';
import Collapse from '@mui/material/Collapse';
import Fade from '@mui/material/Fade';
import Slide from '@mui/material/Slide';
import Grow from '@mui/material/Grow';
import Zoom from '@mui/material/Zoom';
import AccordionSummary from '@mui/material/AccordionSummary';
import describeConformance from '../../test/describeConformance';

Expand Down Expand Up @@ -261,4 +266,48 @@ describe('<Accordion />', () => {
expect(queryByTestId('details')).to.equal(null);
});
});

describe('should not forward ownerState prop to the underlying DOM element when using transition slot', () => {
const transitions = [
{
component: Collapse,
name: 'Collapse',
},
{
component: Fade,
name: 'Fade',
},
{
component: Grow,
name: 'Grow',
},
{
component: Slide,
name: 'Slide',
},
{
component: Zoom,
name: 'Zoom',
},
];

transitions.forEach((transition) => {
it(transition.name, () => {
render(
<Accordion
defaultExpanded
slots={{
transition: transition.component,
}}
slotProps={{ transition: { timeout: 400 } }}
>
<AccordionSummary>Summary</AccordionSummary>
Details
</Accordion>,
);

expect(screen.getByRole('region')).not.to.have.attribute('ownerstate');
});
});
});
});
8 changes: 1 addition & 7 deletions packages/mui-material/src/Backdrop/Backdrop.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ import useSlot from '../utils/useSlot';
import Fade from '../Fade';
import { getBackdropUtilityClass } from './backdropClasses';

const removeOwnerState = (props) => {
const { ownerState, ...rest } = props;
return rest;
};

const useUtilityClasses = (ownerState) => {
const { classes, invisible } = ownerState;

Expand Down Expand Up @@ -101,10 +96,9 @@ const Backdrop = React.forwardRef(function Backdrop(inProps, ref) {
externalForwardedProps,
ownerState,
});
const transitionPropsRemoved = removeOwnerState(transitionProps);

return (
<TransitionSlot in={open} timeout={transitionDuration} {...other} {...transitionPropsRemoved}>
<TransitionSlot in={open} timeout={transitionDuration} {...other} {...transitionProps}>
<RootSlot aria-hidden {...rootProps} classes={classes} ref={ref}>
{children}
</RootSlot>
Expand Down
7 changes: 3 additions & 4 deletions packages/mui-material/src/Collapse/Collapse.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ const Collapse = React.forwardRef(function Collapse(inProps, ref) {
timeout={timeout === 'auto' ? null : timeout}
{...other}
>
{(state, childProps) => (
{/* Destructure child props to prevent the component's "ownerState" from being overridden by incomingOwnerState. */}
{(state, { ownerState: incomingOwnerState, ...restChildProps }) => (
<CollapseRoot
as={component}
className={clsx(
Expand All @@ -324,10 +325,8 @@ const Collapse = React.forwardRef(function Collapse(inProps, ref) {
...style,
}}
ref={handleRef}
{...childProps}
// `ownerState` is set after `childProps` to override any existing `ownerState` property in `childProps`
// that might have been forwarded from the Transition component.
ownerState={{ ...ownerState, state }}
{...restChildProps}
>
<CollapseWrapper
ownerState={{ ...ownerState, state }}
Expand Down
18 changes: 18 additions & 0 deletions packages/mui-material/src/Collapse/Collapse.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,22 @@ describe('<Collapse />', () => {
expect(handleExiting.args[0][0].style.height).to.equal(collapsedSize);
});
});

// Test for https://github.com/mui/material-ui/issues/40653
it('should render correctly when external ownerState prop is passed', function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
this.skip();
}

const { container } = render(
<Collapse in ownerState={{}}>
<div style={{ height: '100px' }} />
</Collapse>,
);
const collapse = container.firstChild;

expect(collapse).toHaveComputedStyle({
height: '100px',
});
});
});
5 changes: 3 additions & 2 deletions packages/mui-material/src/Fade/Fade.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ const Fade = React.forwardRef(function Fade(props, ref) {
timeout={timeout}
{...other}
>
{(state, childProps) => {
{/* Ensure "ownerState" is not forwarded to the child DOM element when a direct HTML element is used. This avoids unexpected behavior since "ownerState" is intended for internal styling, component props and not as a DOM attribute. */}
{(state, { ownerState, ...restChildProps }) => {
return React.cloneElement(children, {
style: {
opacity: 0,
Expand All @@ -138,7 +139,7 @@ const Fade = React.forwardRef(function Fade(props, ref) {
...children.props.style,
},
ref: handleRef,
...childProps,
...restChildProps,
});
}}
</TransitionComponent>
Expand Down
5 changes: 3 additions & 2 deletions packages/mui-material/src/Grow/Grow.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ const Grow = React.forwardRef(function Grow(props, ref) {
timeout={timeout === 'auto' ? null : timeout}
{...other}
>
{(state, childProps) => {
{/* Ensure "ownerState" is not forwarded to the child DOM element when a direct HTML element is used. This avoids unexpected behavior since "ownerState" is intended for internal styling, component props and not as a DOM attribute. */}
{(state, { ownerState, ...restChildProps }) => {
return React.cloneElement(children, {
style: {
opacity: 0,
Expand All @@ -200,7 +201,7 @@ const Grow = React.forwardRef(function Grow(props, ref) {
...children.props.style,
},
ref: handleRef,
...childProps,
...restChildProps,
});
}}
</TransitionComponent>
Expand Down
5 changes: 3 additions & 2 deletions packages/mui-material/src/Slide/Slide.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,16 @@ const Slide = React.forwardRef(function Slide(props, ref) {
timeout={timeout}
{...other}
>
{(state, childProps) => {
{/* Ensure "ownerState" is not forwarded to the child DOM element when a direct HTML element is used. This avoids unexpected behavior since "ownerState" is intended for internal styling, component props and not as a DOM attribute. */}
{(state, { ownerState, ...restChildProps }) => {
return React.cloneElement(children, {
ref: handleRef,
style: {
visibility: state === 'exited' && !inProp ? 'hidden' : undefined,
...style,
...children.props.style,
},
...childProps,
...restChildProps,
});
}}
</TransitionComponent>
Expand Down
5 changes: 3 additions & 2 deletions packages/mui-material/src/Zoom/Zoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ const Zoom = React.forwardRef(function Zoom(props, ref) {
timeout={timeout}
{...other}
>
{(state, childProps) => {
{/* Ensure "ownerState" is not forwarded to the child DOM element when a direct HTML element is used. This avoids unexpected behavior since "ownerState" is intended for internal styling, component props and not as a DOM attribute. */}
{(state, { ownerState, ...restChildProps }) => {
return React.cloneElement(children, {
style: {
transform: 'scale(0)',
Expand All @@ -138,7 +139,7 @@ const Zoom = React.forwardRef(function Zoom(props, ref) {
...children.props.style,
},
ref: handleRef,
...childProps,
...restChildProps,
});
}}
</TransitionComponent>
Expand Down

0 comments on commit 3f851ce

Please sign in to comment.