var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import hljs from "highlight.js"; import { html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { createRef, ref } from "lit/directives/ref.js"; import { unsafeHTML } from "lit/directives/unsafe-html.js"; import { RefreshCw } from "lucide"; import { RUNTIME_MESSAGE_ROUTER } from "../../components/sandbox/RuntimeMessageRouter.js"; import { i18n } from "../../utils/i18n.js"; import "../../components/SandboxedIframe.js"; import { ArtifactElement } from "./ArtifactElement.js"; import "./Console.js"; import { icon } from "@mariozechner/mini-lit"; import { Button } from "@mariozechner/mini-lit/dist/Button.js"; import { CopyButton } from "@mariozechner/mini-lit/dist/CopyButton.js"; import { DownloadButton } from "@mariozechner/mini-lit/dist/DownloadButton.js"; import { PreviewCodeToggle } from "@mariozechner/mini-lit/dist/PreviewCodeToggle.js"; let HtmlArtifact = class HtmlArtifact extends ArtifactElement { constructor() { super(...arguments); this.filename = ""; this.runtimeProviders = []; this._content = ""; this.logs = []; // Refs for DOM elements this.sandboxIframeRef = createRef(); this.consoleRef = createRef(); this.viewMode = "preview"; } setViewMode(mode) { this.viewMode = mode; } getHeaderButtons() { const toggle = new PreviewCodeToggle(); toggle.mode = this.viewMode; toggle.addEventListener("mode-change", (e) => { this.setViewMode(e.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") })}
`; } set content(value) { 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); } } } executeContent(html) { 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 = { handleMessage: async (message) => { 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("")) { modifiedHtml = modifiedHtml.replace("", ""); } else { // If no closing tag, append the script modifiedHtml += ""; } // Load content - this handles sandbox registration, consumer registration, and iframe creation sandbox.loadContent(sandboxId, modifiedHtml, this.runtimeProviders, [consumer]); } get content() { return this._content; } disconnectedCallback() { super.disconnectedCallback(); // Unregister sandbox when element is removed from DOM const sandboxId = `artifact-${this.filename}`; RUNTIME_MESSAGE_ROUTER.unregisterSandbox(sandboxId); } firstUpdated() { // Execute initial content if (this._content && this.sandboxIframeRef.value) { this.executeContent(this._content); } } updated(changedProperties) { super.updated(changedProperties); // If we have content but haven't executed yet (e.g., during reconstruction), // execute when the iframe ref becomes available if (this._content && this.sandboxIframeRef.value && this.logs.length === 0) { this.executeContent(this._content); } } getLogs() { if (this.logs.length === 0) return i18n("No logs for {filename}").replace("{filename}", this.filename); return this.logs.map((l) => `[${l.type}] ${l.text}`).join("\n"); } render() { return html `
${this.logs.length > 0 ? html `` : ""}
${unsafeHTML(hljs.highlight(this._content, { language: "html" }).value)}
`; } }; __decorate([ property() ], HtmlArtifact.prototype, "filename", void 0); __decorate([ property({ attribute: false }) ], HtmlArtifact.prototype, "runtimeProviders", void 0); __decorate([ property({ attribute: false }) ], HtmlArtifact.prototype, "sandboxUrlProvider", void 0); __decorate([ state() ], HtmlArtifact.prototype, "viewMode", void 0); HtmlArtifact = __decorate([ customElement("html-artifact") ], HtmlArtifact); export { HtmlArtifact }; //# sourceMappingURL=HtmlArtifact.js.map