UNPKG

3.43 kBJavaScriptView Raw
1'use client';
2
3import * as React from 'react';
4import * as ReactDOM from 'react-dom';
5import PropTypes from 'prop-types';
6import { exactProp, HTMLElementType, unstable_useEnhancedEffect as useEnhancedEffect, unstable_useForkRef as useForkRef, unstable_setRef as setRef, unstable_getReactElementRef as getReactElementRef } from '@mui/utils';
7function getContainer(container) {
8 return typeof container === 'function' ? container() : container;
9}
10
11/**
12 * Portals provide a first-class way to render children into a DOM node
13 * that exists outside the DOM hierarchy of the parent component.
14 *
15 * Demos:
16 *
17 * - [Portal](https://mui.com/material-ui/react-portal/)
18 *
19 * API:
20 *
21 * - [Portal API](https://mui.com/material-ui/api/portal/)
22 */
23const Portal = /*#__PURE__*/React.forwardRef(function Portal(props, forwardedRef) {
24 const {
25 children,
26 container,
27 disablePortal = false
28 } = props;
29 const [mountNode, setMountNode] = React.useState(null);
30 const handleRef = useForkRef(/*#__PURE__*/React.isValidElement(children) ? getReactElementRef(children) : null, forwardedRef);
31 useEnhancedEffect(() => {
32 if (!disablePortal) {
33 setMountNode(getContainer(container) || document.body);
34 }
35 }, [container, disablePortal]);
36 useEnhancedEffect(() => {
37 if (mountNode && !disablePortal) {
38 setRef(forwardedRef, mountNode);
39 return () => {
40 setRef(forwardedRef, null);
41 };
42 }
43 return undefined;
44 }, [forwardedRef, mountNode, disablePortal]);
45 if (disablePortal) {
46 if (/*#__PURE__*/React.isValidElement(children)) {
47 const newProps = {
48 ref: handleRef
49 };
50 return /*#__PURE__*/React.cloneElement(children, newProps);
51 }
52 return children;
53 }
54 return mountNode ? /*#__PURE__*/ReactDOM.createPortal(children, mountNode) : mountNode;
55});
56process.env.NODE_ENV !== "production" ? Portal.propTypes /* remove-proptypes */ = {
57 // ┌────────────────────────────── Warning ──────────────────────────────┐
58 // │ These PropTypes are generated from the TypeScript type definitions. │
59 // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
60 // └─────────────────────────────────────────────────────────────────────┘
61 /**
62 * The children to render into the `container`.
63 */
64 children: PropTypes.node,
65 /**
66 * An HTML element or function that returns one.
67 * The `container` will have the portal children appended to it.
68 *
69 * You can also provide a callback, which is called in a React layout effect.
70 * This lets you set the container from a ref, and also makes server-side rendering possible.
71 *
72 * By default, it uses the body of the top-level document object,
73 * so it's simply `document.body` most of the time.
74 */
75 container: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([HTMLElementType, PropTypes.func]),
76 /**
77 * The `children` will be under the DOM hierarchy of the parent component.
78 * @default false
79 */
80 disablePortal: PropTypes.bool
81} : void 0;
82if (process.env.NODE_ENV !== 'production') {
83 // eslint-disable-next-line
84 Portal['propTypes' + ''] = exactProp(Portal.propTypes);
85}
86export default Portal;
\No newline at end of file