= createRef();
@state() private viewMode: "preview" | "code" = "preview";
private setViewMode(mode: "preview" | "code") {
this.viewMode = mode;
}
public getHeaderButtons() {
const toggle = new PreviewCodeToggle();
toggle.mode = this.viewMode;
toggle.addEventListener("mode-change", (e: Event) => {
this.setViewMode((e as CustomEvent).detail);
});
const copyButton = new CopyButton();
copyButton.text = this._content;
copyButton.title = i18n("Copy HTML");
copyButton.showText = false;
// Generate standalone HTML with all runtime code injected for download
const sandbox = this.sandboxIframeRef.value;
const sandboxId = `artifact-${this.filename}`;
const downloadContent =
sandbox?.prepareHtmlDocument(sandboxId, this._content, this.runtimeProviders || [], {
isHtmlArtifact: true,
isStandalone: true, // Skip runtime bridge and navigation interceptor for standalone downloads
}) || this._content;
return html`
${toggle}
${Button({
variant: "ghost",
size: "sm",
onClick: () => {
this.logs = [];
this.executeContent(this._content);
},
title: i18n("Reload HTML"),
children: icon(RefreshCw, "sm"),
})}
${copyButton}
${DownloadButton({ content: downloadContent, filename: this.filename, mimeType: "text/html", title: i18n("Download HTML") })}
`;
}
override set content(value: string) {
const oldValue = this._content;
this._content = value;
if (oldValue !== value) {
// Reset logs when content changes
this.logs = [];
this.requestUpdate();
// Execute content in sandbox if it exists
if (this.sandboxIframeRef.value && value) {
this.executeContent(value);
}
}
}
public executeContent(html: string) {
const sandbox = this.sandboxIframeRef.value;
if (!sandbox) return;
// Configure sandbox URL provider if provided (for browser extensions)
if (this.sandboxUrlProvider) {
sandbox.sandboxUrlProvider = this.sandboxUrlProvider;
}
const sandboxId = `artifact-${this.filename}`;
// Create consumer for console messages
const consumer: MessageConsumer = {
handleMessage: async (message: any): Promise => {
if (message.type === "console") {
// Create new array reference for Lit reactivity
this.logs = [
...this.logs,
{
type: message.method === "error" ? "error" : "log",
text: message.text,
},
];
this.requestUpdate(); // Re-render to show console
}
},
};
// Inject window.complete() call at the end of the HTML to signal when page is loaded
// HTML artifacts don't time out - they call complete() when ready
let modifiedHtml = html;
if (modifiedHtml.includes("