PreviewFrame

import { PreviewFrame, PHONE } from '@hanzo/ui/agents'

Framed

A deployed page on its own origin, with the floating edit toolbar over it.

export function Framed() {
const frame = useRef<PreviewHandle>(null)
const [picking, setPicking] = useState(false)
return (
<YStack width="100%" height={360} gap="$2">
<XStack>
<Button variant="ghost" size="icon-sm" aria-label="Reload preview" onClick={() => frame.current?.reload()}>
<RefreshCw size={15} />
</Button>
</XStack>
<PreviewFrame
ref={frame}
src="https://hanzo.ai/"
title="Preview of hanzo.ai"
onBridge={(event) => event.type === 'preview:select' && setPicking(false)}
toolbar={
<>
<Button variant="ghost" size="icon-sm" aria-label="Pick an element" aria-pressed={picking} onClick={() => { setPicking(!picking) frame.current?.post({ type: 'preview:editable', active: !picking }) }} >
<WandSparkles size={15} />
</Button>
<Button variant="ghost" size="icon-sm" aria-label="More">
<MoreVertical size={15} />
</Button>
</>
}
/>
</YStack>
)
}

Phone

The same page in a phone-wide column.

export function Phone() {
return (
<YStack width="100%" height={360}>
<PreviewFrame src="https://hanzo.ai/" device="mobile" />
</YStack>
)
}

Empty

No address yet: nothing has been deployed.

Nothing deployed yet.Describe what to build and the running app appears here.
export function Empty() {
return (
<YStack width="100%" height={220}>
<PreviewFrame src={null} />
</YStack>
)
}

Types

export interface PreviewHandle {
/** Load the address again. */
reload(): void
/** Say something to a page running the bridge. Dropped when there is none. */
post(command: FrameCommand): void
}
export interface PreviewFrameProps extends Col {
/** The address to frame. Anything but http(s) is refused. */
src?: string | null
/** The frame's accessible name. */
title?: string
/** Desktop fills the pane; mobile is a phone-wide column. */
device?: 'desktop' | 'mobile'
/** Drawn when there is no address — nothing deployed yet. */
empty?: ReactNode
/** A floating bar over the bottom of the frame — v2's edit toolbar. */
toolbar?: ReactNode
/** Messages from a page running the bridge. */
onBridge?: (event: FrameEvent) => void
/** Called once the frame has loaded. */
onLoad?: () => void
/**
* The handle — `reload()` and `post()`. A plain prop (React 19), not
* `forwardRef`: the wrapper's `Omit<Props, 'ref'>` collapses these props to
* `any` against gui's index signature, and every caller loses their types.
*/
ref?: Ref<PreviewHandle>
}

Exports

PreviewFramePHONEtype PreviewFramePropstype PreviewHandle