44 * SPDX-License-Identifier: BSD-3-Clause
55 */
66
7- import React , { useEffect , useRef } from 'react' ;
7+ import React , { createContext , useContext , useEffect , useRef } from 'react' ;
88import { createPortal } from 'react-dom' ;
99
10+ const ClayPortalContext = createContext < React . RefObject < Element | null > | null > (
11+ null
12+ ) ;
13+
14+ ClayPortalContext . displayName = 'ClayPortalContext' ;
15+
1016export const ClayPortal : React . FunctionComponent <
11- React . HTMLAttributes < HTMLDivElement >
12- > = ( { children} ) => {
17+ React . HTMLAttributes < HTMLDivElement > & {
18+ /**
19+ * Ref of element to render portal into.
20+ */
21+ containerRef ?: React . RefObject < Element > ;
22+
23+ /**
24+ * Ref of element to render nested portals into.
25+ */
26+ subPortalRef ?: React . RefObject < Element > ;
27+ }
28+ > = ( { children, containerRef, subPortalRef} ) => {
29+ const parentPortalRef = useContext ( ClayPortalContext ) ;
1330 const portalRef = useRef (
14- typeof document !== 'undefined' && document . createElement ( 'div' )
31+ typeof document !== 'undefined' ? document . createElement ( 'div' ) : null
1532 ) ;
16- const elToMountTo = typeof document !== 'undefined' && document . body ;
1733
1834 useEffect ( ( ) => {
35+ const closestParent =
36+ parentPortalRef && parentPortalRef . current
37+ ? parentPortalRef . current
38+ : document . body ;
39+
40+ const elToMountTo =
41+ containerRef && containerRef . current
42+ ? containerRef . current
43+ : closestParent ;
44+
1945 if ( elToMountTo && portalRef . current ) {
2046 elToMountTo . appendChild ( portalRef . current ) ;
2147 }
@@ -24,11 +50,17 @@ export const ClayPortal: React.FunctionComponent<
2450 elToMountTo . removeChild ( portalRef . current ) ;
2551 }
2652 } ;
27- } , [ elToMountTo ] ) ;
53+ } , [ containerRef , parentPortalRef ] ) ;
2854
29- if ( portalRef . current ) {
30- return createPortal ( children , portalRef . current ) ;
31- }
55+ const content = (
56+ < ClayPortalContext . Provider
57+ value = { subPortalRef ? subPortalRef : portalRef }
58+ >
59+ { children }
60+ </ ClayPortalContext . Provider >
61+ ) ;
3262
33- return < > { children } </ > ;
63+ return portalRef . current
64+ ? createPortal ( content , portalRef . current )
65+ : content ;
3466} ;
0 commit comments