import * as React from 'react' ; import { useSandpack , LoadingOverlay } from '@codesandbox/sandpack-react' ; import cn from 'classnames' ; import { Error } from './Error' ; import { computeViewportSize , generateRandomId } from './utils' ; type CustomPreviewProps = { className ? : string ; customStyle : Record < string , unknown > ; isExpanded : boolean ; } ; function useDebounced ( value ) { const ref = React . useRef < any > ( null ) ; const [ saved , setSaved ] = React . useState ( value ) ; React . useEffect ( ( ) => { clearTimeout ( ref . current ) ; ref . current = setTimeout ( ( ) => { setSaved ( value ) ; } , 300 ) ; } , [ value ] ) ; return saved ; } export function Preview ( { customStyle , isExpanded , className , } ) { const { sandpack , listen } = useSandpack ( ) ; const [ isReady , setIsReady ] = React . useState ( false ) ; const [ iframeComputedHeight , setComputedAutoHeight ] = React . useState < number | null > ( null ) ; let { error : rawError , registerBundler , unregisterBundler , errorScreenRegisteredRef , openInCSBRegisteredRef , loadingScreenRegisteredRef , } = sandpack ; if ( rawError && rawError . message === '_csbRefreshUtils.prelude is not a function' ) { rawError = null ; } const error = useDebounced ( rawError ) ; const clientId = React . useRef < string > ( generateRandomId ( ) ) ; const iframeRef = React . useRef < HTMLIFrameElement | null > ( null ) ; openInCSBRegisteredRef . current = true ; errorScreenRegisteredRef . current = true ; loadingScreenRegisteredRef . current = true ; React . useEffect ( ( ) => { const iframeElement = iframeRef . current ! ; registerBundler ( iframeElement , clientId . current ) ; const unsub = listen ( ( message ) => { if ( message . type === 'resize' ) { setComputedAutoHeight ( message . height ) ; } else if ( message . type === 'start' ) { if ( message . firstLoad ) { setIsReady ( false ) ; } } else if ( message . type === 'test' ) { setIsReady ( true ) ; } } , clientId . current ) ; return ( ) => { unsub ( ) ; unregisterBundler ( clientId . current ) ; } ; } , [ ] ) ; const viewportStyle = computeViewportSize ( 'auto' , 'portrait' ) ; const overrideStyle = error ? { maxHeight : undefined , } : null ; const hideContent = ! isReady || error ; return ( < div className = { cn ( 'sp-stack' , className ) } style = { { ... customStyle , ... viewportStyle , ... overrideStyle , } } > < div className = { cn ( 'p-0 sm:p-2 md:p-4 lg:p-8 bg-card dark:bg-wash-dark h-full relative rounded-b-lg lg:rounded-b-none' , ! isExpanded && ! error && isReady ? 'overflow-auto' : null ) } > < div style = { { padding : 'initial' , position : hideContent ? 'relative' : isExpanded ? 'sticky' : undefined , top : isExpanded ? '2rem' : undefined , } } > < iframe ref = { iframeRef } className = { cn ( 'rounded-t-none bg-white shadow-md sm:rounded-lg w-full max-w-full' , hideContent ? 'absolute opacity-0 pointer-events-none' : 'opacity-100' ) } title = "Sandbox Preview" style = { { height : iframeComputedHeight || '100%' , zIndex : isExpanded ? 'initial' : - 1 , } } /> < /div> { error && ( < div className = { cn ( 'p-2' , isExpanded ? 'sticky top-8' : null ) } > < Error error = { error } /> < /div>)} < LoadingOverlay clientId = { clientId . current } / > < /div> < /div>); }