import { readFileSync } from "node:fs"; import { renderComponent } from "../../test/src/index.ts"; import { CORE_COMPONENT_CONTRACTS, type DesignSystem } from "../../design-system/src/index.ts"; import { resolveThemeConfig, renderThemeCss } from "../../styles/src/theme.ts"; import { renderDocument } from "../../ssr/src/index.ts"; import { uiCss } from "../src/registry.ts"; import { getReactiveRuntime } from "../../csr/src/index.ts"; import { runWithRequestContext } from "../../core/src/index.ts"; let fixture: Promise | undefined; export function designFixtureBody(): Promise { return (fixture ??= (async () => { const render = ( name: keyof typeof CORE_COMPONENT_CONTRACTS, props: Record = {}, ) => { let source = readFileSync(CORE_COMPONENT_CONTRACTS[name].source, "utf8"); // The isolated renderer has no parent slot distributor; provide authored trigger content. if (name === "ContextMenu") source = source.replace('', "More options"); return renderComponent(source, props); }; const [ nav, heading, input, select, textarea, checkbox, radio, toggle, save, cancel, loading, disabled, card, alert, modal, menu, ] = await Promise.all([ render("Nav", { items: [ { label: "Profile", href: "#profile", value: "profile" }, { label: "Preferences", href: "#preferences", value: "preferences" }, ], active: "profile", collapsible: false, }), render("PageHeader", { title: "Design system preview", description: "The same components, content, and behavior in three visual systems.", }), render("Input", { id: "display-name", name: "displayName", label: "Display name", placeholder: "Your name", }), render("Select", { id: "language", name: "language", label: "Language", value: "en", options: [ { value: "en", label: "English" }, { value: "hi", label: "Hindi" }, ], }), render("Textarea", { id: "bio", name: "bio", label: "About you", placeholder: "Add a short introduction", }), render("Checkbox", { id: "remember", name: "remember", label: "Remember preferences" }), render("Radio", { name: "density", label: "Page density", options: [ { value: "comfortable", label: "Comfortable" }, { value: "compact", label: "Compact" }, ], value: "comfortable", }), render("Switch", { id: "updates", name: "updates", label: "Email updates" }), render("Button", { label: "Save changes" }), render("Button", { label: "Cancel", variant: "ghost" }), render("Button", { label: "Save changes", loading: true }), render("Button", { label: "Unavailable", disabled: true }), render("Card", { title: "Profile", description: "Update your profile and choose how this application works for you.", }), render("Alert", { title: "Preview only", description: "Changes on this page are not sent to a server.", color: "info", showIcon: true, dismissible: true, }), render("Modal", { title: "Review changes", description: "Check your preferences before continuing.", triggerLabel: "Open dialog", confirmLabel: "Continue", }), render("ContextMenu", { trigger: "click", label: "More options", items: [ { label: "View profile", value: "profile" }, { label: "Reset preferences", value: "reset" }, ], }), ]); return `${nav}${heading}
${card}
${input}${select}${textarea}
${toggle}${checkbox}${radio}
${save}${cancel}
`; })()); } export const PREVIEW_CSS = `*{box-sizing:border-box}body{margin:0;padding:clamp(1rem,4vw,3rem);background:var(--wrn-color-bg);color:var(--wrn-color-text);font-family:var(--wrn-font-sans);line-height:1.5}body>#app{max-width:1120px;margin:auto}.design-preview-grid{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);gap:2rem}.design-preview-form,.design-preview-aside,form{display:grid;gap:1.25rem;align-content:start;min-width:0}.design-preview-actions{display:flex;flex-wrap:wrap;gap:1rem;align-items:center}h2{font-size:1.125rem;margin:0 0 1rem}.preview-controls{display:flex;flex-wrap:wrap;gap:1rem;align-items:center;margin-bottom:2rem;font:0.875rem system-ui}.preview-controls a{color:inherit;text-underline-offset:4px}@media(max-width:720px){.design-preview-grid{grid-template-columns:1fr}.design-preview-actions{gap:0.75rem}}`; export async function designFixtureDocument( system: DesignSystem, mode = "light", delivery: "inline" | "linked" = "inline", ): Promise { const theme = resolveThemeConfig({ designSystem: { system }, default: mode }); const themeCss = renderThemeCss(theme); const themeHead = delivery === "inline" ? `` : ``; const controls = ``; const body = controls + (await designFixtureBody()); return runWithRequestContext({} as never, () => renderDocument({ meta: { title: `${system.name} — Component preview` }, body, htmlAttrs: ` data-theme="${mode}"`, extraHead: `${themeHead}`, componentRecipeCss: theme.recipeCss, styleNonce: "design-preview", extraBody: ``, }), ); }