@@ -3,13 +3,12 @@ import { outputsDeltasQuery, processDeltas } from "@/queries/outputDeltas";
33import { CellType , OutputData , SAFE_MIME_TYPES } from "@runtimed/schema" ;
44import { groupConsecutiveStreamOutputs } from "@/util/output-grouping" ;
55import { useQuery } from "@livestore/react" ;
6- import { useMemo , useState , useRef , useEffect } from "react" ;
7- import { useIframeCommsParent } from "./shared-with-iframe/comms" ;
6+ import { useMemo } from "react" ;
87import { SingleOutput } from "./shared-with-iframe/SingleOutput" ;
9- import { useDebounce } from "react-use" ;
108import { OutputsContainer } from "./shared-with-iframe/OutputsContainer" ;
119import { SuspenseSpinner } from "./shared-with-iframe/SuspenseSpinner" ;
1210import { MaybeFixCodeButton } from "./MaybeFixCodeButton" ;
11+ import { IframeOutput } from "./IframeOutput" ;
1312
1413/**
1514 * TODO: consider renaming this component
@@ -88,82 +87,6 @@ export const MaybeCellOutputs = ({
8887 ) ;
8988} ;
9089
91- interface IframeOutputProps {
92- outputs : OutputData [ ] ;
93- style ?: React . CSSProperties ;
94- className ?: string ;
95- onHeightChange ?: ( height : number ) => void ;
96- isReact ?: boolean ;
97- defaultHeight ?: string ;
98- onDoubleClick ?: ( ) => void ;
99- onMarkdownRendered ?: ( ) => void ;
100- cellType ?: CellType ;
101- }
102-
103- export const IframeOutput : React . FC < IframeOutputProps > = ( {
104- outputs,
105- className,
106- style,
107- isReact,
108- onHeightChange,
109- defaultHeight = "0px" ,
110- onDoubleClick,
111- onMarkdownRendered,
112- cellType,
113- } ) => {
114- const { iframeRef, iframeHeight } = useIframeCommsParent ( {
115- defaultHeight,
116- onHeightChange,
117- outputs,
118- onDoubleClick,
119- onMarkdownRendered,
120- } ) ;
121-
122- const [ debouncedIframeHeight , setDebouncedIframeHeight ] =
123- useState ( iframeHeight ) ;
124-
125- // Iframe can get height updates pretty often, but we want to avoid layout jumping each time
126- // TODO: ensure that it's a leading debounce!
127- useDebounce ( ( ) => setDebouncedIframeHeight ( iframeHeight ) , 50 , [ iframeHeight ] ) ;
128-
129- const isAiCell = cellType === "ai" ;
130- const scrollContainerRef = useRef < HTMLDivElement > ( null ) ;
131-
132- // Auto-scroll to bottom when content changes for AI cells
133- useEffect ( ( ) => {
134- if ( isAiCell && scrollContainerRef . current ) {
135- const container = scrollContainerRef . current ;
136- container . scrollTop = container . scrollHeight ;
137- }
138- } , [ isAiCell , outputs , debouncedIframeHeight ] ) ;
139-
140- const iframeElement = (
141- < iframe
142- src = {
143- import . meta. env . VITE_IFRAME_OUTPUT_URI + ( isReact ? "/react.html" : "" )
144- }
145- ref = { iframeRef }
146- className = { className }
147- width = "100%"
148- height = { debouncedIframeHeight }
149- style = { style }
150- allow = "accelerometer; autoplay; gyroscope; magnetometer; xr-spatial-tracking; clipboard-write; fullscreen"
151- sandbox = "allow-downloads allow-forms allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-storage-access-by-user-activation allow-modals allow-top-navigation-by-user-activation"
152- loading = "lazy"
153- />
154- ) ;
155-
156- if ( isAiCell ) {
157- return (
158- < div ref = { scrollContainerRef } className = "max-h-[30vh] overflow-y-auto" >
159- { iframeElement }
160- </ div >
161- ) ;
162- }
163-
164- return iframeElement ;
165- } ;
166-
16790const hasUnsafeOutputs = ( outputs : OutputData [ ] ) => {
16891 return outputs . some ( ( output ) => {
16992 return ! SAFE_MIME_TYPES . includes ( output . mimeType as any ) ;
0 commit comments