diff --git a/packages/mui-material/src/Fade/Fade.js b/packages/mui-material/src/Fade/Fade.js index ad0f669096ccb8..d618b514bb2d7a 100644 --- a/packages/mui-material/src/Fade/Fade.js +++ b/packages/mui-material/src/Fade/Fade.js @@ -6,6 +6,7 @@ import elementAcceptingRef from '@mui/utils/elementAcceptingRef'; import { useTheme } from '../zero-styled'; import { reflow, getTransitionProps } from '../transitions/utils'; import useForkRef from '../utils/useForkRef'; +import getChildRef from '../utils/getChildRef'; const styles = { entering: { @@ -48,7 +49,7 @@ const Fade = React.forwardRef(function Fade(props, ref) { const enableStrictModeCompat = true; const nodeRef = React.useRef(null); - const handleRef = useForkRef(nodeRef, children.ref, ref); + const handleRef = useForkRef(nodeRef, getChildRef(children), ref); const normalizedTransitionCallback = (callback) => (maybeIsAppearing) => { if (callback) { diff --git a/packages/mui-material/src/Grow/Grow.js b/packages/mui-material/src/Grow/Grow.js index d4f57bf40161fc..427166ec32c8ef 100644 --- a/packages/mui-material/src/Grow/Grow.js +++ b/packages/mui-material/src/Grow/Grow.js @@ -7,6 +7,7 @@ import { Transition } from 'react-transition-group'; import { useTheme } from '../zero-styled'; import { getTransitionProps, reflow } from '../transitions/utils'; import useForkRef from '../utils/useForkRef'; +import getChildRef from '../utils/getChildRef'; function getScale(value) { return `scale(${value}, ${value ** 2})`; @@ -61,7 +62,7 @@ const Grow = React.forwardRef(function Grow(props, ref) { const theme = useTheme(); const nodeRef = React.useRef(null); - const handleRef = useForkRef(nodeRef, children.ref, ref); + const handleRef = useForkRef(nodeRef, getChildRef(children), ref); const normalizedTransitionCallback = (callback) => (maybeIsAppearing) => { if (callback) { diff --git a/packages/mui-material/src/Slide/Slide.js b/packages/mui-material/src/Slide/Slide.js index 556ede01df8ff4..d669e811d6f115 100644 --- a/packages/mui-material/src/Slide/Slide.js +++ b/packages/mui-material/src/Slide/Slide.js @@ -10,6 +10,7 @@ import useForkRef from '../utils/useForkRef'; import { useTheme } from '../zero-styled'; import { reflow, getTransitionProps } from '../transitions/utils'; import { ownerWindow } from '../utils'; +import getChildRef from '../utils/getChildRef'; // Translate the node so it can't be seen on the screen. // Later, we're going to translate the node back to its original location with `none`. @@ -119,7 +120,7 @@ const Slide = React.forwardRef(function Slide(props, ref) { } = props; const childrenRef = React.useRef(null); - const handleRef = useForkRef(children.ref, childrenRef, ref); + const handleRef = useForkRef(getChildRef(children), childrenRef, ref); const normalizedTransitionCallback = (callback) => (isAppearing) => { if (callback) { diff --git a/packages/mui-material/src/Tooltip/Tooltip.js b/packages/mui-material/src/Tooltip/Tooltip.js index a179afe021eaa4..5dbf3bf55eb9db 100644 --- a/packages/mui-material/src/Tooltip/Tooltip.js +++ b/packages/mui-material/src/Tooltip/Tooltip.js @@ -19,6 +19,7 @@ import useForkRef from '../utils/useForkRef'; import useId from '../utils/useId'; import useControlled from '../utils/useControlled'; import tooltipClasses, { getTooltipUtilityClass } from './tooltipClasses'; +import getChildRef from '../utils/getChildRef'; function round(value) { return Math.round(value * 1e5) / 1e5; @@ -545,7 +546,7 @@ const Tooltip = React.forwardRef(function Tooltip(inProps, ref) { }; }, [handleClose, open]); - const handleRef = useForkRef(children.ref, setChildNode, ref); + const handleRef = useForkRef(getChildRef(children), setChildNode, ref); // There is no point in displaying an empty tooltip. // So we exclude all falsy values, except 0, which is valid. diff --git a/packages/mui-material/src/Zoom/Zoom.js b/packages/mui-material/src/Zoom/Zoom.js index b93d79aab2a7df..7c90324999b1e5 100644 --- a/packages/mui-material/src/Zoom/Zoom.js +++ b/packages/mui-material/src/Zoom/Zoom.js @@ -6,6 +6,7 @@ import elementAcceptingRef from '@mui/utils/elementAcceptingRef'; import { useTheme } from '../zero-styled'; import { reflow, getTransitionProps } from '../transitions/utils'; import useForkRef from '../utils/useForkRef'; +import getChildRef from '../utils/getChildRef'; const styles = { entering: { @@ -48,7 +49,7 @@ const Zoom = React.forwardRef(function Zoom(props, ref) { } = props; const nodeRef = React.useRef(null); - const handleRef = useForkRef(nodeRef, children.ref, ref); + const handleRef = useForkRef(nodeRef, getChildRef(children), ref); const normalizedTransitionCallback = (callback) => (maybeIsAppearing) => { if (callback) { diff --git a/packages/mui-material/src/utils/getChildRef.d.ts b/packages/mui-material/src/utils/getChildRef.d.ts new file mode 100644 index 00000000000000..c7e9c058d3e031 --- /dev/null +++ b/packages/mui-material/src/utils/getChildRef.d.ts @@ -0,0 +1 @@ +export default function getChildRef(child: React.ReactElement): React.Ref | null; diff --git a/packages/mui-material/src/utils/getChildRef.js b/packages/mui-material/src/utils/getChildRef.js new file mode 100644 index 00000000000000..a1d0c2aec5af0c --- /dev/null +++ b/packages/mui-material/src/utils/getChildRef.js @@ -0,0 +1,10 @@ +import * as React from 'react'; + +export default function getChildRef(child) { + if (!child || !React.isValidElement(child)) { + return null; + } + // 'ref' is passed as prop in React 19, whereas 'ref' is directly attached to children in React 18 + // below check is to ensure 'ref' is accessible in both cases + return child.props.propertyIsEnumerable('ref') ? child.props.ref : child.ref; +}