/** @jsxImportSource sinho */ import { Component, prop, Style, css, defineComponents, useSignal, useEffect, MaybeSignal, } from "sinho"; export class Playground extends Component("x-playground", { colorMode: prop<"light" | "dark">("light", { attribute: (value) => (value === "dark" ? value : "light"), }), headerText: prop("Preview", { attribute: String, }), importMap: prop<{ imports: Record }>( { imports: {} }, { attribute: JSON.parse }, ), customCode: prop("", { attribute: String, }), autosize: prop(false, { attribute: () => true, }), }) { render() { const [src, setSrc] = useSignal( "document.body.innerHTML = '

Loading…

';", ); const [error, setError] = useSignal(); useEffect(() => { setError(undefined); const customCode = this.props.customCode(); (async () => { try { const swc = await import("@swc/wasm-web"); await swc.default(); const { code } = swc.transformSync(customCode, { jsc: { target: "es2022", parser: { syntax: "typescript", tsx: true, }, transform: { react: { runtime: "automatic", importSource: "sinho", }, }, }, }); setSrc(code); } catch (err) { setError(new Error((err as string).replace(/\x1B\[.*?m/g, ""))); } })(); }); const iframeCss = css` @import url("https://rsms.me/inter/inter.css"); body { background: ${() => this.props.colorMode() == "light" ? "#f6f8fa" : "#282a36"}; color: ${() => this.props.colorMode() == "light" ? "#1c1e21" : "#e3e3e3"}; font-family: "Inter", sans-serif; margin: 0; padding: 0.5em 1em; overflow: ${() => (this.props.autosize() ? "hidden" : "auto")}; } `; const jsBlob = () => new Blob( [ error() == null ? src() : `\ document.body.innerHTML = '

Error loading preview:

';
              document.getElementById("error").innerText = ${JSON.stringify(
                error()!.message,
              )};`,
        ],
        { type: "application/javascript" },
      );

    const htmlBlob = () =>
      new Blob(
        [
          `
          
          
          
          
          
          
          
          
          
          `,
        ],
        { type: "text/html" },
      );

    return (
      <>
        
{this.props.headerText}