import { useRef , useEffect , forwardRef , useState , createContext , useContext } from 'react' ; import { useCurrentShadowRootStyles } from './ShadowRootStyleProvider' ; import type { PopperProps } from '@mui/material' ; /**
 * ! Do not export !
 *
 * You SHOULD NOT use this in React directly
 */ let mountingPoint ; let mountingShadowRoot ; export function setupPortalShadowRoot ( init , preventEventPropagationList ) { if ( mountingPoint ) return mountingShadowRoot ! ; mountingShadowRoot = document . body . appendChild ( document . createElement ( 'div' ) ) . attachShadow ( init ) ; for ( const each of preventEventPropagationList ) { mountingShadowRoot . addEventListener ( each , ( e ) => e . stopPropagation ( ) ) ; } mountingPoint = mountingShadowRoot . appendChild ( document . createElement ( 'div' ) ) ; return mountingShadowRoot ! ; } /** usePortalShadowRoot under this context does not do anything. (And it will return an empty container). */ export const NoEffectUsePortalShadowRootContext = createContext ( false ) ; param renderer example export function usePortalShadowRoot ( renderer ) { const disabled = useRef ( useContext ( NoEffectUsePortalShadowRootContext ) ) . current ; if ( disabled ) return renderer ( undefined ) ; const [ findMountingShadowRef , setRef ] = useState < HTMLSpanElement | null > ( null ) ; const doms = useSideEffectRef ( ( ) => { const root = document . createElement ( 'div' ) ; const container = root . appendChild ( document . createElement ( 'div' ) ) ; const style = root . appendChild ( document . createElement ( 'style' ) ) ; return { root , container , style } ; } ) ; const { container } = doms ; return ( < IsolatedRender { ... doms } findMountingShadowRef = { findMountingShadowRef } > < span style = { { display : 'none' } } ref = { ( ref ) => findMountingShadowRef !== ref && setRef ( ref ) } /> { renderer ( container ) } < /IsolatedRender>); } type IsolatedRenderProps = React . PropsWithChildren < { root : HTMLElement ; container : HTMLElement ; style : HTMLStyleElement ; findMountingShadowRef : HTMLSpanElement | null ; } > ; const IsolatedRender = ( { container , root , style , children , findMountingShadowRef } ) => { const update = useUpdate ( ) ; const css = useCurrentShadowRootStyles ( findMountingShadowRef ) ; const containerInUse = container . children . length !== 0 ; useEffect ( ( ) => { container . appendChild = bind ( container . appendChild , container , update ) ; container . removeChild = bind ( container . removeChild , container , update ) ; } , [ ] ) ; useEffect ( ( ) => { if ( ! containerInUse ) return root . remove ( ) ; const shadow = PortalShadowRoot ( ) ; if ( root . parentElement === shadow ) return ; shadow . appendChild ( root ) ; } , [ containerInUse , root ] ) ; useEffect ( ( ) => { if ( findMountingShadowRef && style . innerHTML !== css ) style . innerHTML = css ; } , [ style , css , findMountingShadowRef ] ) ; return children as any ; } ; export function createShadowRootForwardedComponent < T extends { container ? : Element | ( ( ) => Element | null ) | null | undefined ; open : boolean ; } > ( Component ) { return forwardRef ( ( props , ref ) => { return usePortalShadowRoot ( ( container ) => < Component container = { container } { ... props } ref = { ref } / > ) ; } ) as any as typeof Component ; } export function createShadowRootForwardedPopperComponent < T extends { PopperProps ? : Partial < PopperProps > ; } > ( Component ) { return forwardRef ( ( props , ref ) => { return usePortalShadowRoot ( ( container ) => { return < Component { ... props } PopperProps = { { container , ... props . PopperProps } } ref = { ref } / > ; } ) ; } ) as any as typeof Component ; } /**
 * ! Do not export !
 */ function PortalShadowRoot ( ) { if ( location . protocol . includes ( 'extension' ) ) return document . body ; if ( globalThis . location . hostname === 'localhost' ) return document . body ; if ( ! mountingPoint ) throw new TypeError ( 'Please call setupPortalShadowRoot first' ) ; return mountingPoint ; } function bind ( f , thisArg , hook ) { return ( ... args ) => { try { return f . apply ( thisArg , args ) ; } finally { hook ( ) ; } } ; } function useUpdate ( ) { const [ , _update ] = useState ( 0 ) ; return ( ) => _update ( ( i ) => i + 1 ) ; } function useSideEffectRef < T > ( f ) { const ref = useRef < T > ( undefined ! ) ; if ( ! ref . current ) ref . current = f ( ) ; return ref . current ; }