11"use client"
22
33import { useCallback , useEffect , useMemo , useRef , useState } from "react"
4+ import { createPortal } from "react-dom"
45import type { ChangeEvent , MouseEvent } from "react"
56import { Copy , Download , X } from "lucide-react"
67
@@ -15,6 +16,7 @@ export default function FinalOutputView({ fileName, fileContent, mimeType, onClo
1516 const dialogRef = useRef < HTMLDivElement | null > ( null )
1617 const [ baselineContent , setBaselineContent ] = useState ( fileContent ?? "" )
1718 const [ currentContent , setCurrentContent ] = useState ( fileContent ?? "" )
19+ const [ isMounted , setIsMounted ] = useState ( false )
1820
1921 const normalizedFileName = useMemo ( ( ) => {
2022 const trimmed = fileName ?. trim ( )
@@ -36,6 +38,18 @@ export default function FinalOutputView({ fileName, fileContent, mimeType, onClo
3638 } , [ baselineContent , normalizedFileName ] )
3739
3840 useEffect ( ( ) => {
41+ setIsMounted ( true )
42+
43+ return ( ) => {
44+ setIsMounted ( false )
45+ }
46+ } , [ ] )
47+
48+ useEffect ( ( ) => {
49+ if ( ! isMounted ) {
50+ return undefined
51+ }
52+
3953 const previousOverflow = document . body . style . overflow
4054 document . body . style . overflow = "hidden"
4155
@@ -52,10 +66,11 @@ export default function FinalOutputView({ fileName, fileContent, mimeType, onClo
5266 if ( resetTimerRef . current !== null ) {
5367 window . clearTimeout ( resetTimerRef . current )
5468 }
69+
5570 document . body . style . overflow = previousOverflow
5671 window . removeEventListener ( "keydown" , handleKeyDown )
5772 }
58- } , [ onClose ] )
73+ } , [ onClose , isMounted ] )
5974
6075 const handleCopyClick = useCallback ( async ( ) => {
6176 if ( ! currentContent ) {
@@ -135,7 +150,7 @@ export default function FinalOutputView({ fileName, fileContent, mimeType, onClo
135150 const displayedContent = currentContent && currentContent . length > 0 ? currentContent : ""
136151 const restoreDisabled = displayedContent === baselineContent
137152
138- return (
153+ const modalContent = (
139154 < div
140155 className = "fixed inset-0 z-50 flex items-center justify-center bg-background/80 p-4 backdrop-blur-sm overscroll-contain"
141156 role = "dialog"
@@ -213,4 +228,10 @@ export default function FinalOutputView({ fileName, fileContent, mimeType, onClo
213228 </ div >
214229 </ div >
215230 )
231+
232+ if ( ! isMounted || typeof document === "undefined" ) {
233+ return null
234+ }
235+
236+ return createPortal ( modalContent , document . body )
216237}
0 commit comments