Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 7 additions & 20 deletions packages/mui-material/src/Collapse/Collapse.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { styled, useTheme } from '../zero-styled';
import memoTheme from '../utils/memoTheme';
import { useDefaultProps } from '../DefaultPropsProvider';
import { duration } from '../styles/createTransitions';
import { getTransitionProps } from '../transitions/utils';
import { normalizedTransitionCallback, getTransitionProps } from '../transitions/utils';
import { useForkRef } from '../utils';
import useSlot from '../utils/useSlot';
import { getCollapseUtilityClass } from './collapseClasses';
Expand Down Expand Up @@ -179,23 +179,10 @@ const Collapse = React.forwardRef(function Collapse(inProps, ref) {
const nodeRef = React.useRef(null);
const handleRef = useForkRef(ref, nodeRef);

const normalizedTransitionCallback = (callback) => (maybeIsAppearing) => {
if (callback) {
const node = nodeRef.current;

// onEnterXxx and onExitXxx callbacks have a different arguments.length value.
if (maybeIsAppearing === undefined) {
callback(node);
} else {
callback(node, maybeIsAppearing);
}
}
};

const getWrapperSize = () =>
wrapperRef.current ? wrapperRef.current[isHorizontal ? 'clientWidth' : 'clientHeight'] : 0;

const handleEnter = normalizedTransitionCallback((node, isAppearing) => {
const handleEnter = normalizedTransitionCallback(nodeRef, (node, isAppearing) => {
if (wrapperRef.current && isHorizontal) {
// Set absolute position to get the size of collapsed content
wrapperRef.current.style.position = 'absolute';
Expand All @@ -207,7 +194,7 @@ const Collapse = React.forwardRef(function Collapse(inProps, ref) {
}
});

const handleEntering = normalizedTransitionCallback((node, isAppearing) => {
const handleEntering = normalizedTransitionCallback(nodeRef, (node, isAppearing) => {
const wrapperSize = getWrapperSize();

if (wrapperRef.current && isHorizontal) {
Expand Down Expand Up @@ -239,25 +226,25 @@ const Collapse = React.forwardRef(function Collapse(inProps, ref) {
}
});

const handleEntered = normalizedTransitionCallback((node, isAppearing) => {
const handleEntered = normalizedTransitionCallback(nodeRef, (node, isAppearing) => {
node.style[size] = 'auto';

if (onEntered) {
onEntered(node, isAppearing);
}
});

const handleExit = normalizedTransitionCallback((node) => {
const handleExit = normalizedTransitionCallback(nodeRef, (node) => {
node.style[size] = `${getWrapperSize()}px`;

if (onExit) {
onExit(node);
}
});

const handleExited = normalizedTransitionCallback(onExited);
const handleExited = normalizedTransitionCallback(nodeRef, onExited);

const handleExiting = normalizedTransitionCallback((node) => {
const handleExiting = normalizedTransitionCallback(nodeRef, (node) => {
const wrapperSize = getWrapperSize();
const { duration: transitionDuration, easing: transitionTimingFunction } = getTransitionProps(
{ style, timeout, easing },
Expand Down
81 changes: 40 additions & 41 deletions packages/mui-material/src/Fade/Fade.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@ import { Transition } from 'react-transition-group';
import elementAcceptingRef from '@mui/utils/elementAcceptingRef';
import getReactElementRef from '@mui/utils/getReactElementRef';
import { useTheme } from '../zero-styled';
import { reflow, getTransitionProps } from '../transitions/utils';
import {
normalizedTransitionCallback,
reflow,
getTransitionProps,
getTransitionChildStyle,
} from '../transitions/utils';
import useForkRef from '../utils/useForkRef';

const styles = {
entering: {
opacity: 1,
},
entered: {
opacity: 1,
},
entering: { opacity: 1 },
entered: { opacity: 1 },
exiting: { opacity: 0 },
exited: { opacity: 0 },
};

const hiddenStyles = { opacity: 0, visibility: 'hidden' };

/**
* The Fade transition is used by the [Modal](/material-ui/react-modal/) component.
* It uses [react-transition-group](https://github.com/reactjs/react-transition-group) internally.
Expand All @@ -42,31 +47,15 @@ const Fade = React.forwardRef(function Fade(props, ref) {
onExiting,
style,
timeout = defaultTimeout,
// eslint-disable-next-line react/prop-types
TransitionComponent = Transition,
...other
} = props;

const enableStrictModeCompat = true;
const nodeRef = React.useRef(null);
const handleRef = useForkRef(nodeRef, getReactElementRef(children), ref);

const normalizedTransitionCallback = (callback) => (maybeIsAppearing) => {
if (callback) {
const node = nodeRef.current;

// onEnterXxx and onExitXxx callbacks have a different arguments.length value.
if (maybeIsAppearing === undefined) {
callback(node);
} else {
callback(node, maybeIsAppearing);
}
}
};

const handleEntering = normalizedTransitionCallback(onEntering);
const handleEntering = normalizedTransitionCallback(nodeRef, onEntering);

const handleEnter = normalizedTransitionCallback((node, isAppearing) => {
const handleEnter = normalizedTransitionCallback(nodeRef, (node, isAppearing) => {
reflow(node); // So the animation always start from the start.

const transitionProps = getTransitionProps(
Expand All @@ -76,35 +65,42 @@ const Fade = React.forwardRef(function Fade(props, ref) {
},
);

node.style.webkitTransition = theme.transitions.create('opacity', transitionProps);
node.style.transition = theme.transitions.create('opacity', transitionProps);

if (onEnter) {
onEnter(node, isAppearing);
}
});

const handleEntered = normalizedTransitionCallback(onEntered);
const handleEntered = normalizedTransitionCallback(nodeRef, onEntered);

const handleExiting = normalizedTransitionCallback(onExiting);
const handleExiting = normalizedTransitionCallback(nodeRef, onExiting);

const handleExit = normalizedTransitionCallback((node) => {
const handleExit = normalizedTransitionCallback(nodeRef, (node) => {
const transitionProps = getTransitionProps(
{ style, timeout, easing },
{
mode: 'exit',
},
);

node.style.webkitTransition = theme.transitions.create('opacity', transitionProps);
node.style.transition = theme.transitions.create('opacity', transitionProps);

if (onExit) {
onExit(node);
}
});

const handleExited = normalizedTransitionCallback(onExited);
const handleExited = normalizedTransitionCallback(nodeRef, (node) => {
// Clear the transition CSS to release the compositor layer when the
// element is fully exited (prevents idle CPU usage on fixed elements
// like Backdrop). handleEnter re-sets it on the next open.
node.style.transition = '';

if (onExited) {
onExited(node);
}
});

const handleAddEndListener = (next) => {
if (addEndListener) {
Expand All @@ -114,10 +110,10 @@ const Fade = React.forwardRef(function Fade(props, ref) {
};

return (
<TransitionComponent
<Transition
appear={appear}
in={inProp}
nodeRef={enableStrictModeCompat ? nodeRef : undefined}
nodeRef={nodeRef}
onEnter={handleEnter}
onEntered={handleEntered}
onEntering={handleEntering}
Expand All @@ -130,19 +126,22 @@ const Fade = React.forwardRef(function Fade(props, ref) {
>
{/* 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 }) => {
const childStyle = getTransitionChildStyle(
state,
inProp,
styles,
hiddenStyles,
style,
children.props.style,
);

return React.cloneElement(children, {
style: {
opacity: 0,
visibility: state === 'exited' && !inProp ? 'hidden' : undefined,
...styles[state],
...style,
...children.props.style,
},
style: childStyle,
ref: handleRef,
...restChildProps,
});
}}
</TransitionComponent>
</Transition>
);
});

Expand Down
89 changes: 38 additions & 51 deletions packages/mui-material/src/Grow/Grow.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,26 @@ import elementAcceptingRef from '@mui/utils/elementAcceptingRef';
import getReactElementRef from '@mui/utils/getReactElementRef';
import { Transition } from 'react-transition-group';
import { useTheme } from '../zero-styled';
import { getTransitionProps, reflow } from '../transitions/utils';
import {
normalizedTransitionCallback,
getTransitionProps,
getTransitionChildStyle,
reflow,
} from '../transitions/utils';
import useForkRef from '../utils/useForkRef';

function getScale(value) {
return `scale(${value}, ${value ** 2})`;
}

const styles = {
entering: {
opacity: 1,
transform: getScale(1),
},
entered: {
opacity: 1,
transform: 'none',
},
entering: { opacity: 1, transform: getScale(1) },
entered: { opacity: 1, transform: 'none' },
exiting: { opacity: 0, transform: getScale(0.75) },
exited: { opacity: 0, transform: getScale(0.75) },
};

/*
TODO v6: remove
Conditionally apply a workaround for the CSS transition bug in Safari 15.4 / WebKit browsers.
*/
const isWebKit154 =
typeof navigator !== 'undefined' &&
/^((?!chrome|android).)*(safari|mobile)/i.test(navigator.userAgent) &&
/(os |version\/)15(.|_)4/i.test(navigator.userAgent);
const hiddenStyles = { opacity: 0, transform: getScale(0.75), visibility: 'hidden' };

/**
* The Grow transition is used by the [Tooltip](/material-ui/react-tooltip/) and
Expand All @@ -53,8 +47,6 @@ const Grow = React.forwardRef(function Grow(props, ref) {
onExiting,
style,
timeout = 'auto',
// eslint-disable-next-line react/prop-types
TransitionComponent = Transition,
...other
} = props;
const timer = useTimeout();
Expand All @@ -64,22 +56,9 @@ const Grow = React.forwardRef(function Grow(props, ref) {
const nodeRef = React.useRef(null);
const handleRef = useForkRef(nodeRef, getReactElementRef(children), ref);

const normalizedTransitionCallback = (callback) => (maybeIsAppearing) => {
if (callback) {
const node = nodeRef.current;

// onEnterXxx and onExitXxx callbacks have a different arguments.length value.
if (maybeIsAppearing === undefined) {
callback(node);
} else {
callback(node, maybeIsAppearing);
}
}
};

const handleEntering = normalizedTransitionCallback(onEntering);
const handleEntering = normalizedTransitionCallback(nodeRef, onEntering);

const handleEnter = normalizedTransitionCallback((node, isAppearing) => {
const handleEnter = normalizedTransitionCallback(nodeRef, (node, isAppearing) => {
reflow(node); // So the animation always start from the start.

const {
Expand Down Expand Up @@ -107,7 +86,7 @@ const Grow = React.forwardRef(function Grow(props, ref) {
delay,
}),
theme.transitions.create('transform', {
duration: isWebKit154 ? duration : duration * 0.666,
duration: duration * 0.666,
delay,
easing: transitionTimingFunction,
}),
Expand All @@ -118,11 +97,11 @@ const Grow = React.forwardRef(function Grow(props, ref) {
}
});

const handleEntered = normalizedTransitionCallback(onEntered);
const handleEntered = normalizedTransitionCallback(nodeRef, onEntered);

const handleExiting = normalizedTransitionCallback(onExiting);
const handleExiting = normalizedTransitionCallback(nodeRef, onExiting);

const handleExit = normalizedTransitionCallback((node) => {
const handleExit = normalizedTransitionCallback(nodeRef, (node) => {
const {
duration: transitionDuration,
delay,
Expand All @@ -148,8 +127,8 @@ const Grow = React.forwardRef(function Grow(props, ref) {
delay,
}),
theme.transitions.create('transform', {
duration: isWebKit154 ? duration : duration * 0.666,
delay: isWebKit154 ? delay : delay || duration * 0.333,
duration: duration * 0.666,
delay: delay || duration * 0.333,
easing: transitionTimingFunction,
}),
].join(',');
Expand All @@ -162,7 +141,13 @@ const Grow = React.forwardRef(function Grow(props, ref) {
}
});

const handleExited = normalizedTransitionCallback(onExited);
const handleExited = normalizedTransitionCallback(nodeRef, (node) => {
node.style.transition = '';

if (onExited) {
onExited(node);
}
});

const handleAddEndListener = (next) => {
if (timeout === 'auto') {
Expand All @@ -175,7 +160,7 @@ const Grow = React.forwardRef(function Grow(props, ref) {
};

return (
<TransitionComponent
<Transition
appear={appear}
in={inProp}
nodeRef={nodeRef}
Expand All @@ -191,20 +176,22 @@ const Grow = React.forwardRef(function Grow(props, ref) {
>
{/* 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 }) => {
const childStyle = getTransitionChildStyle(
state,
inProp,
styles,
hiddenStyles,
style,
children.props.style,
);

return React.cloneElement(children, {
style: {
opacity: 0,
transform: getScale(0.75),
visibility: state === 'exited' && !inProp ? 'hidden' : undefined,
...styles[state],
...style,
...children.props.style,
},
style: childStyle,
ref: handleRef,
...restChildProps,
});
}}
</TransitionComponent>
</Transition>
);
});

Expand Down
Loading
Loading