Skip to content

Commit b013339

Browse files
committed
modify logic according to mui#43022 (comment)
1 parent 348814b commit b013339

File tree

3 files changed

+96
-4
lines changed

3 files changed

+96
-4
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import getReactNodeRef from '@mui/utils/getReactNodeRef';
2+
import * as React from 'react';
3+
4+
// @ts-expect-error
5+
getReactNodeRef(false);
6+
7+
// @ts-expect-error
8+
getReactNodeRef(null);
9+
10+
// @ts-expect-error
11+
getReactNodeRef(undefined);
12+
13+
// @ts-expect-error
14+
getReactNodeRef(1);
15+
16+
// @ts-expect-error
17+
getReactNodeRef([<div key="1" />, <div key="2" />]);
18+
19+
getReactNodeRef(<div />);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { expect } from 'chai';
2+
import getReactNodeRef from '@mui/utils/getReactNodeRef';
3+
import * as React from 'react';
4+
5+
describe('getReactNodeRef', () => {
6+
it('should throw when not used correctly', () => {
7+
expect(() => {
8+
// @ts-expect-error
9+
getReactNodeRef(false);
10+
// @ts-expect-error
11+
}).toThrowMinified(/expects a React element/);
12+
13+
expect(() => {
14+
// @ts-expect-error
15+
getReactNodeRef();
16+
// @ts-expect-error
17+
}).toThrowMinified(/expects a React element/);
18+
19+
expect(() => {
20+
// @ts-expect-error
21+
getReactNodeRef(1);
22+
// @ts-expect-error
23+
}).toThrowMinified(/expects a React element/);
24+
});
25+
26+
it('should return the ref of a React element', () => {
27+
const ref = React.createRef<HTMLDivElement>();
28+
const element = <div ref={ref} />;
29+
expect(getReactNodeRef(element)).to.equal(ref);
30+
});
31+
32+
it('should return null for a fragment', () => {
33+
const element = (
34+
<React.Fragment>
35+
<p>Hello</p>
36+
<p>Hello</p>
37+
</React.Fragment>
38+
);
39+
expect(getReactNodeRef(element)).to.equal(null);
40+
});
41+
42+
it('should return undefined for an array', () => {
43+
const element = [<div key="1" />, <div key="2" />];
44+
// @ts-expect-error
45+
expect(getReactNodeRef(element)).to.equal(undefined);
46+
});
47+
48+
it('should return null for element with no ref', () => {
49+
const element = <div />;
50+
expect(getReactNodeRef(element)).to.equal(null);
51+
});
52+
});
Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,39 @@
11
import * as React from 'react';
2+
import MuiError from '@mui/internal-babel-macros/MuiError.macro';
23

34
/**
45
* Returns the ref of a React node handling differences between React 19 and older versions.
56
* It will return null if the node is not a valid React element.
67
*
7-
* @param element React.ReactNode
8+
* @param element React.ReactElement
89
* @returns React.Ref<any> | null
910
*/
10-
export default function getReactNodeRef(element: React.ReactNode): React.Ref<any> | null {
11+
export default function getReactNodeRef(
12+
element: React.ReactElement,
13+
): React.Ref<any> | null | undefined {
14+
if (typeof element !== 'object') {
15+
throw new MuiError('MUI: `getReactNodeRef(element)` expects a React element.');
16+
}
17+
18+
if (Array.isArray(element)) {
19+
return undefined;
20+
}
21+
22+
if (element.type === React.Fragment) {
23+
return null;
24+
}
25+
1126
// 'ref' is passed as prop in React 19, whereas 'ref' is directly attached to children in older versions
12-
return (element as any)?.props?.propertyIsEnumerable('ref')
13-
? (element as any)?.props.ref
27+
const ref = element.props?.propertyIsEnumerable('ref')
28+
? (element.props as any).ref
1429
: // @ts-expect-error element.ref is not included in the ReactElement type
1530
// We cannot check for it, but isValidElement is true at this point
1631
// https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/70189
1732
element.ref;
33+
34+
if (!ref) {
35+
return null;
36+
}
37+
38+
return ref;
1839
}

0 commit comments

Comments
 (0)