fix(web): restore HTML preview after source toggle (#2699) (#2710)

This commit is contained in:
shangxinyu1 2026-05-22 22:51:38 +08:00 committed by GitHub
parent f2703c8cb3
commit ac0a9212fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 0 deletions

View file

@ -6323,6 +6323,11 @@ function HtmlViewer({
onLoad={() => {
const frame = srcDocPreviewIframeRef.current;
if (!useUrlLoadPreview) iframeRef.current = frame;
// Any srcDoc iframe load means we are talking to a
// fresh document shell. Clear the activation dedupe so
// switching preview -> source -> preview cannot strand
// the new shell on the blank transport page.
activatedSrcDocTransportHtmlRef.current = null;
// Belt-and-suspenders for the ready handshake: if the
// postMessage racing the parent's listener registration
// ever loses, the load event still tells us the shell

View file

@ -436,6 +436,59 @@ describe('FileViewer SVG artifacts', () => {
});
});
it('reactivates the srcDoc transport after switching source back to preview', async () => {
const file = baseFile({
name: 'page.html',
path: 'page.html',
mime: 'text/html',
kind: 'html',
artifactManifest: {
version: 1,
kind: 'html',
title: 'Page',
entry: 'page.html',
renderer: 'html',
exports: ['html'],
},
});
render(
<FileViewer
projectId="project-1"
projectKind="prototype"
file={file}
liveHtml='<html><body><main data-od-id="hero">Hero</main></body></html>'
/>,
);
fireEvent.click(screen.getByTestId('inspect-mode-toggle'));
await waitFor(() => {
const activeFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
expect(activeFrame.getAttribute('data-od-render-mode')).toBe('srcdoc');
});
fireEvent.click(screen.getByRole('button', { name: 'Preview' }));
fireEvent.click(screen.getByRole('menuitem', { name: 'Code' }));
expect(screen.queryByTestId('artifact-preview-frame')).toBeNull();
fireEvent.click(screen.getByRole('button', { name: 'Code' }));
fireEvent.click(screen.getByRole('menuitem', { name: 'Preview' }));
const remountedFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
const postMessageSpy = vi.spyOn(remountedFrame.contentWindow!, 'postMessage');
await waitFor(() => {
const activeFrame = screen.getByTestId('artifact-preview-frame') as HTMLIFrameElement;
expect(activeFrame.getAttribute('data-od-render-mode')).toBe('srcdoc');
});
await waitFor(() => {
const activations = srcDocActivationMessages(postMessageSpy.mock.calls);
expect(activations.at(-1)?.html).toContain('data-od-selection-bridge');
expect(activations.at(-1)?.html).toContain('Hero');
});
});
it('uses the next file URL immediately when switching URL-loaded HTML previews', () => {
const first = baseFile({
name: 'first.html',