@vizejs/vite-plugin-musea 0.0.1-alpha.81 → 0.0.1-alpha.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{a11y-ClVMxbud.d.ts → a11y-CHcxz6UR.d.ts} +2 -2
- package/dist/{a11y-ClVMxbud.d.ts.map → a11y-CHcxz6UR.d.ts.map} +1 -1
- package/dist/a11y.d.ts +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +220 -10
- package/dist/index.js.map +1 -1
- package/dist/{vrt-CC29JrCN.d.ts → vrt-m01uFerp.d.ts} +53 -3
- package/dist/vrt-m01uFerp.d.ts.map +1 -0
- package/dist/vrt.d.ts +1 -1
- package/package.json +6 -4
- package/dist/vrt-CC29JrCN.d.ts.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A11yOptions, A11yResult, ArtFileInfo, MuseaVrtRunner$1 as MuseaVrtRunner } from "./vrt-
|
|
1
|
+
import { A11yOptions, A11yResult, ArtFileInfo, MuseaVrtRunner$1 as MuseaVrtRunner } from "./vrt-m01uFerp.js";
|
|
2
2
|
import { Page } from "playwright";
|
|
3
3
|
|
|
4
4
|
//#region src/a11y.d.ts
|
|
@@ -58,4 +58,4 @@ declare class MuseaA11yRunner {
|
|
|
58
58
|
|
|
59
59
|
//# sourceMappingURL=a11y.d.ts.map
|
|
60
60
|
export { A11ySummary, MuseaA11yRunner as MuseaA11yRunner$1 };
|
|
61
|
-
//# sourceMappingURL=a11y-
|
|
61
|
+
//# sourceMappingURL=a11y-CHcxz6UR.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a11y-
|
|
1
|
+
{"version":3,"file":"a11y-CHcxz6UR.d.ts","names":[],"sources":["../src/a11y.ts"],"sourcesContent":null,"mappings":";;;;;;;;AAmBA;;;UAAiB,WAAA;EA4BJ,eAAA,EAAA,MAAe;EAAA,aAAA,EAAA,MAAA;EAAA,eAGL,EAAA,MAAA;EAAgB,aAczB,EAAA,MAAA;EAAW,YAET,EAAA,MAAA;EAAc,aACjB,EAAA,MAAA;EAAU,UAAlB,EAAA,MAAA;;;;;AAkGgC,cAtHxB,eAAA,CAsHwB;EAAW,QAkBlB,OAAA;EAAU,WA6IV,CAAA,OAAA,CAAA,EAlRP,WAkRO;EAAU;;;;sBApQ1B,4CAEE,iBACX,QAAQ;;;;kBA+DW,6CAA6C,QAAQ;;;;sBAmCvD,eAAe;;;;8BAkBP;;;;8BA6IA"}
|
package/dist/a11y.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./vrt-
|
|
2
|
-
import { A11ySummary, MuseaA11yRunner$1 as MuseaA11yRunner } from "./a11y-
|
|
1
|
+
import "./vrt-m01uFerp.js";
|
|
2
|
+
import { A11ySummary, MuseaA11yRunner$1 as MuseaA11yRunner } from "./a11y-CHcxz6UR.js";
|
|
3
3
|
export { A11ySummary, MuseaA11yRunner };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A11yOptions, A11yResult, AnalysisApiResponse, ArtFileInfo, ArtMetadata, ArtVariant, CaptureConfig, CiConfig, ComparisonConfig, CsfOutput, MuseaOptions, MuseaVrtRunner$1 as MuseaVrtRunner, PaletteApiResponse, ViewportConfig, VrtOptions, VrtResult, VrtSummary, generateVrtJsonReport$1 as generateVrtJsonReport, generateVrtReport$1 as generateVrtReport } from "./vrt-
|
|
2
|
-
import { A11ySummary, MuseaA11yRunner$1 as MuseaA11yRunner } from "./a11y-
|
|
1
|
+
import { A11yOptions, A11yResult, AnalysisApiResponse, ArtFileInfo, ArtMetadata, ArtVariant, CaptureConfig, CiConfig, ComparisonConfig, CsfOutput, MuseaOptions, MuseaTheme, MuseaThemeColors, MuseaVrtRunner$1 as MuseaVrtRunner, PaletteApiResponse, ViewportConfig, VrtOptions, VrtResult, VrtSummary, generateVrtJsonReport$1 as generateVrtJsonReport, generateVrtReport$1 as generateVrtReport } from "./vrt-m01uFerp.js";
|
|
2
|
+
import { A11ySummary, MuseaA11yRunner$1 as MuseaA11yRunner } from "./a11y-CHcxz6UR.js";
|
|
3
3
|
import { AutogenOptions, AutogenOutput, GeneratedVariant, PropDefinition, generateArtFile$1 as generateArtFile, writeArtFile$1 as writeArtFile } from "./autogen-D3Zjc3zI.js";
|
|
4
4
|
import { Plugin } from "vite";
|
|
5
5
|
|
|
@@ -93,5 +93,5 @@ declare function processStyleDictionary(config: StyleDictionaryConfig): Promise<
|
|
|
93
93
|
declare function musea(options?: MuseaOptions): Plugin[];
|
|
94
94
|
|
|
95
95
|
//#endregion
|
|
96
|
-
export { A11yOptions, A11yResult, A11ySummary, AnalysisApiResponse, ArtFileInfo, ArtMetadata, ArtVariant, AutogenOptions, AutogenOutput, CaptureConfig, CiConfig, ComparisonConfig, CsfOutput, DesignToken, GeneratedVariant, MuseaA11yRunner, MuseaOptions, MuseaVrtRunner, PaletteApiResponse, PropDefinition, StyleDictionaryConfig, StyleDictionaryOutput, TokenCategory, ViewportConfig, VrtOptions, VrtResult, VrtSummary, musea as default, generateArtFile, generateTokensHtml, generateTokensMarkdown, generateVrtJsonReport, generateVrtReport, musea, parseTokens, processStyleDictionary, writeArtFile };
|
|
96
|
+
export { A11yOptions, A11yResult, A11ySummary, AnalysisApiResponse, ArtFileInfo, ArtMetadata, ArtVariant, AutogenOptions, AutogenOutput, CaptureConfig, CiConfig, ComparisonConfig, CsfOutput, DesignToken, GeneratedVariant, MuseaA11yRunner, MuseaOptions, MuseaTheme, MuseaThemeColors, MuseaVrtRunner, PaletteApiResponse, PropDefinition, StyleDictionaryConfig, StyleDictionaryOutput, TokenCategory, ViewportConfig, VrtOptions, VrtResult, VrtSummary, musea as default, generateArtFile, generateTokensHtml, generateTokensMarkdown, generateVrtJsonReport, generateVrtReport, musea, parseTokens, processStyleDictionary, writeArtFile };
|
|
97
97
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/style-dictionary.ts","../src/index.ts"],"sourcesContent":null,"mappings":";;;;;;;;;;;;;;;;;;;;UAWiB,WAAA;;;;eAIF;;AAJf;;;UAUiB,aAAA;EAAA,IAAA,EAAA,MAAA;EAAa,MAAA,EAEpB,MAFoB,CAAA,MAAA,EAEL,WAFK,CAAA;EAAA,aAEL,CAAA,EACP,aADO,EAAA;;;AACM;;UAMd,qBAAA;cACH;EADG,QAAA,EAAA;;;;EAYA,CAAA;;;;AA2BjB;AAA0B,UA3BT,qBAAA,CA2BS;EAAA;;AAAsD;;;;AAKhF;;EAAiC,YAA8B,CAAA,EAAA,MAAA,GAAA,MAAA,GAAA,UAAA;EAAa;AAAd;;;;EAgJ9C;;;eA3JD;AA6Rf;;;;AAsCsB,KA7TV,cAAA,GA6TgC,CAAA,KAAA,EA7TP,WA6TO,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,GA7TyB,WA6TzB;;;;AAEzC,iBA1TmB,WAAA,CA0TnB,UAAA,EAAA,MAAA,CAAA,EA1ToD,OA0TpD,CA1T4D,aA0T5D,EAAA,CAAA;AAAO;;;iBA1KM,kBAAA,aAA+B;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/style-dictionary.ts","../src/index.ts"],"sourcesContent":null,"mappings":";;;;;;;;;;;;;;;;;;;;UAWiB,WAAA;;;;eAIF;;AAJf;;;UAUiB,aAAA;EAAA,IAAA,EAAA,MAAA;EAAa,MAAA,EAEpB,MAFoB,CAAA,MAAA,EAEL,WAFK,CAAA;EAAA,aAEL,CAAA,EACP,aADO,EAAA;;;AACM;;UAMd,qBAAA;cACH;EADG,QAAA,EAAA;;;;EAYA,CAAA;;;;AA2BjB;AAA0B,UA3BT,qBAAA,CA2BS;EAAA;;AAAsD;;;;AAKhF;;EAAiC,YAA8B,CAAA,EAAA,MAAA,GAAA,MAAA,GAAA,UAAA;EAAa;AAAd;;;;EAgJ9C;;;eA3JD;AA6Rf;;;;AAsCsB,KA7TV,cAAA,GA6TgC,CAAA,KAAA,EA7TP,WA6TO,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,GA7TyB,WA6TzB;;;;AAEzC,iBA1TmB,WAAA,CA0TnB,UAAA,EAAA,MAAA,CAAA,EA1ToD,OA0TpD,CA1T4D,aA0T5D,EAAA,CAAA;AAAO;;;iBA1KM,kBAAA,aAA+B;;;;ACU/B,iBDwHA,sBAAA,CCxHK,UAAA,EDwH8B,aCxH9B,EAAA,CAAA,EAAA,MAAA;;;;AAAoC,iBD8JnC,sBAAA,CC9JmC,MAAA,ED+J/C,qBC/J+C,CAAA,EDgKtD,OChKsD,CDgK9C,qBChK8C,CAAA,CAAA;;AD5M1B;;;iBC4Mf,KAAA,WAAe,eAAoB"}
|
package/dist/index.js
CHANGED
|
@@ -293,6 +293,23 @@ function loadNative() {
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
/**
|
|
296
|
+
* Build the theme config object from plugin options for runtime injection.
|
|
297
|
+
*/
|
|
298
|
+
function buildThemeConfig(theme) {
|
|
299
|
+
if (!theme) return void 0;
|
|
300
|
+
if (typeof theme === "string") return { default: theme };
|
|
301
|
+
const themes = Array.isArray(theme) ? theme : [theme];
|
|
302
|
+
const custom = {};
|
|
303
|
+
for (const t of themes) custom[t.name] = {
|
|
304
|
+
base: t.base,
|
|
305
|
+
colors: t.colors
|
|
306
|
+
};
|
|
307
|
+
return {
|
|
308
|
+
default: themes[0].name,
|
|
309
|
+
custom
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
296
313
|
* Create Musea Vite plugin.
|
|
297
314
|
*/
|
|
298
315
|
function musea(options = {}) {
|
|
@@ -302,6 +319,8 @@ function musea(options = {}) {
|
|
|
302
319
|
let storybookCompat = options.storybookCompat ?? false;
|
|
303
320
|
const storybookOutDir = options.storybookOutDir ?? ".storybook/stories";
|
|
304
321
|
let inlineArt = options.inlineArt ?? false;
|
|
322
|
+
const tokensPath = options.tokensPath;
|
|
323
|
+
const themeConfig = buildThemeConfig(options.theme);
|
|
305
324
|
let config;
|
|
306
325
|
let server = null;
|
|
307
326
|
const artFiles = new Map();
|
|
@@ -333,13 +352,14 @@ function musea(options = {}) {
|
|
|
333
352
|
try {
|
|
334
353
|
await fs.promises.access(indexHtmlPath);
|
|
335
354
|
let html = await fs.promises.readFile(indexHtmlPath, "utf-8");
|
|
336
|
-
|
|
355
|
+
const themeScript = themeConfig ? `window.__MUSEA_THEME_CONFIG__=${JSON.stringify(themeConfig)};` : "";
|
|
356
|
+
html = html.replace("</head>", `<script>window.__MUSEA_BASE_PATH__='${basePath}';${themeScript}</script></head>`);
|
|
337
357
|
html = await devServer.transformIndexHtml(basePath + url, html);
|
|
338
358
|
res.setHeader("Content-Type", "text/html");
|
|
339
359
|
res.end(html);
|
|
340
360
|
return;
|
|
341
361
|
} catch {
|
|
342
|
-
const html = generateGalleryHtml(basePath);
|
|
362
|
+
const html = generateGalleryHtml(basePath, themeConfig);
|
|
343
363
|
res.setHeader("Content-Type", "text/html");
|
|
344
364
|
res.end(html);
|
|
345
365
|
return;
|
|
@@ -479,7 +499,21 @@ function musea(options = {}) {
|
|
|
479
499
|
return;
|
|
480
500
|
}
|
|
481
501
|
if (req.url === "/tokens" && req.method === "GET") {
|
|
482
|
-
|
|
502
|
+
if (!tokensPath) {
|
|
503
|
+
sendJson({ categories: [] });
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
try {
|
|
507
|
+
const absoluteTokensPath = path.resolve(config.root, tokensPath);
|
|
508
|
+
const categories = await parseTokens(absoluteTokensPath);
|
|
509
|
+
sendJson({ categories });
|
|
510
|
+
} catch (e) {
|
|
511
|
+
console.error("[musea] Failed to load tokens:", e);
|
|
512
|
+
sendJson({
|
|
513
|
+
categories: [],
|
|
514
|
+
error: String(e)
|
|
515
|
+
});
|
|
516
|
+
}
|
|
483
517
|
return;
|
|
484
518
|
}
|
|
485
519
|
if (req.url?.startsWith("/arts/") && req.method === "GET") {
|
|
@@ -553,7 +587,24 @@ function musea(options = {}) {
|
|
|
553
587
|
const binding = loadNative();
|
|
554
588
|
if (binding.generateArtDoc) {
|
|
555
589
|
const doc = binding.generateArtDoc(source, { filename: artPath$1 });
|
|
556
|
-
|
|
590
|
+
let markdown = doc.markdown || "";
|
|
591
|
+
const componentName = art$1.metadata.title || "Component";
|
|
592
|
+
markdown = markdown.replace(/<Self(\s|>|\/)/g, `<${componentName}$1`).replace(/<\/Self>/g, `</${componentName}>`);
|
|
593
|
+
markdown = markdown.replace(/```(\w*)\n([\s\S]*?)```/g, (_match, lang, code) => {
|
|
594
|
+
const lines = code.split("\n");
|
|
595
|
+
let minIndent = Infinity;
|
|
596
|
+
for (const line of lines) if (line.trim()) {
|
|
597
|
+
const indent = line.match(/^(\s*)/)?.[1].length || 0;
|
|
598
|
+
minIndent = Math.min(minIndent, indent);
|
|
599
|
+
}
|
|
600
|
+
if (minIndent === Infinity) minIndent = 0;
|
|
601
|
+
const formatted = lines.map((line) => line.slice(minIndent)).join("\n");
|
|
602
|
+
return "```" + lang + "\n" + formatted + "```";
|
|
603
|
+
});
|
|
604
|
+
sendJson({
|
|
605
|
+
...doc,
|
|
606
|
+
markdown
|
|
607
|
+
});
|
|
557
608
|
} else sendJson({
|
|
558
609
|
markdown: "",
|
|
559
610
|
title: art$1.metadata.title,
|
|
@@ -635,6 +686,43 @@ function musea(options = {}) {
|
|
|
635
686
|
});
|
|
636
687
|
return;
|
|
637
688
|
}
|
|
689
|
+
if (req.url === "/run-vrt" && req.method === "POST") {
|
|
690
|
+
let body = "";
|
|
691
|
+
req.on("data", (chunk) => {
|
|
692
|
+
body += chunk;
|
|
693
|
+
});
|
|
694
|
+
req.on("end", async () => {
|
|
695
|
+
try {
|
|
696
|
+
const { artPath, updateSnapshots } = JSON.parse(body);
|
|
697
|
+
const { MuseaVrtRunner: MuseaVrtRunner$1 } = await import("./vrt.js");
|
|
698
|
+
const runner = new MuseaVrtRunner$1({ snapshotDir: path.resolve(config.root, ".vize/snapshots") });
|
|
699
|
+
const port = devServer.config.server.port || 5173;
|
|
700
|
+
const baseUrl = `http://localhost:${port}`;
|
|
701
|
+
let artsToTest = Array.from(artFiles.values());
|
|
702
|
+
if (artPath) artsToTest = artsToTest.filter((a) => a.path === artPath);
|
|
703
|
+
await runner.start();
|
|
704
|
+
const results = await runner.runTests(artsToTest, baseUrl, { updateSnapshots });
|
|
705
|
+
const summary = runner.getSummary(results);
|
|
706
|
+
await runner.stop();
|
|
707
|
+
sendJson({
|
|
708
|
+
success: true,
|
|
709
|
+
summary,
|
|
710
|
+
results: results.map((r) => ({
|
|
711
|
+
artPath: r.artPath,
|
|
712
|
+
variantName: r.variantName,
|
|
713
|
+
viewport: r.viewport.name,
|
|
714
|
+
passed: r.passed,
|
|
715
|
+
isNew: r.isNew,
|
|
716
|
+
diffPercentage: r.diffPercentage,
|
|
717
|
+
error: r.error
|
|
718
|
+
}))
|
|
719
|
+
});
|
|
720
|
+
} catch (e) {
|
|
721
|
+
sendError(e instanceof Error ? e.message : String(e));
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
638
726
|
next();
|
|
639
727
|
});
|
|
640
728
|
devServer.watcher.on("change", async (file) => {
|
|
@@ -673,6 +761,20 @@ function musea(options = {}) {
|
|
|
673
761
|
console.log(`[musea] Removed: ${path.relative(config.root, file)}`);
|
|
674
762
|
}
|
|
675
763
|
});
|
|
764
|
+
return () => {
|
|
765
|
+
devServer.httpServer?.once("listening", () => {
|
|
766
|
+
const address = devServer.httpServer?.address();
|
|
767
|
+
if (address && typeof address === "object") {
|
|
768
|
+
const protocol = devServer.config.server.https ? "https" : "http";
|
|
769
|
+
const rawHost = address.address;
|
|
770
|
+
const host = rawHost === "::" || rawHost === "::1" || rawHost === "0.0.0.0" || rawHost === "127.0.0.1" ? "localhost" : rawHost;
|
|
771
|
+
const port = address.port;
|
|
772
|
+
const url = `${protocol}://${host}:${port}${basePath}`;
|
|
773
|
+
console.log();
|
|
774
|
+
console.log(` \x1b[36m➜\x1b[0m \x1b[1mMusea Gallery:\x1b[0m \x1b[36m${url}\x1b[0m`);
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
};
|
|
676
778
|
},
|
|
677
779
|
async buildStart() {
|
|
678
780
|
const files = await scanArtFiles(config.root, include, exclude, inlineArt);
|
|
@@ -818,13 +920,15 @@ async function scanArtFiles(root, include, exclude, scanInlineArt = false) {
|
|
|
818
920
|
await scan(root);
|
|
819
921
|
return files;
|
|
820
922
|
}
|
|
821
|
-
function generateGalleryHtml(basePath) {
|
|
923
|
+
function generateGalleryHtml(basePath, themeConfig) {
|
|
924
|
+
const themeScript = themeConfig ? `window.__MUSEA_THEME_CONFIG__=${JSON.stringify(themeConfig)};` : "";
|
|
822
925
|
return `<!DOCTYPE html>
|
|
823
926
|
<html lang="en">
|
|
824
927
|
<head>
|
|
825
928
|
<meta charset="UTF-8">
|
|
826
929
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
827
930
|
<title>Musea - Component Gallery</title>
|
|
931
|
+
<script>window.__MUSEA_BASE_PATH__='${basePath}';${themeScript}</script>
|
|
828
932
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
829
933
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
830
934
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@@ -1558,16 +1662,69 @@ export async function loadArts() {
|
|
|
1558
1662
|
`;
|
|
1559
1663
|
}
|
|
1560
1664
|
const MUSEA_ADDONS_INIT_CODE = `
|
|
1561
|
-
function __museaInitAddons(container) {
|
|
1665
|
+
function __museaInitAddons(container, variantName) {
|
|
1562
1666
|
// === DOM event capture ===
|
|
1563
|
-
|
|
1667
|
+
// Note: mousemove, mouseenter, mouseleave, pointermove are excluded as they are too noisy
|
|
1668
|
+
const CAPTURE_EVENTS = ['click','dblclick','input','change','submit','focus','blur','keydown','keyup','mousedown','mouseup','wheel','contextmenu','pointerdown','pointerup'];
|
|
1564
1669
|
for (const evt of CAPTURE_EVENTS) {
|
|
1565
1670
|
container.addEventListener(evt, (e) => {
|
|
1671
|
+
// Extract raw event properties
|
|
1672
|
+
const rawEvent = {
|
|
1673
|
+
type: e.type,
|
|
1674
|
+
bubbles: e.bubbles,
|
|
1675
|
+
cancelable: e.cancelable,
|
|
1676
|
+
composed: e.composed,
|
|
1677
|
+
defaultPrevented: e.defaultPrevented,
|
|
1678
|
+
eventPhase: e.eventPhase,
|
|
1679
|
+
isTrusted: e.isTrusted,
|
|
1680
|
+
timeStamp: e.timeStamp,
|
|
1681
|
+
};
|
|
1682
|
+
// Mouse/Pointer event properties
|
|
1683
|
+
if ('clientX' in e) {
|
|
1684
|
+
rawEvent.clientX = e.clientX;
|
|
1685
|
+
rawEvent.clientY = e.clientY;
|
|
1686
|
+
rawEvent.screenX = e.screenX;
|
|
1687
|
+
rawEvent.screenY = e.screenY;
|
|
1688
|
+
rawEvent.pageX = e.pageX;
|
|
1689
|
+
rawEvent.pageY = e.pageY;
|
|
1690
|
+
rawEvent.offsetX = e.offsetX;
|
|
1691
|
+
rawEvent.offsetY = e.offsetY;
|
|
1692
|
+
rawEvent.button = e.button;
|
|
1693
|
+
rawEvent.buttons = e.buttons;
|
|
1694
|
+
rawEvent.altKey = e.altKey;
|
|
1695
|
+
rawEvent.ctrlKey = e.ctrlKey;
|
|
1696
|
+
rawEvent.metaKey = e.metaKey;
|
|
1697
|
+
rawEvent.shiftKey = e.shiftKey;
|
|
1698
|
+
}
|
|
1699
|
+
// Keyboard event properties
|
|
1700
|
+
if ('key' in e) {
|
|
1701
|
+
rawEvent.key = e.key;
|
|
1702
|
+
rawEvent.code = e.code;
|
|
1703
|
+
rawEvent.repeat = e.repeat;
|
|
1704
|
+
rawEvent.altKey = e.altKey;
|
|
1705
|
+
rawEvent.ctrlKey = e.ctrlKey;
|
|
1706
|
+
rawEvent.metaKey = e.metaKey;
|
|
1707
|
+
rawEvent.shiftKey = e.shiftKey;
|
|
1708
|
+
}
|
|
1709
|
+
// Input event properties
|
|
1710
|
+
if ('inputType' in e) {
|
|
1711
|
+
rawEvent.inputType = e.inputType;
|
|
1712
|
+
rawEvent.data = e.data;
|
|
1713
|
+
}
|
|
1714
|
+
// Wheel event properties
|
|
1715
|
+
if ('deltaX' in e) {
|
|
1716
|
+
rawEvent.deltaX = e.deltaX;
|
|
1717
|
+
rawEvent.deltaY = e.deltaY;
|
|
1718
|
+
rawEvent.deltaZ = e.deltaZ;
|
|
1719
|
+
rawEvent.deltaMode = e.deltaMode;
|
|
1720
|
+
}
|
|
1566
1721
|
const payload = {
|
|
1567
1722
|
name: evt,
|
|
1568
1723
|
target: e.target?.tagName,
|
|
1569
1724
|
timestamp: Date.now(),
|
|
1570
|
-
source: 'dom'
|
|
1725
|
+
source: 'dom',
|
|
1726
|
+
rawEvent,
|
|
1727
|
+
variantName
|
|
1571
1728
|
};
|
|
1572
1729
|
if (e.target && 'value' in e.target) {
|
|
1573
1730
|
payload.value = e.target.value;
|
|
@@ -1732,6 +1889,59 @@ function __museaInitAddons(container) {
|
|
|
1732
1889
|
}
|
|
1733
1890
|
break;
|
|
1734
1891
|
}
|
|
1892
|
+
case 'musea:run-a11y': {
|
|
1893
|
+
// Run axe-core a11y test
|
|
1894
|
+
(async () => {
|
|
1895
|
+
try {
|
|
1896
|
+
// Dynamically load axe-core from CDN if not already loaded
|
|
1897
|
+
if (!window.axe) {
|
|
1898
|
+
const script = document.createElement('script');
|
|
1899
|
+
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js';
|
|
1900
|
+
script.crossOrigin = 'anonymous';
|
|
1901
|
+
await new Promise((resolve, reject) => {
|
|
1902
|
+
script.onload = resolve;
|
|
1903
|
+
script.onerror = reject;
|
|
1904
|
+
document.head.appendChild(script);
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
// Run axe-core on the .musea-variant container only (not the full document)
|
|
1908
|
+
const context = document.querySelector('.musea-variant') || document;
|
|
1909
|
+
const results = await window.axe.run(context, {
|
|
1910
|
+
// Run all rules without restrictions for comprehensive testing
|
|
1911
|
+
resultTypes: ['violations', 'incomplete', 'passes']
|
|
1912
|
+
});
|
|
1913
|
+
window.parent.postMessage({
|
|
1914
|
+
type: 'musea:a11y-result',
|
|
1915
|
+
payload: {
|
|
1916
|
+
violations: results.violations.map(v => ({
|
|
1917
|
+
id: v.id,
|
|
1918
|
+
impact: v.impact,
|
|
1919
|
+
description: v.description,
|
|
1920
|
+
helpUrl: v.helpUrl,
|
|
1921
|
+
nodes: v.nodes.map(n => ({
|
|
1922
|
+
html: n.html,
|
|
1923
|
+
target: n.target,
|
|
1924
|
+
failureSummary: n.failureSummary
|
|
1925
|
+
}))
|
|
1926
|
+
})),
|
|
1927
|
+
passes: results.passes.length,
|
|
1928
|
+
incomplete: results.incomplete.length
|
|
1929
|
+
}
|
|
1930
|
+
}, '*');
|
|
1931
|
+
} catch (err) {
|
|
1932
|
+
window.parent.postMessage({
|
|
1933
|
+
type: 'musea:a11y-result',
|
|
1934
|
+
payload: {
|
|
1935
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1936
|
+
violations: [],
|
|
1937
|
+
passes: 0,
|
|
1938
|
+
incomplete: 0
|
|
1939
|
+
}
|
|
1940
|
+
}, '*');
|
|
1941
|
+
}
|
|
1942
|
+
})();
|
|
1943
|
+
break;
|
|
1944
|
+
}
|
|
1735
1945
|
}
|
|
1736
1946
|
});
|
|
1737
1947
|
|
|
@@ -1784,7 +1994,7 @@ async function mount() {
|
|
|
1784
1994
|
currentApp = app;
|
|
1785
1995
|
|
|
1786
1996
|
console.log('[musea-preview] Mounted variant: ${escapedVariantName}');
|
|
1787
|
-
__museaInitAddons(container);
|
|
1997
|
+
__museaInitAddons(container, '${escapedVariantName}');
|
|
1788
1998
|
|
|
1789
1999
|
// Override set-props to remount with raw component + props
|
|
1790
2000
|
if (RawComponent) {
|
|
@@ -1941,7 +2151,7 @@ async function mount() {
|
|
|
1941
2151
|
container.className = 'musea-variant';
|
|
1942
2152
|
app.mount(container);
|
|
1943
2153
|
console.log('[musea-preview] Mounted variant: ${escapedVariantName} with props override');
|
|
1944
|
-
__museaInitAddons(container);
|
|
2154
|
+
__museaInitAddons(container, '${escapedVariantName}');
|
|
1945
2155
|
} catch (error) {
|
|
1946
2156
|
console.error('[musea-preview] Failed to mount:', error);
|
|
1947
2157
|
container.innerHTML = '<div class="musea-error"><div class="musea-error-title">Failed to render</div><div>' + error.message + '</div></div>';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["tokensPath: string","dirPath: string","categories: TokenCategory[]","tokens: Record<string, unknown>","prefix: string[]","obj: Record<string, unknown>","tokens: Record<string, DesignToken>","subcategories: TokenCategory[]","value: unknown","raw: Record<string, unknown>","name: string","token: DesignToken","category: TokenCategory","level: number","config: StyleDictionaryConfig","content: string","filename: string","native: NativeBinding | null","options: MuseaOptions","config: ResolvedConfig","server: ViteDevServer | null","mainPlugin: Plugin","mimeTypes: Record<string, string>","data: unknown","message: string","artPath","art","filePath: string","info: ArtFileInfo","file: string","include: string[]","exclude: string[]","root: string","filepath: string","pattern: string","files: string[]","dir: string","basePath: string","art: ArtFileInfo","variantComponentName: string","variantName: string","artFiles: Map<string, ArtFileInfo>","componentImportPath: string | undefined","componentName: string | undefined","outDir: string","str: string","propsOverride: Record<string, unknown>","variant: ArtVariant"],"sources":["../src/style-dictionary.ts","../src/index.ts"],"sourcesContent":["/**\n * Style Dictionary integration for Musea.\n * Generates design token documentation from Style Dictionary format.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Design token value.\n */\nexport interface DesignToken {\n value: string | number;\n type?: string;\n description?: string;\n attributes?: Record<string, unknown>;\n}\n\n/**\n * Token category (e.g., colors, spacing, typography).\n */\nexport interface TokenCategory {\n name: string;\n tokens: Record<string, DesignToken>;\n subcategories?: TokenCategory[];\n}\n\n/**\n * Style Dictionary output format.\n */\nexport interface StyleDictionaryOutput {\n categories: TokenCategory[];\n metadata: {\n name: string;\n version?: string;\n generatedAt: string;\n };\n}\n\n/**\n * Configuration for Style Dictionary integration.\n */\nexport interface StyleDictionaryConfig {\n /**\n * Path to tokens JSON/JS file or directory.\n */\n tokensPath: string;\n\n /**\n * Output format for documentation.\n * @default 'html'\n */\n outputFormat?: \"html\" | \"json\" | \"markdown\";\n\n /**\n * Output directory for generated documentation.\n * @default '.vize/tokens'\n */\n outputDir?: string;\n\n /**\n * Custom token transformations.\n */\n transforms?: TokenTransform[];\n}\n\n/**\n * Token transformation function.\n */\nexport type TokenTransform = (token: DesignToken, path: string[]) => DesignToken;\n\n/**\n * Parse Style Dictionary tokens file.\n */\nexport async function parseTokens(tokensPath: string): Promise<TokenCategory[]> {\n const absolutePath = path.resolve(tokensPath);\n const stat = await fs.promises.stat(absolutePath);\n\n if (stat.isDirectory()) {\n return parseTokenDirectory(absolutePath);\n }\n\n const content = await fs.promises.readFile(absolutePath, \"utf-8\");\n const tokens = JSON.parse(content);\n return flattenTokens(tokens);\n}\n\n/**\n * Parse tokens from a directory.\n */\nasync function parseTokenDirectory(dirPath: string): Promise<TokenCategory[]> {\n const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });\n const categories: TokenCategory[] = [];\n\n for (const entry of entries) {\n if (entry.isFile() && (entry.name.endsWith(\".json\") || entry.name.endsWith(\".tokens.json\"))) {\n const filePath = path.join(dirPath, entry.name);\n const content = await fs.promises.readFile(filePath, \"utf-8\");\n const tokens = JSON.parse(content);\n const categoryName = path\n .basename(entry.name, path.extname(entry.name))\n .replace(\".tokens\", \"\");\n\n categories.push({\n name: formatCategoryName(categoryName),\n tokens: extractTokens(tokens),\n subcategories: extractSubcategories(tokens),\n });\n }\n }\n\n return categories;\n}\n\n/**\n * Flatten nested token structure into categories.\n */\nfunction flattenTokens(tokens: Record<string, unknown>, prefix: string[] = []): TokenCategory[] {\n const categories: TokenCategory[] = [];\n\n for (const [key, value] of Object.entries(tokens)) {\n if (isTokenValue(value)) {\n // This is a token leaf node\n continue;\n }\n\n if (typeof value === \"object\" && value !== null) {\n const categoryTokens = extractTokens(value as Record<string, unknown>);\n const subcategories = flattenTokens(value as Record<string, unknown>, [...prefix, key]);\n\n if (Object.keys(categoryTokens).length > 0 || subcategories.length > 0) {\n categories.push({\n name: formatCategoryName(key),\n tokens: categoryTokens,\n subcategories: subcategories.length > 0 ? subcategories : undefined,\n });\n }\n }\n }\n\n return categories;\n}\n\n/**\n * Extract token values from an object.\n */\nfunction extractTokens(obj: Record<string, unknown>): Record<string, DesignToken> {\n const tokens: Record<string, DesignToken> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (isTokenValue(value)) {\n tokens[key] = normalizeToken(value as Record<string, unknown>);\n }\n }\n\n return tokens;\n}\n\n/**\n * Extract subcategories from an object.\n */\nfunction extractSubcategories(obj: Record<string, unknown>): TokenCategory[] | undefined {\n const subcategories: TokenCategory[] = [];\n\n for (const [key, value] of Object.entries(obj)) {\n if (!isTokenValue(value) && typeof value === \"object\" && value !== null) {\n const categoryTokens = extractTokens(value as Record<string, unknown>);\n const nested = extractSubcategories(value as Record<string, unknown>);\n\n if (Object.keys(categoryTokens).length > 0 || (nested && nested.length > 0)) {\n subcategories.push({\n name: formatCategoryName(key),\n tokens: categoryTokens,\n subcategories: nested,\n });\n }\n }\n }\n\n return subcategories.length > 0 ? subcategories : undefined;\n}\n\n/**\n * Check if a value is a token definition.\n */\nfunction isTokenValue(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n return \"value\" in obj && (typeof obj.value === \"string\" || typeof obj.value === \"number\");\n}\n\n/**\n * Normalize token to DesignToken interface.\n */\nfunction normalizeToken(raw: Record<string, unknown>): DesignToken {\n return {\n value: raw.value as string | number,\n type: raw.type as string | undefined,\n description: raw.description as string | undefined,\n attributes: raw.attributes as Record<string, unknown> | undefined,\n };\n}\n\n/**\n * Format category name for display.\n */\nfunction formatCategoryName(name: string): string {\n return name\n .replace(/[-_]/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\" \");\n}\n\n/**\n * Generate HTML documentation for tokens.\n */\nexport function generateTokensHtml(categories: TokenCategory[]): string {\n const renderToken = (name: string, token: DesignToken): string => {\n const isColor =\n typeof token.value === \"string\" &&\n (token.value.startsWith(\"#\") ||\n token.value.startsWith(\"rgb\") ||\n token.value.startsWith(\"hsl\") ||\n token.type === \"color\");\n\n return `\n <div class=\"token\">\n <div class=\"token-preview\">\n ${isColor ? `<div class=\"color-swatch\" style=\"background: ${token.value}\"></div>` : \"\"}\n </div>\n <div class=\"token-info\">\n <div class=\"token-name\">${name}</div>\n <div class=\"token-value\">${token.value}</div>\n ${token.description ? `<div class=\"token-description\">${token.description}</div>` : \"\"}\n </div>\n </div>\n `;\n };\n\n const renderCategory = (category: TokenCategory, level: number = 2): string => {\n const heading = `h${Math.min(level, 6)}`;\n let html = `<${heading}>${category.name}</${heading}>`;\n html += '<div class=\"tokens-grid\">';\n\n for (const [name, token] of Object.entries(category.tokens)) {\n html += renderToken(name, token);\n }\n\n html += \"</div>\";\n\n if (category.subcategories) {\n for (const sub of category.subcategories) {\n html += renderCategory(sub, level + 1);\n }\n }\n\n return html;\n };\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Design Tokens - Musea</title>\n <style>\n :root {\n --musea-bg: #0d0d0d;\n --musea-bg-secondary: #1a1815;\n --musea-text: #e6e9f0;\n --musea-text-muted: #7b8494;\n --musea-accent: #a34828;\n --musea-border: #3a3530;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: 'Inter', -apple-system, sans-serif;\n background: var(--musea-bg);\n color: var(--musea-text);\n line-height: 1.6;\n padding: 2rem;\n }\n h1 { margin-bottom: 2rem; color: var(--musea-accent); }\n h2 { margin: 2rem 0 1rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--musea-border); }\n h3, h4, h5, h6 { margin: 1.5rem 0 0.75rem; }\n .tokens-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 1rem;\n margin-bottom: 1.5rem;\n }\n .token {\n background: var(--musea-bg-secondary);\n border: 1px solid var(--musea-border);\n border-radius: 8px;\n padding: 1rem;\n display: flex;\n gap: 1rem;\n align-items: center;\n }\n .token-preview {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .color-swatch {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n border: 1px solid var(--musea-border);\n }\n .token-info {\n flex: 1;\n min-width: 0;\n }\n .token-name {\n font-weight: 600;\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.875rem;\n }\n .token-value {\n color: var(--musea-text-muted);\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.75rem;\n word-break: break-all;\n }\n .token-description {\n color: var(--musea-text-muted);\n font-size: 0.75rem;\n margin-top: 0.25rem;\n }\n </style>\n</head>\n<body>\n <h1>Design Tokens</h1>\n ${categories.map((cat) => renderCategory(cat)).join(\"\")}\n</body>\n</html>`;\n}\n\n/**\n * Generate Markdown documentation for tokens.\n */\nexport function generateTokensMarkdown(categories: TokenCategory[]): string {\n const renderCategory = (category: TokenCategory, level: number = 2): string => {\n const heading = \"#\".repeat(level);\n let md = `\\n${heading} ${category.name}\\n\\n`;\n\n if (Object.keys(category.tokens).length > 0) {\n md += \"| Token | Value | Description |\\n\";\n md += \"|-------|-------|-------------|\\n\";\n\n for (const [name, token] of Object.entries(category.tokens)) {\n const desc = token.description || \"-\";\n md += `| \\`${name}\\` | \\`${token.value}\\` | ${desc} |\\n`;\n }\n md += \"\\n\";\n }\n\n if (category.subcategories) {\n for (const sub of category.subcategories) {\n md += renderCategory(sub, level + 1);\n }\n }\n\n return md;\n };\n\n let markdown = \"# Design Tokens\\n\\n\";\n markdown += `> Generated by Musea on ${new Date().toISOString()}\\n`;\n\n for (const category of categories) {\n markdown += renderCategory(category);\n }\n\n return markdown;\n}\n\n/**\n * Style Dictionary plugin for Musea.\n */\nexport async function processStyleDictionary(\n config: StyleDictionaryConfig,\n): Promise<StyleDictionaryOutput> {\n const categories = await parseTokens(config.tokensPath);\n const outputDir = config.outputDir ?? \".vize/tokens\";\n const outputFormat = config.outputFormat ?? \"html\";\n\n // Ensure output directory exists\n await fs.promises.mkdir(outputDir, { recursive: true });\n\n // Generate documentation\n let content: string;\n let filename: string;\n\n switch (outputFormat) {\n case \"html\":\n content = generateTokensHtml(categories);\n filename = \"tokens.html\";\n break;\n case \"markdown\":\n content = generateTokensMarkdown(categories);\n filename = \"tokens.md\";\n break;\n case \"json\":\n default:\n content = JSON.stringify({ categories }, null, 2);\n filename = \"tokens.json\";\n }\n\n const outputPath = path.join(outputDir, filename);\n await fs.promises.writeFile(outputPath, content, \"utf-8\");\n\n console.log(`[musea] Generated token documentation: ${outputPath}`);\n\n return {\n categories,\n metadata: {\n name: path.basename(config.tokensPath),\n generatedAt: new Date().toISOString(),\n },\n };\n}\n\nexport default processStyleDictionary;\n","/**\n * Vite plugin for Musea - Component gallery for Vue components.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'vite';\n * import { vize } from '@vizejs/vite-plugin';\n * import { musea } from '@vizejs/vite-plugin-musea';\n *\n * export default defineConfig({\n * plugins: [vize(), musea()],\n * });\n * ```\n */\n\nimport type { Plugin, ViteDevServer, ResolvedConfig } from \"vite\";\nimport { createRequire } from \"node:module\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { vizeConfigStore } from \"@vizejs/vite-plugin\";\n\nimport type {\n MuseaOptions,\n ArtFileInfo,\n ArtMetadata,\n ArtVariant,\n CsfOutput,\n PaletteApiResponse,\n AnalysisApiResponse,\n A11yOptions,\n A11yResult,\n CaptureConfig,\n ComparisonConfig,\n CiConfig,\n} from \"./types.js\";\n\nexport type {\n MuseaOptions,\n ArtFileInfo,\n ArtMetadata,\n ArtVariant,\n CsfOutput,\n VrtOptions,\n ViewportConfig,\n PaletteApiResponse,\n AnalysisApiResponse,\n A11yOptions,\n A11yResult,\n CaptureConfig,\n ComparisonConfig,\n CiConfig,\n} from \"./types.js\";\n\nexport {\n MuseaVrtRunner,\n generateVrtReport,\n generateVrtJsonReport,\n type VrtResult,\n type VrtSummary,\n} from \"./vrt.js\";\n\nexport {\n processStyleDictionary,\n parseTokens,\n generateTokensHtml,\n generateTokensMarkdown,\n type DesignToken,\n type TokenCategory,\n type StyleDictionaryConfig,\n type StyleDictionaryOutput,\n} from \"./style-dictionary.js\";\n\nexport { MuseaA11yRunner, type A11ySummary } from \"./a11y.js\";\n\nexport {\n generateArtFile,\n writeArtFile,\n type AutogenOptions,\n type AutogenOutput,\n type PropDefinition,\n type GeneratedVariant,\n} from \"./autogen.js\";\n\n// Virtual module prefixes\nconst VIRTUAL_MUSEA_PREFIX = \"\\0musea:\";\nconst VIRTUAL_GALLERY = \"\\0musea-gallery\";\nconst VIRTUAL_MANIFEST = \"\\0musea-manifest\";\n\n// Native binding types\ninterface NativeBinding {\n parseArt: (\n source: string,\n options?: { filename?: string },\n ) => {\n filename: string;\n metadata: {\n title: string;\n description?: string;\n component?: string;\n category?: string;\n tags: string[];\n status: string;\n order?: number;\n };\n variants: Array<{\n name: string;\n template: string;\n is_default: boolean;\n skip_vrt: boolean;\n }>;\n has_script_setup: boolean;\n has_script: boolean;\n style_count: number;\n };\n artToCsf: (\n source: string,\n options?: { filename?: string },\n ) => {\n code: string;\n filename: string;\n };\n generateArtPalette?: (\n source: string,\n artOptions?: { filename?: string },\n paletteOptions?: { infer_options?: boolean; group_by_type?: boolean },\n ) => {\n title: string;\n controls: Array<{\n name: string;\n control: string;\n default_value?: unknown;\n description?: string;\n required: boolean;\n options: Array<{ label: string; value: unknown }>;\n range?: { min: number; max: number; step?: number };\n group?: string;\n }>;\n groups: string[];\n json: string;\n typescript: string;\n };\n generateArtDoc?: (\n source: string,\n artOptions?: { filename?: string },\n docOptions?: {\n include_source?: boolean;\n include_templates?: boolean;\n include_metadata?: boolean;\n },\n ) => {\n markdown: string;\n filename: string;\n title: string;\n category?: string;\n variant_count: number;\n };\n analyzeSfc?: (\n source: string,\n options?: { filename?: string },\n ) => {\n props: Array<{ name: string; type: string; required: boolean; default_value?: unknown }>;\n emits: string[];\n };\n}\n\n// Lazy-load native binding\nlet native: NativeBinding | null = null;\n\nfunction loadNative(): NativeBinding {\n if (native) return native;\n\n const require = createRequire(import.meta.url);\n try {\n native = require(\"@vizejs/native\") as NativeBinding;\n return native;\n } catch (e) {\n throw new Error(\n `Failed to load @vizejs/native. Make sure it's installed and built:\\n${String(e)}`,\n );\n }\n}\n\n/**\n * Create Musea Vite plugin.\n */\nexport function musea(options: MuseaOptions = {}): Plugin[] {\n let include = options.include ?? [\"**/*.art.vue\"];\n let exclude = options.exclude ?? [\"node_modules/**\", \"dist/**\"];\n let basePath = options.basePath ?? \"/__musea__\";\n let storybookCompat = options.storybookCompat ?? false;\n const storybookOutDir = options.storybookOutDir ?? \".storybook/stories\";\n let inlineArt = options.inlineArt ?? false;\n\n let config: ResolvedConfig;\n let server: ViteDevServer | null = null;\n const artFiles = new Map<string, ArtFileInfo>();\n\n // Main plugin\n const mainPlugin: Plugin = {\n name: \"vite-plugin-musea\",\n enforce: \"pre\",\n\n config() {\n // Add Vue alias for runtime template compilation\n // This is needed because variant templates are compiled at runtime\n return {\n resolve: {\n alias: {\n vue: \"vue/dist/vue.esm-bundler.js\",\n },\n },\n };\n },\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n\n // Merge musea config from vize.config.ts (plugin args > config file > defaults)\n const vizeConfig = vizeConfigStore.get(resolvedConfig.root);\n if (vizeConfig?.musea) {\n const mc = vizeConfig.musea;\n // Only apply config file values when plugin options were not explicitly set\n if (!options.include && mc.include) include = mc.include;\n if (!options.exclude && mc.exclude) exclude = mc.exclude;\n if (!options.basePath && mc.basePath) basePath = mc.basePath;\n if (options.storybookCompat === undefined && mc.storybookCompat !== undefined)\n storybookCompat = mc.storybookCompat;\n if (options.inlineArt === undefined && mc.inlineArt !== undefined) inlineArt = mc.inlineArt;\n }\n },\n\n configureServer(devServer) {\n server = devServer;\n\n // Gallery SPA route - serves built SPA or falls back to inline HTML\n devServer.middlewares.use(basePath, async (req, res, next) => {\n const url = req.url || \"/\";\n\n // Serve SPA for gallery routes (not /api/, /preview, /preview-module, /art)\n if (\n url === \"/\" ||\n url === \"/index.html\" ||\n url.startsWith(\"/tokens\") ||\n url.startsWith(\"/component/\")\n ) {\n // Try serving built SPA first\n const galleryDistDir = path.resolve(\n path.dirname(new URL(import.meta.url).pathname),\n \"gallery\",\n );\n const indexHtmlPath = path.join(galleryDistDir, \"index.html\");\n\n try {\n await fs.promises.access(indexHtmlPath);\n let html = await fs.promises.readFile(indexHtmlPath, \"utf-8\");\n // Inject basePath for runtime use\n html = html.replace(\n \"</head>\",\n `<script>window.__MUSEA_BASE_PATH__='${basePath}';</script></head>`,\n );\n // Transform through Vite for HMR\n html = await devServer.transformIndexHtml(basePath + url, html);\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(html);\n return;\n } catch {\n // Fall back to inline gallery HTML\n const html = generateGalleryHtml(basePath);\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(html);\n return;\n }\n }\n // Serve gallery static assets (JS, CSS) from built SPA\n if (url.startsWith(\"/assets/\")) {\n const galleryDistDir = path.resolve(\n path.dirname(new URL(import.meta.url).pathname),\n \"gallery\",\n );\n const filePath = path.join(galleryDistDir, url);\n try {\n const stat = await fs.promises.stat(filePath);\n if (stat.isFile()) {\n const content = await fs.promises.readFile(filePath);\n const ext = path.extname(filePath);\n const mimeTypes: Record<string, string> = {\n \".js\": \"application/javascript\",\n \".css\": \"text/css\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n \".woff\": \"font/woff\",\n };\n res.setHeader(\"Content-Type\", mimeTypes[ext] || \"application/octet-stream\");\n res.setHeader(\"Cache-Control\", \"public, max-age=31536000, immutable\");\n res.end(content);\n return;\n }\n } catch {\n // File not found, fall through\n }\n }\n\n next();\n });\n\n // Preview module route - serves the JavaScript module for a specific variant\n devServer.middlewares.use(`${basePath}/preview-module`, async (req, res, _next) => {\n const url = new URL(req.url || \"\", `http://localhost`);\n const artPath = url.searchParams.get(\"art\");\n const variantName = url.searchParams.get(\"variant\");\n\n if (!artPath || !variantName) {\n res.statusCode = 400;\n res.end(\"Missing art or variant parameter\");\n return;\n }\n\n const art = artFiles.get(artPath);\n if (!art) {\n res.statusCode = 404;\n res.end(\"Art not found\");\n return;\n }\n\n const variant = art.variants.find((v) => v.name === variantName);\n if (!variant) {\n res.statusCode = 404;\n res.end(\"Variant not found\");\n return;\n }\n\n const variantComponentName = toPascalCase(variant.name);\n const moduleCode = generatePreviewModule(art, variantComponentName, variant.name);\n\n // Transform the module through Vite to resolve imports\n try {\n const result = await devServer.transformRequest(\n `virtual:musea-preview:${artPath}:${variantName}`,\n );\n if (result) {\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.end(result.code);\n return;\n }\n } catch {\n // Fall through to manual response\n }\n\n // Fallback: serve the module directly (imports won't be resolved)\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.end(moduleCode);\n });\n\n // VRT preview route - renders a single variant for screenshot\n devServer.middlewares.use(`${basePath}/preview`, async (req, res, _next) => {\n const url = new URL(req.url || \"\", `http://localhost`);\n const artPath = url.searchParams.get(\"art\");\n const variantName = url.searchParams.get(\"variant\");\n\n if (!artPath || !variantName) {\n res.statusCode = 400;\n res.end(\"Missing art or variant parameter\");\n return;\n }\n\n const art = artFiles.get(artPath);\n if (!art) {\n res.statusCode = 404;\n res.end(\"Art not found\");\n return;\n }\n\n const variant = art.variants.find((v) => v.name === variantName);\n if (!variant) {\n res.statusCode = 404;\n res.end(\"Variant not found\");\n return;\n }\n\n const rawHtml = generatePreviewHtml(art, variant, basePath);\n // Transform HTML through Vite to properly resolve module imports\n const html = await devServer.transformIndexHtml(\n `${basePath}/preview?art=${encodeURIComponent(artPath)}&variant=${encodeURIComponent(variantName)}`,\n rawHtml,\n );\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(html);\n });\n\n // Art module route - serves transformed art file as ES module\n devServer.middlewares.use(`${basePath}/art`, async (req, res, next) => {\n const url = new URL(req.url || \"\", \"http://localhost\");\n const artPath = decodeURIComponent(url.pathname.slice(1)); // Remove leading /\n\n if (!artPath) {\n next();\n return;\n }\n\n const art = artFiles.get(artPath);\n if (!art) {\n res.statusCode = 404;\n res.end(\"Art not found: \" + artPath);\n return;\n }\n\n // Transform through Vite for proper imports\n try {\n const virtualId = `virtual:musea-art:${artPath}`;\n const result = await devServer.transformRequest(virtualId);\n if (result) {\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.end(result.code);\n } else {\n // Fallback: generate and serve the module directly\n const moduleCode = generateArtModule(art, artPath);\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.end(moduleCode);\n }\n } catch (err) {\n console.error(\"[musea] Failed to transform art module:\", err);\n // Fallback if transform fails\n const moduleCode = generateArtModule(art, artPath);\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.end(moduleCode);\n }\n });\n\n // API endpoints\n devServer.middlewares.use(`${basePath}/api`, async (req, res, next) => {\n const sendJson = (data: unknown, status = 200) => {\n res.statusCode = status;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify(data));\n };\n\n const sendError = (message: string, status = 500) => {\n sendJson({ error: message }, status);\n };\n\n // GET /api/arts - List all arts\n if (req.url === \"/arts\" && req.method === \"GET\") {\n sendJson(Array.from(artFiles.values()));\n return;\n }\n\n // GET /api/tokens - Get design tokens\n if (req.url === \"/tokens\" && req.method === \"GET\") {\n sendJson({ categories: [] });\n return;\n }\n\n // Arts sub-routes: /api/arts/:encodedPath/...\n if (req.url?.startsWith(\"/arts/\") && req.method === \"GET\") {\n const rest = req.url.slice(6); // after \"/arts/\"\n\n // Check for sub-resource patterns\n const paletteMatch = rest.match(/^(.+)\\/palette$/);\n const analysisMatch = rest.match(/^(.+)\\/analysis$/);\n const docsMatch = rest.match(/^(.+)\\/docs$/);\n const a11yMatch = rest.match(/^(.+)\\/variants\\/([^/]+)\\/a11y$/);\n\n if (paletteMatch) {\n // GET /api/arts/:path/palette\n const artPath = decodeURIComponent(paletteMatch[1]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n try {\n const source = await fs.promises.readFile(artPath, \"utf-8\");\n const binding = loadNative();\n if (binding.generateArtPalette) {\n const palette = binding.generateArtPalette(source, { filename: artPath });\n sendJson(palette);\n } else {\n sendJson({\n title: art.metadata.title,\n controls: [],\n groups: [],\n json: \"{}\",\n typescript: \"\",\n });\n }\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n return;\n }\n\n if (analysisMatch) {\n // GET /api/arts/:path/analysis\n const artPath = decodeURIComponent(analysisMatch[1]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n try {\n // Determine the component file path: inline art uses the file itself, .art.vue uses the component attribute\n const resolvedComponentPath =\n art.isInline && art.componentPath\n ? art.componentPath\n : art.metadata.component\n ? path.isAbsolute(art.metadata.component)\n ? art.metadata.component\n : path.resolve(path.dirname(artPath), art.metadata.component)\n : null;\n\n if (resolvedComponentPath) {\n const source = await fs.promises.readFile(resolvedComponentPath, \"utf-8\");\n const binding = loadNative();\n if (binding.analyzeSfc) {\n const analysis = binding.analyzeSfc(source, { filename: resolvedComponentPath });\n sendJson(analysis);\n } else {\n sendJson({ props: [], emits: [] });\n }\n } else {\n sendJson({ props: [], emits: [] });\n }\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n return;\n }\n\n if (docsMatch) {\n // GET /api/arts/:path/docs\n const artPath = decodeURIComponent(docsMatch[1]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n try {\n const source = await fs.promises.readFile(artPath, \"utf-8\");\n const binding = loadNative();\n if (binding.generateArtDoc) {\n const doc = binding.generateArtDoc(source, { filename: artPath });\n sendJson(doc);\n } else {\n sendJson({\n markdown: \"\",\n title: art.metadata.title,\n variant_count: art.variants.length,\n });\n }\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n return;\n }\n\n if (a11yMatch) {\n // GET /api/arts/:path/variants/:name/a11y\n const artPath = decodeURIComponent(a11yMatch[1]);\n const _variantName = decodeURIComponent(a11yMatch[2]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n // Return empty a11y results (populated after VRT --a11y run)\n sendJson({ violations: [], passes: 0, incomplete: 0 });\n return;\n }\n\n // GET /api/arts/:path - Get single art (no sub-resource)\n const artPath = decodeURIComponent(rest);\n const art = artFiles.get(artPath);\n if (art) {\n sendJson(art);\n } else {\n sendError(\"Art not found\", 404);\n }\n return;\n }\n\n // POST /api/preview-with-props\n if (req.url === \"/preview-with-props\" && req.method === \"POST\") {\n let body = \"\";\n req.on(\"data\", (chunk) => {\n body += chunk;\n });\n req.on(\"end\", () => {\n try {\n const { artPath: reqArtPath, variantName, props: propsOverride } = JSON.parse(body);\n const art = artFiles.get(reqArtPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n const variant = art.variants.find((v) => v.name === variantName);\n if (!variant) {\n sendError(\"Variant not found\", 404);\n return;\n }\n\n // Generate preview module with props override\n const variantComponentName = toPascalCase(variant.name);\n const moduleCode = generatePreviewModuleWithProps(\n art,\n variantComponentName,\n variant.name,\n propsOverride,\n );\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.end(moduleCode);\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n });\n return;\n }\n\n // POST /api/generate\n if (req.url === \"/generate\" && req.method === \"POST\") {\n let body = \"\";\n req.on(\"data\", (chunk) => {\n body += chunk;\n });\n req.on(\"end\", async () => {\n try {\n const { componentPath: reqComponentPath, options: autogenOptions } = JSON.parse(body);\n const { generateArtFile: genArt } = await import(\"./autogen.js\");\n const result = await genArt(reqComponentPath, autogenOptions);\n sendJson({\n generated: true,\n componentName: result.componentName,\n variants: result.variants,\n artFileContent: result.artFileContent,\n });\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n });\n return;\n }\n\n next();\n });\n\n // Watch for Art file changes\n devServer.watcher.on(\"change\", async (file) => {\n if (file.endsWith(\".art.vue\") && shouldProcess(file, include, exclude, config.root)) {\n await processArtFile(file);\n console.log(`[musea] Reloaded: ${path.relative(config.root, file)}`);\n }\n // Inline art: re-check .vue files on change\n if (inlineArt && file.endsWith(\".vue\") && !file.endsWith(\".art.vue\")) {\n const hadArt = artFiles.has(file);\n const source = await fs.promises.readFile(file, \"utf-8\");\n if (source.includes(\"<art\")) {\n await processArtFile(file);\n console.log(`[musea] Reloaded inline art: ${path.relative(config.root, file)}`);\n } else if (hadArt) {\n artFiles.delete(file);\n console.log(`[musea] Removed inline art: ${path.relative(config.root, file)}`);\n }\n }\n });\n\n devServer.watcher.on(\"add\", async (file) => {\n if (file.endsWith(\".art.vue\") && shouldProcess(file, include, exclude, config.root)) {\n await processArtFile(file);\n console.log(`[musea] Added: ${path.relative(config.root, file)}`);\n }\n // Inline art: check new .vue files\n if (inlineArt && file.endsWith(\".vue\") && !file.endsWith(\".art.vue\")) {\n const source = await fs.promises.readFile(file, \"utf-8\");\n if (source.includes(\"<art\")) {\n await processArtFile(file);\n console.log(`[musea] Added inline art: ${path.relative(config.root, file)}`);\n }\n }\n });\n\n devServer.watcher.on(\"unlink\", (file) => {\n if (artFiles.has(file)) {\n artFiles.delete(file);\n console.log(`[musea] Removed: ${path.relative(config.root, file)}`);\n }\n });\n },\n\n async buildStart() {\n // Scan for Art files\n const files = await scanArtFiles(config.root, include, exclude, inlineArt);\n\n console.log(`[musea] Found ${files.length} art files`);\n\n for (const file of files) {\n await processArtFile(file);\n }\n\n // Generate Storybook CSF if enabled\n if (storybookCompat) {\n await generateStorybookFiles(artFiles, config.root, storybookOutDir);\n }\n },\n\n resolveId(id) {\n if (id === VIRTUAL_GALLERY) {\n return VIRTUAL_GALLERY;\n }\n if (id === VIRTUAL_MANIFEST) {\n return VIRTUAL_MANIFEST;\n }\n // Handle virtual:musea-preview: prefix for preview modules\n if (id.startsWith(\"virtual:musea-preview:\")) {\n return \"\\0musea-preview:\" + id.slice(\"virtual:musea-preview:\".length);\n }\n // Handle virtual:musea-art: prefix for preview modules\n if (id.startsWith(\"virtual:musea-art:\")) {\n const artPath = id.slice(\"virtual:musea-art:\".length);\n if (artFiles.has(artPath)) {\n return \"\\0musea-art:\" + artPath;\n }\n }\n if (id.endsWith(\".art.vue\")) {\n const resolved = path.resolve(config.root, id);\n if (artFiles.has(resolved)) {\n return VIRTUAL_MUSEA_PREFIX + resolved;\n }\n }\n // Inline art: resolve .vue files that have <art> blocks\n if (inlineArt && id.endsWith(\".vue\") && !id.endsWith(\".art.vue\")) {\n const resolved = path.resolve(config.root, id);\n if (artFiles.has(resolved)) {\n return VIRTUAL_MUSEA_PREFIX + resolved;\n }\n }\n return null;\n },\n\n load(id) {\n if (id === VIRTUAL_GALLERY) {\n return generateGalleryModule(basePath);\n }\n if (id === VIRTUAL_MANIFEST) {\n return generateManifestModule(artFiles);\n }\n // Handle \\0musea-preview: prefix for preview modules\n if (id.startsWith(\"\\0musea-preview:\")) {\n const rest = id.slice(\"\\0musea-preview:\".length);\n const lastColonIndex = rest.lastIndexOf(\":\");\n if (lastColonIndex !== -1) {\n const artPath = rest.slice(0, lastColonIndex);\n const variantName = rest.slice(lastColonIndex + 1);\n const art = artFiles.get(artPath);\n if (art) {\n const variantComponentName = toPascalCase(variantName);\n return generatePreviewModule(art, variantComponentName, variantName);\n }\n }\n }\n // Handle \\0musea-art: prefix for preview modules\n if (id.startsWith(\"\\0musea-art:\")) {\n const artPath = id.slice(\"\\0musea-art:\".length);\n const art = artFiles.get(artPath);\n if (art) {\n return generateArtModule(art, artPath);\n }\n }\n if (id.startsWith(VIRTUAL_MUSEA_PREFIX)) {\n const realPath = id.slice(VIRTUAL_MUSEA_PREFIX.length);\n const art = artFiles.get(realPath);\n if (art) {\n return generateArtModule(art, realPath);\n }\n }\n return null;\n },\n\n async handleHotUpdate(ctx) {\n const { file } = ctx;\n if (file.endsWith(\".art.vue\") && artFiles.has(file)) {\n await processArtFile(file);\n\n // Invalidate virtual modules\n const virtualId = VIRTUAL_MUSEA_PREFIX + file;\n const modules = server?.moduleGraph.getModulesByFile(virtualId);\n if (modules) {\n return [...modules];\n }\n }\n\n // Inline art: HMR for .vue files with <art> blocks\n if (inlineArt && file.endsWith(\".vue\") && !file.endsWith(\".art.vue\") && artFiles.has(file)) {\n await processArtFile(file);\n\n const virtualId = VIRTUAL_MUSEA_PREFIX + file;\n const modules = server?.moduleGraph.getModulesByFile(virtualId);\n if (modules) {\n return [...modules];\n }\n }\n\n return undefined;\n },\n };\n\n // Helper functions scoped to this plugin instance\n\n async function processArtFile(filePath: string): Promise<void> {\n try {\n const source = await fs.promises.readFile(filePath, \"utf-8\");\n const binding = loadNative();\n const parsed = binding.parseArt(source, { filename: filePath });\n\n // Skip files with no variants (e.g. .vue files without <art> block)\n if (!parsed.variants || parsed.variants.length === 0) return;\n\n const isInline = !filePath.endsWith(\".art.vue\");\n\n const info: ArtFileInfo = {\n path: filePath,\n metadata: {\n title: parsed.metadata.title || (isInline ? path.basename(filePath, \".vue\") : \"\"),\n description: parsed.metadata.description,\n component: isInline ? undefined : parsed.metadata.component,\n category: parsed.metadata.category,\n tags: parsed.metadata.tags,\n status: parsed.metadata.status as \"draft\" | \"ready\" | \"deprecated\",\n order: parsed.metadata.order,\n },\n variants: parsed.variants.map((v) => ({\n name: v.name,\n template: v.template,\n isDefault: v.is_default,\n skipVrt: v.skip_vrt,\n })),\n hasScriptSetup: parsed.has_script_setup,\n hasScript: parsed.has_script,\n styleCount: parsed.style_count,\n isInline,\n componentPath: isInline ? filePath : undefined,\n };\n\n artFiles.set(filePath, info);\n } catch (e) {\n console.error(`[musea] Failed to process ${filePath}:`, e);\n }\n }\n\n return [mainPlugin];\n}\n\n// Utility functions\n\nfunction shouldProcess(file: string, include: string[], exclude: string[], root: string): boolean {\n const relative = path.relative(root, file);\n\n // Check exclude patterns\n for (const pattern of exclude) {\n if (matchGlob(relative, pattern)) {\n return false;\n }\n }\n\n // Check include patterns\n for (const pattern of include) {\n if (matchGlob(relative, pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction matchGlob(filepath: string, pattern: string): boolean {\n // Simple glob matching (supports * and **)\n // Escape . first, then replace glob patterns\n const regex = pattern\n .replace(/\\./g, \"\\\\.\")\n .replace(/\\*\\*/g, \".*\")\n .replace(/\\*(?!\\*)/g, \"[^/]*\");\n\n return new RegExp(`^${regex}$`).test(filepath);\n}\n\nasync function scanArtFiles(\n root: string,\n include: string[],\n exclude: string[],\n scanInlineArt = false,\n): Promise<string[]> {\n const files: string[] = [];\n\n async function scan(dir: string): Promise<void> {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n const relative = path.relative(root, fullPath);\n\n // Check exclude\n let excluded = false;\n for (const pattern of exclude) {\n if (matchGlob(relative, pattern) || matchGlob(entry.name, pattern)) {\n excluded = true;\n break;\n }\n }\n\n if (excluded) continue;\n\n if (entry.isDirectory()) {\n await scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith(\".art.vue\")) {\n // Check include\n for (const pattern of include) {\n if (matchGlob(relative, pattern)) {\n files.push(fullPath);\n break;\n }\n }\n } else if (\n scanInlineArt &&\n entry.isFile() &&\n entry.name.endsWith(\".vue\") &&\n !entry.name.endsWith(\".art.vue\")\n ) {\n // Inline art: check if .vue file contains <art block\n const content = await fs.promises.readFile(fullPath, \"utf-8\");\n if (content.includes(\"<art\")) {\n files.push(fullPath);\n }\n }\n }\n }\n\n await scan(root);\n return files;\n}\n\nfunction generateGalleryHtml(basePath: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Musea - Component Gallery</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n <style>\n :root {\n --musea-bg-primary: #0d0d0d;\n --musea-bg-secondary: #1a1815;\n --musea-bg-tertiary: #252220;\n --musea-bg-elevated: #2d2a27;\n --musea-accent: #a34828;\n --musea-accent-hover: #c45a32;\n --musea-accent-subtle: rgba(163, 72, 40, 0.15);\n --musea-text: #e6e9f0;\n --musea-text-secondary: #c4c9d4;\n --musea-text-muted: #7b8494;\n --musea-border: #3a3530;\n --musea-border-subtle: #2a2725;\n --musea-success: #4ade80;\n --musea-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);\n --musea-radius-sm: 6px;\n --musea-radius-md: 8px;\n --musea-radius-lg: 12px;\n --musea-transition: 0.15s ease;\n }\n\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n body {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n background: var(--musea-bg-primary);\n color: var(--musea-text);\n min-height: 100vh;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n }\n\n /* Header */\n .header {\n background: var(--musea-bg-secondary);\n border-bottom: 1px solid var(--musea-border);\n padding: 0 1.5rem;\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n position: sticky;\n top: 0;\n z-index: 100;\n }\n\n .header-left {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n }\n\n .logo {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 1.125rem;\n font-weight: 700;\n color: var(--musea-accent);\n text-decoration: none;\n }\n\n .logo-svg {\n width: 32px;\n height: 32px;\n flex-shrink: 0;\n }\n\n .logo-icon svg {\n width: 16px;\n height: 16px;\n color: white;\n }\n\n .header-subtitle {\n color: var(--musea-text-muted);\n font-size: 0.8125rem;\n font-weight: 500;\n padding-left: 1.5rem;\n border-left: 1px solid var(--musea-border);\n }\n\n .search-container {\n position: relative;\n width: 280px;\n }\n\n .search-input {\n width: 100%;\n background: var(--musea-bg-tertiary);\n border: 1px solid var(--musea-border);\n border-radius: var(--musea-radius-md);\n padding: 0.5rem 0.75rem 0.5rem 2.25rem;\n color: var(--musea-text);\n font-size: 0.8125rem;\n outline: none;\n transition: border-color var(--musea-transition), background var(--musea-transition);\n }\n\n .search-input::placeholder {\n color: var(--musea-text-muted);\n }\n\n .search-input:focus {\n border-color: var(--musea-accent);\n background: var(--musea-bg-elevated);\n }\n\n .search-icon {\n position: absolute;\n left: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--musea-text-muted);\n pointer-events: none;\n }\n\n /* Layout */\n .main {\n display: grid;\n grid-template-columns: 260px 1fr;\n min-height: calc(100vh - 56px);\n }\n\n /* Sidebar */\n .sidebar {\n background: var(--musea-bg-secondary);\n border-right: 1px solid var(--musea-border);\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n .sidebar::-webkit-scrollbar {\n width: 6px;\n }\n\n .sidebar::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .sidebar::-webkit-scrollbar-thumb {\n background: var(--musea-border);\n border-radius: 3px;\n }\n\n .sidebar-section {\n padding: 0.75rem;\n }\n\n .category-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.625rem 0.75rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--musea-text-muted);\n cursor: pointer;\n user-select: none;\n border-radius: var(--musea-radius-sm);\n transition: background var(--musea-transition);\n }\n\n .category-header:hover {\n background: var(--musea-bg-tertiary);\n }\n\n .category-icon {\n width: 16px;\n height: 16px;\n transition: transform var(--musea-transition);\n }\n\n .category-header.collapsed .category-icon {\n transform: rotate(-90deg);\n }\n\n .category-count {\n margin-left: auto;\n background: var(--musea-bg-tertiary);\n padding: 0.125rem 0.375rem;\n border-radius: 4px;\n font-size: 0.625rem;\n }\n\n .art-list {\n list-style: none;\n margin-top: 0.25rem;\n }\n\n .art-item {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 0.5rem 0.75rem 0.5rem 1.75rem;\n border-radius: var(--musea-radius-sm);\n cursor: pointer;\n font-size: 0.8125rem;\n color: var(--musea-text-secondary);\n transition: all var(--musea-transition);\n position: relative;\n }\n\n .art-item::before {\n content: '';\n position: absolute;\n left: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--musea-border);\n transition: background var(--musea-transition);\n }\n\n .art-item:hover {\n background: var(--musea-bg-tertiary);\n color: var(--musea-text);\n }\n\n .art-item:hover::before {\n background: var(--musea-text-muted);\n }\n\n .art-item.active {\n background: var(--musea-accent-subtle);\n color: var(--musea-accent-hover);\n }\n\n .art-item.active::before {\n background: var(--musea-accent);\n }\n\n .art-variant-count {\n margin-left: auto;\n font-size: 0.6875rem;\n color: var(--musea-text-muted);\n opacity: 0;\n transition: opacity var(--musea-transition);\n }\n\n .art-item:hover .art-variant-count {\n opacity: 1;\n }\n\n /* Content */\n .content {\n background: var(--musea-bg-primary);\n overflow-y: auto;\n }\n\n .content-inner {\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n }\n\n .content-header {\n margin-bottom: 2rem;\n }\n\n .content-title {\n font-size: 1.5rem;\n font-weight: 700;\n margin-bottom: 0.5rem;\n }\n\n .content-description {\n color: var(--musea-text-muted);\n font-size: 0.9375rem;\n max-width: 600px;\n }\n\n .content-meta {\n display: flex;\n align-items: center;\n gap: 1rem;\n margin-top: 1rem;\n }\n\n .meta-tag {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.625rem;\n background: var(--musea-bg-secondary);\n border: 1px solid var(--musea-border);\n border-radius: var(--musea-radius-sm);\n font-size: 0.75rem;\n color: var(--musea-text-muted);\n }\n\n .meta-tag svg {\n width: 12px;\n height: 12px;\n }\n\n /* Gallery Grid */\n .gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 1.25rem;\n }\n\n /* Variant Card */\n .variant-card {\n background: var(--musea-bg-secondary);\n border: 1px solid var(--musea-border);\n border-radius: var(--musea-radius-lg);\n overflow: hidden;\n transition: all var(--musea-transition);\n }\n\n .variant-card:hover {\n border-color: var(--musea-text-muted);\n box-shadow: var(--musea-shadow);\n transform: translateY(-2px);\n }\n\n .variant-preview {\n aspect-ratio: 16 / 10;\n background: var(--musea-bg-tertiary);\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n }\n\n .variant-preview iframe {\n width: 100%;\n height: 100%;\n border: none;\n background: white;\n }\n\n .variant-preview-placeholder {\n color: var(--musea-text-muted);\n font-size: 0.8125rem;\n text-align: center;\n padding: 1rem;\n }\n\n .variant-preview-code {\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 0.75rem;\n color: var(--musea-text-muted);\n background: var(--musea-bg-primary);\n padding: 1rem;\n overflow: auto;\n max-height: 100%;\n width: 100%;\n }\n\n .variant-info {\n padding: 1rem;\n border-top: 1px solid var(--musea-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .variant-name {\n font-weight: 600;\n font-size: 0.875rem;\n }\n\n .variant-badge {\n font-size: 0.625rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n padding: 0.1875rem 0.5rem;\n border-radius: 4px;\n background: var(--musea-accent-subtle);\n color: var(--musea-accent);\n }\n\n .variant-actions {\n display: flex;\n gap: 0.5rem;\n }\n\n .variant-action-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: var(--musea-bg-tertiary);\n border-radius: var(--musea-radius-sm);\n color: var(--musea-text-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all var(--musea-transition);\n }\n\n .variant-action-btn:hover {\n background: var(--musea-bg-elevated);\n color: var(--musea-text);\n }\n\n .variant-action-btn svg {\n width: 14px;\n height: 14px;\n }\n\n /* Empty State */\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 400px;\n text-align: center;\n padding: 2rem;\n }\n\n .empty-state-icon {\n width: 80px;\n height: 80px;\n background: var(--musea-bg-secondary);\n border-radius: var(--musea-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 1.5rem;\n }\n\n .empty-state-icon svg {\n width: 40px;\n height: 40px;\n color: var(--musea-text-muted);\n }\n\n .empty-state-title {\n font-size: 1.125rem;\n font-weight: 600;\n margin-bottom: 0.5rem;\n }\n\n .empty-state-text {\n color: var(--musea-text-muted);\n font-size: 0.875rem;\n max-width: 300px;\n }\n\n /* Loading */\n .loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n color: var(--musea-text-muted);\n gap: 0.75rem;\n }\n\n .loading-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid var(--musea-border);\n border-top-color: var(--musea-accent);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .main {\n grid-template-columns: 1fr;\n }\n .sidebar {\n display: none;\n }\n .header-subtitle {\n display: none;\n }\n }\n </style>\n</head>\n<body>\n <header class=\"header\">\n <div class=\"header-left\">\n <a href=\"${basePath}\" class=\"logo\">\n <svg class=\"logo-svg\" width=\"32\" height=\"32\" viewBox=\"0 0 200 200\" fill=\"none\">\n <defs>\n <linearGradient id=\"metal-grad\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"20%\">\n <stop offset=\"0%\" stop-color=\"#f0f2f5\"/>\n <stop offset=\"50%\" stop-color=\"#9ca3b0\"/>\n <stop offset=\"100%\" stop-color=\"#e07048\"/>\n </linearGradient>\n <linearGradient id=\"metal-grad-dark\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"30%\">\n <stop offset=\"0%\" stop-color=\"#d0d4dc\"/>\n <stop offset=\"60%\" stop-color=\"#6b7280\"/>\n <stop offset=\"100%\" stop-color=\"#c45530\"/>\n </linearGradient>\n </defs>\n <g transform=\"translate(40, 40)\">\n <g transform=\"skewX(-12)\">\n <path d=\"M 100 0 L 60 120 L 105 30 L 100 0 Z\" fill=\"url(#metal-grad-dark)\" stroke=\"#4b5563\" stroke-width=\"0.5\"/>\n <path d=\"M 30 0 L 60 120 L 80 20 L 30 0 Z\" fill=\"url(#metal-grad)\" stroke-width=\"0.5\" stroke-opacity=\"0.4\"/>\n </g>\n </g>\n <g transform=\"translate(110, 120)\">\n <line x1=\"5\" y1=\"10\" x2=\"5\" y2=\"50\" stroke=\"#e07048\" stroke-width=\"3\" stroke-linecap=\"round\"/>\n <line x1=\"60\" y1=\"10\" x2=\"60\" y2=\"50\" stroke=\"#e07048\" stroke-width=\"3\" stroke-linecap=\"round\"/>\n <path d=\"M 0 10 L 32.5 0 L 65 10\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <rect x=\"15\" y=\"18\" width=\"14\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"1.5\" opacity=\"0.7\"/>\n <rect x=\"36\" y=\"18\" width=\"14\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"1.5\" opacity=\"0.7\"/>\n <rect x=\"23\" y=\"35\" width=\"18\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"1.5\" opacity=\"0.6\"/>\n </g>\n </svg>\n Musea\n </a>\n <span class=\"header-subtitle\">Component Gallery</span>\n </div>\n <div class=\"search-container\">\n <svg class=\"search-icon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"m21 21-4.35-4.35\"/>\n </svg>\n <input type=\"text\" class=\"search-input\" placeholder=\"Search components...\" id=\"search\">\n </div>\n </header>\n\n <main class=\"main\">\n <aside class=\"sidebar\" id=\"sidebar\">\n <div class=\"loading\">\n <div class=\"loading-spinner\"></div>\n Loading...\n </div>\n </aside>\n <section class=\"content\" id=\"content\">\n <div class=\"empty-state\">\n <div class=\"empty-state-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M4 5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5Z\"/>\n <path d=\"M4 13a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-6Z\"/>\n <path d=\"M16 13a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6Z\"/>\n </svg>\n </div>\n <div class=\"empty-state-title\">Select a component</div>\n <div class=\"empty-state-text\">Choose a component from the sidebar to view its variants and documentation</div>\n </div>\n </section>\n </main>\n\n <script type=\"module\">\n const basePath = '${basePath}';\n let arts = [];\n let selectedArt = null;\n let searchQuery = '';\n\n async function loadArts() {\n try {\n const res = await fetch(basePath + '/api/arts');\n arts = await res.json();\n renderSidebar();\n } catch (e) {\n console.error('Failed to load arts:', e);\n document.getElementById('sidebar').innerHTML = '<div class=\"loading\">Failed to load</div>';\n }\n }\n\n function renderSidebar() {\n const sidebar = document.getElementById('sidebar');\n const categories = {};\n\n const filtered = searchQuery\n ? arts.filter(a => a.metadata.title.toLowerCase().includes(searchQuery.toLowerCase()))\n : arts;\n\n for (const art of filtered) {\n const cat = art.metadata.category || 'Components';\n if (!categories[cat]) categories[cat] = [];\n categories[cat].push(art);\n }\n\n if (Object.keys(categories).length === 0) {\n sidebar.innerHTML = '<div class=\"sidebar-section\"><div class=\"loading\">No components found</div></div>';\n return;\n }\n\n let html = '';\n for (const [category, items] of Object.entries(categories)) {\n html += '<div class=\"sidebar-section\">';\n html += '<div class=\"category-header\" data-category=\"' + category + '\">';\n html += '<svg class=\"category-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m9 18 6-6-6-6\"/></svg>';\n html += '<span>' + category + '</span>';\n html += '<span class=\"category-count\">' + items.length + '</span>';\n html += '</div>';\n html += '<ul class=\"art-list\" data-category=\"' + category + '\">';\n for (const art of items) {\n const active = selectedArt?.path === art.path ? 'active' : '';\n const variantCount = art.variants?.length || 0;\n html += '<li class=\"art-item ' + active + '\" data-path=\"' + art.path + '\">';\n html += '<span>' + escapeHtml(art.metadata.title) + '</span>';\n html += '<span class=\"art-variant-count\">' + variantCount + ' variant' + (variantCount !== 1 ? 's' : '') + '</span>';\n html += '</li>';\n }\n html += '</ul>';\n html += '</div>';\n }\n\n sidebar.innerHTML = html;\n\n sidebar.querySelectorAll('.art-item').forEach(item => {\n item.addEventListener('click', () => {\n const artPath = item.dataset.path;\n selectedArt = arts.find(a => a.path === artPath);\n renderSidebar();\n renderContent();\n });\n });\n\n sidebar.querySelectorAll('.category-header').forEach(header => {\n header.addEventListener('click', () => {\n header.classList.toggle('collapsed');\n const list = sidebar.querySelector('.art-list[data-category=\"' + header.dataset.category + '\"]');\n if (list) list.style.display = header.classList.contains('collapsed') ? 'none' : 'block';\n });\n });\n }\n\n function renderContent() {\n const content = document.getElementById('content');\n if (!selectedArt) {\n content.innerHTML = \\`\n <div class=\"empty-state\">\n <div class=\"empty-state-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M4 5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5Z\"/>\n <path d=\"M4 13a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-6Z\"/>\n <path d=\"M16 13a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6Z\"/>\n </svg>\n </div>\n <div class=\"empty-state-title\">Select a component</div>\n <div class=\"empty-state-text\">Choose a component from the sidebar to view its variants</div>\n </div>\n \\`;\n return;\n }\n\n const meta = selectedArt.metadata;\n const tags = meta.tags || [];\n const variantCount = selectedArt.variants?.length || 0;\n\n let html = '<div class=\"content-inner\">';\n html += '<div class=\"content-header\">';\n html += '<h1 class=\"content-title\">' + escapeHtml(meta.title) + '</h1>';\n if (meta.description) {\n html += '<p class=\"content-description\">' + escapeHtml(meta.description) + '</p>';\n }\n html += '<div class=\"content-meta\">';\n html += '<span class=\"meta-tag\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"/></svg>' + variantCount + ' variant' + (variantCount !== 1 ? 's' : '') + '</span>';\n if (meta.category) {\n html += '<span class=\"meta-tag\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\"/></svg>' + escapeHtml(meta.category) + '</span>';\n }\n for (const tag of tags) {\n html += '<span class=\"meta-tag\">#' + escapeHtml(tag) + '</span>';\n }\n html += '</div>';\n html += '</div>';\n\n html += '<div class=\"gallery\">';\n for (const variant of selectedArt.variants) {\n const previewUrl = basePath + '/preview?art=' + encodeURIComponent(selectedArt.path) + '&variant=' + encodeURIComponent(variant.name);\n\n html += '<div class=\"variant-card\">';\n html += '<div class=\"variant-preview\">';\n html += '<iframe src=\"' + previewUrl + '\" loading=\"lazy\" title=\"' + escapeHtml(variant.name) + '\"></iframe>';\n html += '</div>';\n html += '<div class=\"variant-info\">';\n html += '<div>';\n html += '<span class=\"variant-name\">' + escapeHtml(variant.name) + '</span>';\n if (variant.isDefault) html += ' <span class=\"variant-badge\">Default</span>';\n html += '</div>';\n html += '<div class=\"variant-actions\">';\n html += '<button class=\"variant-action-btn\" title=\"Open in new tab\" onclick=\"window.open(\\\\'' + previewUrl + '\\\\', \\\\'_blank\\\\')\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/><polyline points=\"15 3 21 3 21 9\"/><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"/></svg></button>';\n html += '</div>';\n html += '</div>';\n html += '</div>';\n }\n html += '</div>';\n html += '</div>';\n\n content.innerHTML = html;\n }\n\n function escapeHtml(str) {\n if (!str) return '';\n return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n }\n\n // Search\n document.getElementById('search').addEventListener('input', (e) => {\n searchQuery = e.target.value;\n renderSidebar();\n });\n\n // Keyboard shortcut for search\n document.addEventListener('keydown', (e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n e.preventDefault();\n document.getElementById('search').focus();\n }\n });\n\n loadArts();\n </script>\n</body>\n</html>`;\n}\n\nfunction generateGalleryModule(basePath: string): string {\n return `\nexport const basePath = '${basePath}';\nexport async function loadArts() {\n const res = await fetch(basePath + '/api/arts');\n return res.json();\n}\n`;\n}\n\n// Addon initialization code injected into preview iframe modules.\n// Shared between generatePreviewModule and generatePreviewModuleWithProps.\nconst MUSEA_ADDONS_INIT_CODE = `\nfunction __museaInitAddons(container) {\n // === DOM event capture ===\n const CAPTURE_EVENTS = ['click','dblclick','input','change','submit','focus','blur','keydown','keyup'];\n for (const evt of CAPTURE_EVENTS) {\n container.addEventListener(evt, (e) => {\n const payload = {\n name: evt,\n target: e.target?.tagName,\n timestamp: Date.now(),\n source: 'dom'\n };\n if (e.target && 'value' in e.target) {\n payload.value = e.target.value;\n }\n window.parent.postMessage({ type: 'musea:event', payload }, '*');\n }, true);\n }\n\n // === Message handler for parent commands ===\n let measureActive = false;\n let measureOverlay = null;\n let measureLabel = null;\n\n function toggleStyleById(id, enabled, css) {\n let el = document.getElementById(id);\n if (enabled) {\n if (!el) {\n el = document.createElement('style');\n el.id = id;\n el.textContent = css;\n document.head.appendChild(el);\n }\n } else {\n if (el) el.remove();\n }\n }\n\n function createMeasureOverlay() {\n if (measureOverlay) return;\n measureOverlay = document.createElement('div');\n measureOverlay.id = 'musea-measure-overlay';\n measureOverlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:99999;';\n document.body.appendChild(measureOverlay);\n\n measureLabel = document.createElement('div');\n measureLabel.className = 'musea-measure-label';\n measureLabel.style.cssText = 'position:fixed;background:#333;color:#fff;font-size:11px;padding:2px 6px;border-radius:3px;pointer-events:none;z-index:100000;display:none;';\n document.body.appendChild(measureLabel);\n }\n\n function removeMeasureOverlay() {\n if (measureOverlay) { measureOverlay.remove(); measureOverlay = null; }\n if (measureLabel) { measureLabel.remove(); measureLabel = null; }\n }\n\n function onMeasureMouseMove(e) {\n if (!measureActive || !measureOverlay) return;\n const el = document.elementFromPoint(e.clientX, e.clientY);\n if (!el || el === measureOverlay || el === measureLabel) return;\n\n const rect = el.getBoundingClientRect();\n const cs = getComputedStyle(el);\n const mt = parseFloat(cs.marginTop) || 0;\n const mr = parseFloat(cs.marginRight) || 0;\n const mb = parseFloat(cs.marginBottom) || 0;\n const ml = parseFloat(cs.marginLeft) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n const blw = parseFloat(cs.borderLeftWidth) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const pl = parseFloat(cs.paddingLeft) || 0;\n\n const cw = rect.width - blw - br - pl - pr;\n const ch = rect.height - bt - bb - pt - pb;\n\n measureOverlay.innerHTML = ''\n // Margin\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + (rect.left - ml) + 'px;top:' + (rect.top - mt) + 'px;'\n + 'width:' + (rect.width + ml + mr) + 'px;height:' + mt + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + (rect.left - ml) + 'px;top:' + (rect.bottom) + 'px;'\n + 'width:' + (rect.width + ml + mr) + 'px;height:' + mb + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + (rect.left - ml) + 'px;top:' + rect.top + 'px;'\n + 'width:' + ml + 'px;height:' + rect.height + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + rect.right + 'px;top:' + rect.top + 'px;'\n + 'width:' + mr + 'px;height:' + rect.height + 'px;\"></div>'\n // Border\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + rect.left + 'px;top:' + rect.top + 'px;'\n + 'width:' + rect.width + 'px;height:' + bt + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + rect.left + 'px;top:' + (rect.bottom - bb) + 'px;'\n + 'width:' + rect.width + 'px;height:' + bb + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + rect.left + 'px;top:' + (rect.top + bt) + 'px;'\n + 'width:' + blw + 'px;height:' + (rect.height - bt - bb) + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + (rect.right - br) + 'px;top:' + (rect.top + bt) + 'px;'\n + 'width:' + br + 'px;height:' + (rect.height - bt - bb) + 'px;\"></div>'\n // Padding\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.left + blw) + 'px;top:' + (rect.top + bt) + 'px;'\n + 'width:' + (rect.width - blw - br) + 'px;height:' + pt + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.left + blw) + 'px;top:' + (rect.bottom - bb - pb) + 'px;'\n + 'width:' + (rect.width - blw - br) + 'px;height:' + pb + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.left + blw) + 'px;top:' + (rect.top + bt + pt) + 'px;'\n + 'width:' + pl + 'px;height:' + (rect.height - bt - bb - pt - pb) + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.right - br - pr) + 'px;top:' + (rect.top + bt + pt) + 'px;'\n + 'width:' + pr + 'px;height:' + (rect.height - bt - bb - pt - pb) + 'px;\"></div>'\n // Content\n + '<div style=\"position:fixed;background:rgba(100,149,237,0.3);'\n + 'left:' + (rect.left + blw + pl) + 'px;top:' + (rect.top + bt + pt) + 'px;'\n + 'width:' + cw + 'px;height:' + ch + 'px;\"></div>';\n\n // Label\n measureLabel.textContent = Math.round(rect.width) + ' x ' + Math.round(rect.height);\n measureLabel.style.display = 'block';\n measureLabel.style.left = (rect.right + 8) + 'px';\n measureLabel.style.top = rect.top + 'px';\n }\n\n window.addEventListener('message', (e) => {\n if (!e.data?.type?.startsWith('musea:')) return;\n const { type, payload } = e.data;\n switch (type) {\n case 'musea:set-background': {\n if (payload.pattern === 'checkerboard') {\n document.body.style.background = '';\n document.body.classList.add('musea-bg-checkerboard');\n } else {\n document.body.classList.remove('musea-bg-checkerboard');\n document.body.style.background = payload.color || '';\n }\n break;\n }\n case 'musea:toggle-outline': {\n toggleStyleById('musea-outline', payload.enabled,\n '* { outline: 1px solid rgba(255, 0, 0, 0.3) !important; }');\n break;\n }\n case 'musea:toggle-measure': {\n measureActive = payload.enabled;\n if (measureActive) {\n createMeasureOverlay();\n document.addEventListener('mousemove', onMeasureMouseMove);\n } else {\n document.removeEventListener('mousemove', onMeasureMouseMove);\n removeMeasureOverlay();\n }\n break;\n }\n case 'musea:set-props': {\n // Store props for remount - handled by preview module\n if (window.__museaSetProps) {\n window.__museaSetProps(payload.props || {});\n }\n break;\n }\n case 'musea:set-slots': {\n // Store slots for remount - handled by preview module\n if (window.__museaSetSlots) {\n window.__museaSetSlots(payload.slots || {});\n }\n break;\n }\n }\n });\n\n // Notify parent that iframe is ready\n window.parent.postMessage({ type: 'musea:ready', payload: {} }, '*');\n}\n`;\n\nfunction generatePreviewModule(\n art: ArtFileInfo,\n variantComponentName: string,\n variantName: string,\n): string {\n const artModuleId = `virtual:musea-art:${art.path}`;\n const escapedVariantName = escapeTemplate(variantName);\n\n return `\nimport { createApp, reactive, h } from 'vue';\nimport * as artModule from '${artModuleId}';\n\nconst container = document.getElementById('app');\n\n${MUSEA_ADDONS_INIT_CODE}\n\nlet currentApp = null;\nconst propsOverride = reactive({});\nconst slotsOverride = reactive({ default: '' });\n\nwindow.__museaSetProps = (props) => {\n // Clear old keys\n for (const key of Object.keys(propsOverride)) {\n delete propsOverride[key];\n }\n Object.assign(propsOverride, props);\n};\n\nwindow.__museaSetSlots = (slots) => {\n Object.assign(slotsOverride, slots);\n};\n\nasync function mount() {\n try {\n // Get the specific variant component\n const VariantComponent = artModule['${variantComponentName}'];\n const RawComponent = artModule.__component__;\n\n if (!VariantComponent) {\n throw new Error('Variant component \"${variantComponentName}\" not found in art module');\n }\n\n // Create and mount the app\n const app = createApp(VariantComponent);\n container.innerHTML = '';\n container.className = 'musea-variant';\n app.mount(container);\n currentApp = app;\n\n console.log('[musea-preview] Mounted variant: ${escapedVariantName}');\n __museaInitAddons(container);\n\n // Override set-props to remount with raw component + props\n if (RawComponent) {\n window.__museaSetProps = (props) => {\n for (const key of Object.keys(propsOverride)) {\n delete propsOverride[key];\n }\n Object.assign(propsOverride, props);\n remountWithProps(RawComponent);\n };\n window.__museaSetSlots = (slots) => {\n Object.assign(slotsOverride, slots);\n remountWithProps(RawComponent);\n };\n }\n } catch (error) {\n console.error('[musea-preview] Failed to mount:', error);\n container.innerHTML = \\`\n <div class=\"musea-error\">\n <div class=\"musea-error-title\">Failed to render component</div>\n <div>\\${error.message}</div>\n <pre>\\${error.stack || ''}</pre>\n </div>\n \\`;\n }\n}\n\nfunction remountWithProps(Component) {\n if (currentApp) {\n currentApp.unmount();\n }\n const app = createApp({\n setup() {\n return () => {\n const slotFns = {};\n if (slotsOverride.default) {\n slotFns.default = () => h('span', { innerHTML: slotsOverride.default });\n }\n return h('div', { class: 'musea-variant' }, [\n h(Component, { ...propsOverride }, slotFns)\n ]);\n };\n }\n });\n container.innerHTML = '';\n app.mount(container);\n currentApp = app;\n}\n\nmount();\n`;\n}\n\nfunction generateManifestModule(artFiles: Map<string, ArtFileInfo>): string {\n const arts = Array.from(artFiles.values());\n return `export const arts = ${JSON.stringify(arts, null, 2)};`;\n}\n\nfunction generateArtModule(art: ArtFileInfo, filePath: string): string {\n let componentImportPath: string | undefined;\n let componentName: string | undefined;\n\n if (art.isInline && art.componentPath) {\n // Inline art: import the host .vue file itself as the component\n componentImportPath = art.componentPath;\n componentName = path.basename(art.componentPath, \".vue\");\n } else if (art.metadata.component) {\n // Traditional .art.vue: resolve component from the component attribute\n const comp = art.metadata.component;\n componentImportPath = path.isAbsolute(comp) ? comp : path.resolve(path.dirname(filePath), comp);\n componentName = path.basename(comp, \".vue\");\n }\n\n let code = `\n// Auto-generated module for: ${path.basename(filePath)}\nimport { defineComponent, h } from 'vue';\n`;\n\n if (componentImportPath && componentName) {\n code += `import ${componentName} from '${componentImportPath}';\\n`;\n code += `export const __component__ = ${componentName};\\n`;\n }\n\n code += `\nexport const metadata = ${JSON.stringify(art.metadata)};\nexport const variants = ${JSON.stringify(art.variants)};\n`;\n\n // Generate variant components\n for (const variant of art.variants) {\n const variantComponentName = toPascalCase(variant.name);\n\n let template = variant.template;\n\n // Replace <Self> with the actual component name (for inline art)\n if (componentName) {\n template = template\n .replace(/<Self/g, `<${componentName}`)\n .replace(/<\\/Self>/g, `</${componentName}>`);\n }\n\n // Escape the template for use in a JS string\n const escapedTemplate = template\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/`/g, \"\\\\`\")\n .replace(/\\$/g, \"\\\\$\");\n\n // Wrap template with the variant container\n const fullTemplate = `<div class=\"musea-variant\" data-variant=\"${variant.name}\">${escapedTemplate}</div>`;\n\n if (componentName) {\n code += `\nexport const ${variantComponentName} = {\n name: '${variantComponentName}',\n components: { ${componentName} },\n template: \\`${fullTemplate}\\`,\n};\n`;\n } else {\n code += `\nexport const ${variantComponentName} = {\n name: '${variantComponentName}',\n template: \\`${fullTemplate}\\`,\n};\n`;\n }\n }\n\n // Default export\n const defaultVariant = art.variants.find((v) => v.isDefault) || art.variants[0];\n if (defaultVariant) {\n code += `\nexport default ${toPascalCase(defaultVariant.name)};\n`;\n }\n\n return code;\n}\n\nasync function generateStorybookFiles(\n artFiles: Map<string, ArtFileInfo>,\n root: string,\n outDir: string,\n): Promise<void> {\n const binding = loadNative();\n const outputDir = path.resolve(root, outDir);\n\n // Ensure output directory exists\n await fs.promises.mkdir(outputDir, { recursive: true });\n\n for (const [filePath, _art] of artFiles) {\n try {\n const source = await fs.promises.readFile(filePath, \"utf-8\");\n const csf = binding.artToCsf(source, { filename: filePath });\n\n const outputPath = path.join(outputDir, csf.filename);\n await fs.promises.writeFile(outputPath, csf.code, \"utf-8\");\n\n console.log(`[musea] Generated: ${path.relative(root, outputPath)}`);\n } catch (e) {\n console.error(`[musea] Failed to generate CSF for ${filePath}:`, e);\n }\n }\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[\\s\\-_]+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n\nfunction escapeTemplate(str: string): string {\n return str.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\").replace(/\\n/g, \"\\\\n\");\n}\n\nfunction generatePreviewModuleWithProps(\n art: ArtFileInfo,\n variantComponentName: string,\n variantName: string,\n propsOverride: Record<string, unknown>,\n): string {\n const artModuleId = `virtual:musea-art:${art.path}`;\n const escapedVariantName = escapeTemplate(variantName);\n const propsJson = JSON.stringify(propsOverride);\n\n return `\nimport { createApp, h } from 'vue';\nimport * as artModule from '${artModuleId}';\n\nconst container = document.getElementById('app');\nconst propsOverride = ${propsJson};\n\n${MUSEA_ADDONS_INIT_CODE}\n\nasync function mount() {\n try {\n const VariantComponent = artModule['${variantComponentName}'];\n if (!VariantComponent) {\n throw new Error('Variant component \"${variantComponentName}\" not found');\n }\n\n const WrappedComponent = {\n render() {\n return h(VariantComponent, propsOverride);\n }\n };\n\n const app = createApp(WrappedComponent);\n container.innerHTML = '';\n container.className = 'musea-variant';\n app.mount(container);\n console.log('[musea-preview] Mounted variant: ${escapedVariantName} with props override');\n __museaInitAddons(container);\n } catch (error) {\n console.error('[musea-preview] Failed to mount:', error);\n container.innerHTML = '<div class=\"musea-error\"><div class=\"musea-error-title\">Failed to render</div><div>' + error.message + '</div></div>';\n }\n}\n\nmount();\n`;\n}\n\nfunction generatePreviewHtml(art: ArtFileInfo, variant: ArtVariant, basePath: string): string {\n // Create a unique module URL for each variant to avoid caching issues\n const previewModuleUrl = `${basePath}/preview-module?art=${encodeURIComponent(art.path)}&variant=${encodeURIComponent(variant.name)}`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(art.metadata.title)} - ${escapeHtml(variant.name)}</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n html, body {\n width: 100%;\n height: 100%;\n }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n }\n .musea-variant {\n padding: 1.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .musea-error {\n color: #dc2626;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n padding: 1rem;\n font-size: 0.875rem;\n max-width: 400px;\n }\n .musea-error-title {\n font-weight: 600;\n margin-bottom: 0.5rem;\n }\n .musea-error pre {\n font-family: monospace;\n font-size: 0.75rem;\n white-space: pre-wrap;\n word-break: break-all;\n margin-top: 0.5rem;\n padding: 0.5rem;\n background: #fff;\n border-radius: 4px;\n }\n .musea-loading {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n color: #6b7280;\n font-size: 0.875rem;\n }\n .musea-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid #e5e7eb;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n\n /* Musea Addons: Checkerboard background for transparent mode */\n .musea-bg-checkerboard {\n background-image:\n linear-gradient(45deg, #ccc 25%, transparent 25%),\n linear-gradient(-45deg, #ccc 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #ccc 75%),\n linear-gradient(-45deg, transparent 75%, #ccc 75%) !important;\n background-size: 20px 20px !important;\n background-position: 0 0, 0 10px, 10px -10px, -10px 0 !important;\n }\n\n /* Musea Addons: Measure label */\n .musea-measure-label {\n position: fixed;\n background: #333;\n color: #fff;\n font-size: 11px;\n padding: 2px 6px;\n border-radius: 3px;\n pointer-events: none;\n z-index: 100000;\n }\n </style>\n</head>\n<body>\n <div id=\"app\" class=\"musea-variant\" data-art=\"${escapeHtml(art.path)}\" data-variant=\"${escapeHtml(variant.name)}\">\n <div class=\"musea-loading\">\n <div class=\"musea-spinner\"></div>\n Loading component...\n </div>\n </div>\n <script type=\"module\" src=\"${previewModuleUrl}\"></script>\n</body>\n</html>`;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nexport default musea;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["tokensPath: string","dirPath: string","categories: TokenCategory[]","tokens: Record<string, unknown>","prefix: string[]","obj: Record<string, unknown>","tokens: Record<string, DesignToken>","subcategories: TokenCategory[]","value: unknown","raw: Record<string, unknown>","name: string","token: DesignToken","category: TokenCategory","level: number","config: StyleDictionaryConfig","content: string","filename: string","native: NativeBinding | null","theme?: MuseaOptions[\"theme\"]","custom: Record<string, { base?: \"dark\" | \"light\"; colors: Record<string, string> }>","options: MuseaOptions","config: ResolvedConfig","server: ViteDevServer | null","mainPlugin: Plugin","mimeTypes: Record<string, string>","data: unknown","message: string","artPath","art","MuseaVrtRunner","filePath: string","info: ArtFileInfo","file: string","include: string[]","exclude: string[]","root: string","filepath: string","pattern: string","files: string[]","dir: string","basePath: string","themeConfig?: { default: string; custom?: Record<string, unknown> }","art: ArtFileInfo","variantComponentName: string","variantName: string","artFiles: Map<string, ArtFileInfo>","componentImportPath: string | undefined","componentName: string | undefined","outDir: string","str: string","propsOverride: Record<string, unknown>","variant: ArtVariant"],"sources":["../src/style-dictionary.ts","../src/index.ts"],"sourcesContent":["/**\n * Style Dictionary integration for Musea.\n * Generates design token documentation from Style Dictionary format.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Design token value.\n */\nexport interface DesignToken {\n value: string | number;\n type?: string;\n description?: string;\n attributes?: Record<string, unknown>;\n}\n\n/**\n * Token category (e.g., colors, spacing, typography).\n */\nexport interface TokenCategory {\n name: string;\n tokens: Record<string, DesignToken>;\n subcategories?: TokenCategory[];\n}\n\n/**\n * Style Dictionary output format.\n */\nexport interface StyleDictionaryOutput {\n categories: TokenCategory[];\n metadata: {\n name: string;\n version?: string;\n generatedAt: string;\n };\n}\n\n/**\n * Configuration for Style Dictionary integration.\n */\nexport interface StyleDictionaryConfig {\n /**\n * Path to tokens JSON/JS file or directory.\n */\n tokensPath: string;\n\n /**\n * Output format for documentation.\n * @default 'html'\n */\n outputFormat?: \"html\" | \"json\" | \"markdown\";\n\n /**\n * Output directory for generated documentation.\n * @default '.vize/tokens'\n */\n outputDir?: string;\n\n /**\n * Custom token transformations.\n */\n transforms?: TokenTransform[];\n}\n\n/**\n * Token transformation function.\n */\nexport type TokenTransform = (token: DesignToken, path: string[]) => DesignToken;\n\n/**\n * Parse Style Dictionary tokens file.\n */\nexport async function parseTokens(tokensPath: string): Promise<TokenCategory[]> {\n const absolutePath = path.resolve(tokensPath);\n const stat = await fs.promises.stat(absolutePath);\n\n if (stat.isDirectory()) {\n return parseTokenDirectory(absolutePath);\n }\n\n const content = await fs.promises.readFile(absolutePath, \"utf-8\");\n const tokens = JSON.parse(content);\n return flattenTokens(tokens);\n}\n\n/**\n * Parse tokens from a directory.\n */\nasync function parseTokenDirectory(dirPath: string): Promise<TokenCategory[]> {\n const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });\n const categories: TokenCategory[] = [];\n\n for (const entry of entries) {\n if (entry.isFile() && (entry.name.endsWith(\".json\") || entry.name.endsWith(\".tokens.json\"))) {\n const filePath = path.join(dirPath, entry.name);\n const content = await fs.promises.readFile(filePath, \"utf-8\");\n const tokens = JSON.parse(content);\n const categoryName = path\n .basename(entry.name, path.extname(entry.name))\n .replace(\".tokens\", \"\");\n\n categories.push({\n name: formatCategoryName(categoryName),\n tokens: extractTokens(tokens),\n subcategories: extractSubcategories(tokens),\n });\n }\n }\n\n return categories;\n}\n\n/**\n * Flatten nested token structure into categories.\n */\nfunction flattenTokens(tokens: Record<string, unknown>, prefix: string[] = []): TokenCategory[] {\n const categories: TokenCategory[] = [];\n\n for (const [key, value] of Object.entries(tokens)) {\n if (isTokenValue(value)) {\n // This is a token leaf node\n continue;\n }\n\n if (typeof value === \"object\" && value !== null) {\n const categoryTokens = extractTokens(value as Record<string, unknown>);\n const subcategories = flattenTokens(value as Record<string, unknown>, [...prefix, key]);\n\n if (Object.keys(categoryTokens).length > 0 || subcategories.length > 0) {\n categories.push({\n name: formatCategoryName(key),\n tokens: categoryTokens,\n subcategories: subcategories.length > 0 ? subcategories : undefined,\n });\n }\n }\n }\n\n return categories;\n}\n\n/**\n * Extract token values from an object.\n */\nfunction extractTokens(obj: Record<string, unknown>): Record<string, DesignToken> {\n const tokens: Record<string, DesignToken> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (isTokenValue(value)) {\n tokens[key] = normalizeToken(value as Record<string, unknown>);\n }\n }\n\n return tokens;\n}\n\n/**\n * Extract subcategories from an object.\n */\nfunction extractSubcategories(obj: Record<string, unknown>): TokenCategory[] | undefined {\n const subcategories: TokenCategory[] = [];\n\n for (const [key, value] of Object.entries(obj)) {\n if (!isTokenValue(value) && typeof value === \"object\" && value !== null) {\n const categoryTokens = extractTokens(value as Record<string, unknown>);\n const nested = extractSubcategories(value as Record<string, unknown>);\n\n if (Object.keys(categoryTokens).length > 0 || (nested && nested.length > 0)) {\n subcategories.push({\n name: formatCategoryName(key),\n tokens: categoryTokens,\n subcategories: nested,\n });\n }\n }\n }\n\n return subcategories.length > 0 ? subcategories : undefined;\n}\n\n/**\n * Check if a value is a token definition.\n */\nfunction isTokenValue(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n return \"value\" in obj && (typeof obj.value === \"string\" || typeof obj.value === \"number\");\n}\n\n/**\n * Normalize token to DesignToken interface.\n */\nfunction normalizeToken(raw: Record<string, unknown>): DesignToken {\n return {\n value: raw.value as string | number,\n type: raw.type as string | undefined,\n description: raw.description as string | undefined,\n attributes: raw.attributes as Record<string, unknown> | undefined,\n };\n}\n\n/**\n * Format category name for display.\n */\nfunction formatCategoryName(name: string): string {\n return name\n .replace(/[-_]/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\" \");\n}\n\n/**\n * Generate HTML documentation for tokens.\n */\nexport function generateTokensHtml(categories: TokenCategory[]): string {\n const renderToken = (name: string, token: DesignToken): string => {\n const isColor =\n typeof token.value === \"string\" &&\n (token.value.startsWith(\"#\") ||\n token.value.startsWith(\"rgb\") ||\n token.value.startsWith(\"hsl\") ||\n token.type === \"color\");\n\n return `\n <div class=\"token\">\n <div class=\"token-preview\">\n ${isColor ? `<div class=\"color-swatch\" style=\"background: ${token.value}\"></div>` : \"\"}\n </div>\n <div class=\"token-info\">\n <div class=\"token-name\">${name}</div>\n <div class=\"token-value\">${token.value}</div>\n ${token.description ? `<div class=\"token-description\">${token.description}</div>` : \"\"}\n </div>\n </div>\n `;\n };\n\n const renderCategory = (category: TokenCategory, level: number = 2): string => {\n const heading = `h${Math.min(level, 6)}`;\n let html = `<${heading}>${category.name}</${heading}>`;\n html += '<div class=\"tokens-grid\">';\n\n for (const [name, token] of Object.entries(category.tokens)) {\n html += renderToken(name, token);\n }\n\n html += \"</div>\";\n\n if (category.subcategories) {\n for (const sub of category.subcategories) {\n html += renderCategory(sub, level + 1);\n }\n }\n\n return html;\n };\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Design Tokens - Musea</title>\n <style>\n :root {\n --musea-bg: #0d0d0d;\n --musea-bg-secondary: #1a1815;\n --musea-text: #e6e9f0;\n --musea-text-muted: #7b8494;\n --musea-accent: #a34828;\n --musea-border: #3a3530;\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: 'Inter', -apple-system, sans-serif;\n background: var(--musea-bg);\n color: var(--musea-text);\n line-height: 1.6;\n padding: 2rem;\n }\n h1 { margin-bottom: 2rem; color: var(--musea-accent); }\n h2 { margin: 2rem 0 1rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--musea-border); }\n h3, h4, h5, h6 { margin: 1.5rem 0 0.75rem; }\n .tokens-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 1rem;\n margin-bottom: 1.5rem;\n }\n .token {\n background: var(--musea-bg-secondary);\n border: 1px solid var(--musea-border);\n border-radius: 8px;\n padding: 1rem;\n display: flex;\n gap: 1rem;\n align-items: center;\n }\n .token-preview {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .color-swatch {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n border: 1px solid var(--musea-border);\n }\n .token-info {\n flex: 1;\n min-width: 0;\n }\n .token-name {\n font-weight: 600;\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.875rem;\n }\n .token-value {\n color: var(--musea-text-muted);\n font-family: 'JetBrains Mono', monospace;\n font-size: 0.75rem;\n word-break: break-all;\n }\n .token-description {\n color: var(--musea-text-muted);\n font-size: 0.75rem;\n margin-top: 0.25rem;\n }\n </style>\n</head>\n<body>\n <h1>Design Tokens</h1>\n ${categories.map((cat) => renderCategory(cat)).join(\"\")}\n</body>\n</html>`;\n}\n\n/**\n * Generate Markdown documentation for tokens.\n */\nexport function generateTokensMarkdown(categories: TokenCategory[]): string {\n const renderCategory = (category: TokenCategory, level: number = 2): string => {\n const heading = \"#\".repeat(level);\n let md = `\\n${heading} ${category.name}\\n\\n`;\n\n if (Object.keys(category.tokens).length > 0) {\n md += \"| Token | Value | Description |\\n\";\n md += \"|-------|-------|-------------|\\n\";\n\n for (const [name, token] of Object.entries(category.tokens)) {\n const desc = token.description || \"-\";\n md += `| \\`${name}\\` | \\`${token.value}\\` | ${desc} |\\n`;\n }\n md += \"\\n\";\n }\n\n if (category.subcategories) {\n for (const sub of category.subcategories) {\n md += renderCategory(sub, level + 1);\n }\n }\n\n return md;\n };\n\n let markdown = \"# Design Tokens\\n\\n\";\n markdown += `> Generated by Musea on ${new Date().toISOString()}\\n`;\n\n for (const category of categories) {\n markdown += renderCategory(category);\n }\n\n return markdown;\n}\n\n/**\n * Style Dictionary plugin for Musea.\n */\nexport async function processStyleDictionary(\n config: StyleDictionaryConfig,\n): Promise<StyleDictionaryOutput> {\n const categories = await parseTokens(config.tokensPath);\n const outputDir = config.outputDir ?? \".vize/tokens\";\n const outputFormat = config.outputFormat ?? \"html\";\n\n // Ensure output directory exists\n await fs.promises.mkdir(outputDir, { recursive: true });\n\n // Generate documentation\n let content: string;\n let filename: string;\n\n switch (outputFormat) {\n case \"html\":\n content = generateTokensHtml(categories);\n filename = \"tokens.html\";\n break;\n case \"markdown\":\n content = generateTokensMarkdown(categories);\n filename = \"tokens.md\";\n break;\n case \"json\":\n default:\n content = JSON.stringify({ categories }, null, 2);\n filename = \"tokens.json\";\n }\n\n const outputPath = path.join(outputDir, filename);\n await fs.promises.writeFile(outputPath, content, \"utf-8\");\n\n console.log(`[musea] Generated token documentation: ${outputPath}`);\n\n return {\n categories,\n metadata: {\n name: path.basename(config.tokensPath),\n generatedAt: new Date().toISOString(),\n },\n };\n}\n\nexport default processStyleDictionary;\n","/**\n * Vite plugin for Musea - Component gallery for Vue components.\n *\n * @example\n * ```ts\n * import { defineConfig } from 'vite';\n * import { vize } from '@vizejs/vite-plugin';\n * import { musea } from '@vizejs/vite-plugin-musea';\n *\n * export default defineConfig({\n * plugins: [vize(), musea()],\n * });\n * ```\n */\n\nimport type { Plugin, ViteDevServer, ResolvedConfig } from \"vite\";\nimport { createRequire } from \"node:module\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { vizeConfigStore } from \"@vizejs/vite-plugin\";\n\nimport type {\n MuseaOptions,\n MuseaTheme,\n MuseaThemeColors,\n ArtFileInfo,\n ArtMetadata,\n ArtVariant,\n CsfOutput,\n PaletteApiResponse,\n AnalysisApiResponse,\n A11yOptions,\n A11yResult,\n CaptureConfig,\n ComparisonConfig,\n CiConfig,\n} from \"./types.js\";\n\nexport type {\n MuseaOptions,\n MuseaTheme,\n MuseaThemeColors,\n ArtFileInfo,\n ArtMetadata,\n ArtVariant,\n CsfOutput,\n VrtOptions,\n ViewportConfig,\n PaletteApiResponse,\n AnalysisApiResponse,\n A11yOptions,\n A11yResult,\n CaptureConfig,\n ComparisonConfig,\n CiConfig,\n} from \"./types.js\";\n\nexport {\n MuseaVrtRunner,\n generateVrtReport,\n generateVrtJsonReport,\n type VrtResult,\n type VrtSummary,\n} from \"./vrt.js\";\n\nimport {\n processStyleDictionary,\n parseTokens,\n generateTokensHtml,\n generateTokensMarkdown,\n type DesignToken,\n type TokenCategory,\n type StyleDictionaryConfig,\n type StyleDictionaryOutput,\n} from \"./style-dictionary.js\";\n\nexport {\n processStyleDictionary,\n parseTokens,\n generateTokensHtml,\n generateTokensMarkdown,\n type DesignToken,\n type TokenCategory,\n type StyleDictionaryConfig,\n type StyleDictionaryOutput,\n};\n\nexport { MuseaA11yRunner, type A11ySummary } from \"./a11y.js\";\n\nexport {\n generateArtFile,\n writeArtFile,\n type AutogenOptions,\n type AutogenOutput,\n type PropDefinition,\n type GeneratedVariant,\n} from \"./autogen.js\";\n\n// Virtual module prefixes\nconst VIRTUAL_MUSEA_PREFIX = \"\\0musea:\";\nconst VIRTUAL_GALLERY = \"\\0musea-gallery\";\nconst VIRTUAL_MANIFEST = \"\\0musea-manifest\";\n\n// Native binding types\ninterface NativeBinding {\n parseArt: (\n source: string,\n options?: { filename?: string },\n ) => {\n filename: string;\n metadata: {\n title: string;\n description?: string;\n component?: string;\n category?: string;\n tags: string[];\n status: string;\n order?: number;\n };\n variants: Array<{\n name: string;\n template: string;\n is_default: boolean;\n skip_vrt: boolean;\n }>;\n has_script_setup: boolean;\n has_script: boolean;\n style_count: number;\n };\n artToCsf: (\n source: string,\n options?: { filename?: string },\n ) => {\n code: string;\n filename: string;\n };\n generateArtPalette?: (\n source: string,\n artOptions?: { filename?: string },\n paletteOptions?: { infer_options?: boolean; group_by_type?: boolean },\n ) => {\n title: string;\n controls: Array<{\n name: string;\n control: string;\n default_value?: unknown;\n description?: string;\n required: boolean;\n options: Array<{ label: string; value: unknown }>;\n range?: { min: number; max: number; step?: number };\n group?: string;\n }>;\n groups: string[];\n json: string;\n typescript: string;\n };\n generateArtDoc?: (\n source: string,\n artOptions?: { filename?: string },\n docOptions?: {\n include_source?: boolean;\n include_templates?: boolean;\n include_metadata?: boolean;\n },\n ) => {\n markdown: string;\n filename: string;\n title: string;\n category?: string;\n variant_count: number;\n };\n analyzeSfc?: (\n source: string,\n options?: { filename?: string },\n ) => {\n props: Array<{ name: string; type: string; required: boolean; default_value?: unknown }>;\n emits: string[];\n };\n}\n\n// Lazy-load native binding\nlet native: NativeBinding | null = null;\n\nfunction loadNative(): NativeBinding {\n if (native) return native;\n\n const require = createRequire(import.meta.url);\n try {\n native = require(\"@vizejs/native\") as NativeBinding;\n return native;\n } catch (e) {\n throw new Error(\n `Failed to load @vizejs/native. Make sure it's installed and built:\\n${String(e)}`,\n );\n }\n}\n\n/**\n * Build the theme config object from plugin options for runtime injection.\n */\nfunction buildThemeConfig(\n theme?: MuseaOptions[\"theme\"],\n): { default: string; custom?: Record<string, { base?: \"dark\" | \"light\"; colors: Record<string, string> }> } | undefined {\n if (!theme) return undefined;\n\n if (typeof theme === \"string\") {\n // 'dark' | 'light' | 'system'\n return { default: theme };\n }\n\n // Single custom theme or array of custom themes\n const themes = Array.isArray(theme) ? theme : [theme];\n const custom: Record<string, { base?: \"dark\" | \"light\"; colors: Record<string, string> }> = {};\n for (const t of themes) {\n custom[t.name] = {\n base: t.base,\n colors: t.colors as Record<string, string>,\n };\n }\n return {\n default: themes[0].name,\n custom,\n };\n}\n\n/**\n * Create Musea Vite plugin.\n */\nexport function musea(options: MuseaOptions = {}): Plugin[] {\n let include = options.include ?? [\"**/*.art.vue\"];\n let exclude = options.exclude ?? [\"node_modules/**\", \"dist/**\"];\n let basePath = options.basePath ?? \"/__musea__\";\n let storybookCompat = options.storybookCompat ?? false;\n const storybookOutDir = options.storybookOutDir ?? \".storybook/stories\";\n let inlineArt = options.inlineArt ?? false;\n const tokensPath = options.tokensPath;\n const themeConfig = buildThemeConfig(options.theme);\n\n let config: ResolvedConfig;\n let server: ViteDevServer | null = null;\n const artFiles = new Map<string, ArtFileInfo>();\n\n // Main plugin\n const mainPlugin: Plugin = {\n name: \"vite-plugin-musea\",\n enforce: \"pre\",\n\n config() {\n // Add Vue alias for runtime template compilation\n // This is needed because variant templates are compiled at runtime\n return {\n resolve: {\n alias: {\n vue: \"vue/dist/vue.esm-bundler.js\",\n },\n },\n };\n },\n\n configResolved(resolvedConfig) {\n config = resolvedConfig;\n\n // Merge musea config from vize.config.ts (plugin args > config file > defaults)\n const vizeConfig = vizeConfigStore.get(resolvedConfig.root);\n if (vizeConfig?.musea) {\n const mc = vizeConfig.musea;\n // Only apply config file values when plugin options were not explicitly set\n if (!options.include && mc.include) include = mc.include;\n if (!options.exclude && mc.exclude) exclude = mc.exclude;\n if (!options.basePath && mc.basePath) basePath = mc.basePath;\n if (options.storybookCompat === undefined && mc.storybookCompat !== undefined)\n storybookCompat = mc.storybookCompat;\n if (options.inlineArt === undefined && mc.inlineArt !== undefined) inlineArt = mc.inlineArt;\n }\n },\n\n configureServer(devServer) {\n server = devServer;\n\n // Gallery SPA route - serves built SPA or falls back to inline HTML\n devServer.middlewares.use(basePath, async (req, res, next) => {\n const url = req.url || \"/\";\n\n // Serve SPA for gallery routes (not /api/, /preview, /preview-module, /art)\n if (\n url === \"/\" ||\n url === \"/index.html\" ||\n url.startsWith(\"/tokens\") ||\n url.startsWith(\"/component/\")\n ) {\n // Try serving built SPA first\n const galleryDistDir = path.resolve(\n path.dirname(new URL(import.meta.url).pathname),\n \"gallery\",\n );\n const indexHtmlPath = path.join(galleryDistDir, \"index.html\");\n\n try {\n await fs.promises.access(indexHtmlPath);\n let html = await fs.promises.readFile(indexHtmlPath, \"utf-8\");\n // Inject basePath and theme config for runtime use\n const themeScript = themeConfig\n ? `window.__MUSEA_THEME_CONFIG__=${JSON.stringify(themeConfig)};`\n : \"\";\n html = html.replace(\n \"</head>\",\n `<script>window.__MUSEA_BASE_PATH__='${basePath}';${themeScript}</script></head>`,\n );\n // Transform through Vite for HMR\n html = await devServer.transformIndexHtml(basePath + url, html);\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(html);\n return;\n } catch {\n // Fall back to inline gallery HTML\n const html = generateGalleryHtml(basePath, themeConfig);\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(html);\n return;\n }\n }\n // Serve gallery static assets (JS, CSS) from built SPA\n if (url.startsWith(\"/assets/\")) {\n const galleryDistDir = path.resolve(\n path.dirname(new URL(import.meta.url).pathname),\n \"gallery\",\n );\n const filePath = path.join(galleryDistDir, url);\n try {\n const stat = await fs.promises.stat(filePath);\n if (stat.isFile()) {\n const content = await fs.promises.readFile(filePath);\n const ext = path.extname(filePath);\n const mimeTypes: Record<string, string> = {\n \".js\": \"application/javascript\",\n \".css\": \"text/css\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n \".woff\": \"font/woff\",\n };\n res.setHeader(\"Content-Type\", mimeTypes[ext] || \"application/octet-stream\");\n res.setHeader(\"Cache-Control\", \"public, max-age=31536000, immutable\");\n res.end(content);\n return;\n }\n } catch {\n // File not found, fall through\n }\n }\n\n next();\n });\n\n // Preview module route - serves the JavaScript module for a specific variant\n devServer.middlewares.use(`${basePath}/preview-module`, async (req, res, _next) => {\n const url = new URL(req.url || \"\", `http://localhost`);\n const artPath = url.searchParams.get(\"art\");\n const variantName = url.searchParams.get(\"variant\");\n\n if (!artPath || !variantName) {\n res.statusCode = 400;\n res.end(\"Missing art or variant parameter\");\n return;\n }\n\n const art = artFiles.get(artPath);\n if (!art) {\n res.statusCode = 404;\n res.end(\"Art not found\");\n return;\n }\n\n const variant = art.variants.find((v) => v.name === variantName);\n if (!variant) {\n res.statusCode = 404;\n res.end(\"Variant not found\");\n return;\n }\n\n const variantComponentName = toPascalCase(variant.name);\n const moduleCode = generatePreviewModule(art, variantComponentName, variant.name);\n\n // Transform the module through Vite to resolve imports\n try {\n const result = await devServer.transformRequest(\n `virtual:musea-preview:${artPath}:${variantName}`,\n );\n if (result) {\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.end(result.code);\n return;\n }\n } catch {\n // Fall through to manual response\n }\n\n // Fallback: serve the module directly (imports won't be resolved)\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.end(moduleCode);\n });\n\n // VRT preview route - renders a single variant for screenshot\n devServer.middlewares.use(`${basePath}/preview`, async (req, res, _next) => {\n const url = new URL(req.url || \"\", `http://localhost`);\n const artPath = url.searchParams.get(\"art\");\n const variantName = url.searchParams.get(\"variant\");\n\n if (!artPath || !variantName) {\n res.statusCode = 400;\n res.end(\"Missing art or variant parameter\");\n return;\n }\n\n const art = artFiles.get(artPath);\n if (!art) {\n res.statusCode = 404;\n res.end(\"Art not found\");\n return;\n }\n\n const variant = art.variants.find((v) => v.name === variantName);\n if (!variant) {\n res.statusCode = 404;\n res.end(\"Variant not found\");\n return;\n }\n\n const rawHtml = generatePreviewHtml(art, variant, basePath);\n // Transform HTML through Vite to properly resolve module imports\n const html = await devServer.transformIndexHtml(\n `${basePath}/preview?art=${encodeURIComponent(artPath)}&variant=${encodeURIComponent(variantName)}`,\n rawHtml,\n );\n res.setHeader(\"Content-Type\", \"text/html\");\n res.end(html);\n });\n\n // Art module route - serves transformed art file as ES module\n devServer.middlewares.use(`${basePath}/art`, async (req, res, next) => {\n const url = new URL(req.url || \"\", \"http://localhost\");\n const artPath = decodeURIComponent(url.pathname.slice(1)); // Remove leading /\n\n if (!artPath) {\n next();\n return;\n }\n\n const art = artFiles.get(artPath);\n if (!art) {\n res.statusCode = 404;\n res.end(\"Art not found: \" + artPath);\n return;\n }\n\n // Transform through Vite for proper imports\n try {\n const virtualId = `virtual:musea-art:${artPath}`;\n const result = await devServer.transformRequest(virtualId);\n if (result) {\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.end(result.code);\n } else {\n // Fallback: generate and serve the module directly\n const moduleCode = generateArtModule(art, artPath);\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.end(moduleCode);\n }\n } catch (err) {\n console.error(\"[musea] Failed to transform art module:\", err);\n // Fallback if transform fails\n const moduleCode = generateArtModule(art, artPath);\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.end(moduleCode);\n }\n });\n\n // API endpoints\n devServer.middlewares.use(`${basePath}/api`, async (req, res, next) => {\n const sendJson = (data: unknown, status = 200) => {\n res.statusCode = status;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify(data));\n };\n\n const sendError = (message: string, status = 500) => {\n sendJson({ error: message }, status);\n };\n\n // GET /api/arts - List all arts\n if (req.url === \"/arts\" && req.method === \"GET\") {\n sendJson(Array.from(artFiles.values()));\n return;\n }\n\n // GET /api/tokens - Get design tokens\n if (req.url === \"/tokens\" && req.method === \"GET\") {\n if (!tokensPath) {\n sendJson({ categories: [] });\n return;\n }\n\n try {\n const absoluteTokensPath = path.resolve(config.root, tokensPath);\n const categories = await parseTokens(absoluteTokensPath);\n sendJson({ categories });\n } catch (e) {\n console.error(\"[musea] Failed to load tokens:\", e);\n sendJson({ categories: [], error: String(e) });\n }\n return;\n }\n\n // Arts sub-routes: /api/arts/:encodedPath/...\n if (req.url?.startsWith(\"/arts/\") && req.method === \"GET\") {\n const rest = req.url.slice(6); // after \"/arts/\"\n\n // Check for sub-resource patterns\n const paletteMatch = rest.match(/^(.+)\\/palette$/);\n const analysisMatch = rest.match(/^(.+)\\/analysis$/);\n const docsMatch = rest.match(/^(.+)\\/docs$/);\n const a11yMatch = rest.match(/^(.+)\\/variants\\/([^/]+)\\/a11y$/);\n\n if (paletteMatch) {\n // GET /api/arts/:path/palette\n const artPath = decodeURIComponent(paletteMatch[1]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n try {\n const source = await fs.promises.readFile(artPath, \"utf-8\");\n const binding = loadNative();\n if (binding.generateArtPalette) {\n const palette = binding.generateArtPalette(source, { filename: artPath });\n sendJson(palette);\n } else {\n sendJson({\n title: art.metadata.title,\n controls: [],\n groups: [],\n json: \"{}\",\n typescript: \"\",\n });\n }\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n return;\n }\n\n if (analysisMatch) {\n // GET /api/arts/:path/analysis\n const artPath = decodeURIComponent(analysisMatch[1]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n try {\n // Determine the component file path: inline art uses the file itself, .art.vue uses the component attribute\n const resolvedComponentPath =\n art.isInline && art.componentPath\n ? art.componentPath\n : art.metadata.component\n ? path.isAbsolute(art.metadata.component)\n ? art.metadata.component\n : path.resolve(path.dirname(artPath), art.metadata.component)\n : null;\n\n if (resolvedComponentPath) {\n const source = await fs.promises.readFile(resolvedComponentPath, \"utf-8\");\n const binding = loadNative();\n if (binding.analyzeSfc) {\n const analysis = binding.analyzeSfc(source, { filename: resolvedComponentPath });\n sendJson(analysis);\n } else {\n sendJson({ props: [], emits: [] });\n }\n } else {\n sendJson({ props: [], emits: [] });\n }\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n return;\n }\n\n if (docsMatch) {\n // GET /api/arts/:path/docs\n const artPath = decodeURIComponent(docsMatch[1]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n try {\n const source = await fs.promises.readFile(artPath, \"utf-8\");\n const binding = loadNative();\n if (binding.generateArtDoc) {\n const doc = binding.generateArtDoc(source, { filename: artPath });\n // Replace Self with component name and format indentation\n let markdown = doc.markdown || \"\";\n const componentName = art.metadata.title || \"Component\";\n markdown = markdown\n .replace(/<Self(\\s|>|\\/)/g, `<${componentName}$1`)\n .replace(/<\\/Self>/g, `</${componentName}>`);\n // Fix indentation in code blocks\n markdown = markdown.replace(/```(\\w*)\\n([\\s\\S]*?)```/g, (_match, lang, code) => {\n const lines = code.split(\"\\n\");\n // Find minimum indentation (excluding empty lines)\n let minIndent = Infinity;\n for (const line of lines) {\n if (line.trim()) {\n const indent = line.match(/^(\\s*)/)?.[1].length || 0;\n minIndent = Math.min(minIndent, indent);\n }\n }\n if (minIndent === Infinity) minIndent = 0;\n // Remove minimum indentation from all lines\n const formatted = lines.map((line) => line.slice(minIndent)).join(\"\\n\");\n return \"```\" + lang + \"\\n\" + formatted + \"```\";\n });\n sendJson({ ...doc, markdown });\n } else {\n sendJson({\n markdown: \"\",\n title: art.metadata.title,\n variant_count: art.variants.length,\n });\n }\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n return;\n }\n\n if (a11yMatch) {\n // GET /api/arts/:path/variants/:name/a11y\n const artPath = decodeURIComponent(a11yMatch[1]);\n const _variantName = decodeURIComponent(a11yMatch[2]);\n const art = artFiles.get(artPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n // Return empty a11y results (populated after VRT --a11y run)\n sendJson({ violations: [], passes: 0, incomplete: 0 });\n return;\n }\n\n // GET /api/arts/:path - Get single art (no sub-resource)\n const artPath = decodeURIComponent(rest);\n const art = artFiles.get(artPath);\n if (art) {\n sendJson(art);\n } else {\n sendError(\"Art not found\", 404);\n }\n return;\n }\n\n // POST /api/preview-with-props\n if (req.url === \"/preview-with-props\" && req.method === \"POST\") {\n let body = \"\";\n req.on(\"data\", (chunk) => {\n body += chunk;\n });\n req.on(\"end\", () => {\n try {\n const { artPath: reqArtPath, variantName, props: propsOverride } = JSON.parse(body);\n const art = artFiles.get(reqArtPath);\n if (!art) {\n sendError(\"Art not found\", 404);\n return;\n }\n\n const variant = art.variants.find((v) => v.name === variantName);\n if (!variant) {\n sendError(\"Variant not found\", 404);\n return;\n }\n\n // Generate preview module with props override\n const variantComponentName = toPascalCase(variant.name);\n const moduleCode = generatePreviewModuleWithProps(\n art,\n variantComponentName,\n variant.name,\n propsOverride,\n );\n res.setHeader(\"Content-Type\", \"application/javascript\");\n res.end(moduleCode);\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n });\n return;\n }\n\n // POST /api/generate\n if (req.url === \"/generate\" && req.method === \"POST\") {\n let body = \"\";\n req.on(\"data\", (chunk) => {\n body += chunk;\n });\n req.on(\"end\", async () => {\n try {\n const { componentPath: reqComponentPath, options: autogenOptions } = JSON.parse(body);\n const { generateArtFile: genArt } = await import(\"./autogen.js\");\n const result = await genArt(reqComponentPath, autogenOptions);\n sendJson({\n generated: true,\n componentName: result.componentName,\n variants: result.variants,\n artFileContent: result.artFileContent,\n });\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n });\n return;\n }\n\n // POST /api/run-vrt - Run VRT for a specific art file or all\n if (req.url === \"/run-vrt\" && req.method === \"POST\") {\n let body = \"\";\n req.on(\"data\", (chunk) => {\n body += chunk;\n });\n req.on(\"end\", async () => {\n try {\n const { artPath, updateSnapshots } = JSON.parse(body);\n const { MuseaVrtRunner } = await import(\"./vrt.js\");\n\n const runner = new MuseaVrtRunner({\n snapshotDir: path.resolve(config.root, \".vize/snapshots\"),\n });\n\n const port = devServer.config.server.port || 5173;\n const baseUrl = `http://localhost:${port}`;\n\n // Get arts to test\n let artsToTest = Array.from(artFiles.values());\n if (artPath) {\n artsToTest = artsToTest.filter((a) => a.path === artPath);\n }\n\n await runner.start();\n const results = await runner.runTests(artsToTest, baseUrl, { updateSnapshots });\n const summary = runner.getSummary(results);\n await runner.stop();\n\n sendJson({\n success: true,\n summary,\n results: results.map((r) => ({\n artPath: r.artPath,\n variantName: r.variantName,\n viewport: r.viewport.name,\n passed: r.passed,\n isNew: r.isNew,\n diffPercentage: r.diffPercentage,\n error: r.error,\n })),\n });\n } catch (e) {\n sendError(e instanceof Error ? e.message : String(e));\n }\n });\n return;\n }\n\n next();\n });\n\n // Watch for Art file changes\n devServer.watcher.on(\"change\", async (file) => {\n if (file.endsWith(\".art.vue\") && shouldProcess(file, include, exclude, config.root)) {\n await processArtFile(file);\n console.log(`[musea] Reloaded: ${path.relative(config.root, file)}`);\n }\n // Inline art: re-check .vue files on change\n if (inlineArt && file.endsWith(\".vue\") && !file.endsWith(\".art.vue\")) {\n const hadArt = artFiles.has(file);\n const source = await fs.promises.readFile(file, \"utf-8\");\n if (source.includes(\"<art\")) {\n await processArtFile(file);\n console.log(`[musea] Reloaded inline art: ${path.relative(config.root, file)}`);\n } else if (hadArt) {\n artFiles.delete(file);\n console.log(`[musea] Removed inline art: ${path.relative(config.root, file)}`);\n }\n }\n });\n\n devServer.watcher.on(\"add\", async (file) => {\n if (file.endsWith(\".art.vue\") && shouldProcess(file, include, exclude, config.root)) {\n await processArtFile(file);\n console.log(`[musea] Added: ${path.relative(config.root, file)}`);\n }\n // Inline art: check new .vue files\n if (inlineArt && file.endsWith(\".vue\") && !file.endsWith(\".art.vue\")) {\n const source = await fs.promises.readFile(file, \"utf-8\");\n if (source.includes(\"<art\")) {\n await processArtFile(file);\n console.log(`[musea] Added inline art: ${path.relative(config.root, file)}`);\n }\n }\n });\n\n devServer.watcher.on(\"unlink\", (file) => {\n if (artFiles.has(file)) {\n artFiles.delete(file);\n console.log(`[musea] Removed: ${path.relative(config.root, file)}`);\n }\n });\n\n // Print Musea gallery URL after server starts\n return () => {\n devServer.httpServer?.once(\"listening\", () => {\n const address = devServer.httpServer?.address();\n if (address && typeof address === \"object\") {\n const protocol = devServer.config.server.https ? \"https\" : \"http\";\n const rawHost = address.address;\n // Normalize IPv6/IPv4 localhost addresses to \"localhost\"\n const host =\n rawHost === \"::\" ||\n rawHost === \"::1\" ||\n rawHost === \"0.0.0.0\" ||\n rawHost === \"127.0.0.1\"\n ? \"localhost\"\n : rawHost;\n const port = address.port;\n const url = `${protocol}://${host}:${port}${basePath}`;\n\n console.log();\n console.log(` \\x1b[36m➜\\x1b[0m \\x1b[1mMusea Gallery:\\x1b[0m \\x1b[36m${url}\\x1b[0m`);\n }\n });\n };\n },\n\n async buildStart() {\n // Scan for Art files\n const files = await scanArtFiles(config.root, include, exclude, inlineArt);\n\n console.log(`[musea] Found ${files.length} art files`);\n\n for (const file of files) {\n await processArtFile(file);\n }\n\n // Generate Storybook CSF if enabled\n if (storybookCompat) {\n await generateStorybookFiles(artFiles, config.root, storybookOutDir);\n }\n },\n\n resolveId(id) {\n if (id === VIRTUAL_GALLERY) {\n return VIRTUAL_GALLERY;\n }\n if (id === VIRTUAL_MANIFEST) {\n return VIRTUAL_MANIFEST;\n }\n // Handle virtual:musea-preview: prefix for preview modules\n if (id.startsWith(\"virtual:musea-preview:\")) {\n return \"\\0musea-preview:\" + id.slice(\"virtual:musea-preview:\".length);\n }\n // Handle virtual:musea-art: prefix for preview modules\n if (id.startsWith(\"virtual:musea-art:\")) {\n const artPath = id.slice(\"virtual:musea-art:\".length);\n if (artFiles.has(artPath)) {\n return \"\\0musea-art:\" + artPath;\n }\n }\n if (id.endsWith(\".art.vue\")) {\n const resolved = path.resolve(config.root, id);\n if (artFiles.has(resolved)) {\n return VIRTUAL_MUSEA_PREFIX + resolved;\n }\n }\n // Inline art: resolve .vue files that have <art> blocks\n if (inlineArt && id.endsWith(\".vue\") && !id.endsWith(\".art.vue\")) {\n const resolved = path.resolve(config.root, id);\n if (artFiles.has(resolved)) {\n return VIRTUAL_MUSEA_PREFIX + resolved;\n }\n }\n return null;\n },\n\n load(id) {\n if (id === VIRTUAL_GALLERY) {\n return generateGalleryModule(basePath);\n }\n if (id === VIRTUAL_MANIFEST) {\n return generateManifestModule(artFiles);\n }\n // Handle \\0musea-preview: prefix for preview modules\n if (id.startsWith(\"\\0musea-preview:\")) {\n const rest = id.slice(\"\\0musea-preview:\".length);\n const lastColonIndex = rest.lastIndexOf(\":\");\n if (lastColonIndex !== -1) {\n const artPath = rest.slice(0, lastColonIndex);\n const variantName = rest.slice(lastColonIndex + 1);\n const art = artFiles.get(artPath);\n if (art) {\n const variantComponentName = toPascalCase(variantName);\n return generatePreviewModule(art, variantComponentName, variantName);\n }\n }\n }\n // Handle \\0musea-art: prefix for preview modules\n if (id.startsWith(\"\\0musea-art:\")) {\n const artPath = id.slice(\"\\0musea-art:\".length);\n const art = artFiles.get(artPath);\n if (art) {\n return generateArtModule(art, artPath);\n }\n }\n if (id.startsWith(VIRTUAL_MUSEA_PREFIX)) {\n const realPath = id.slice(VIRTUAL_MUSEA_PREFIX.length);\n const art = artFiles.get(realPath);\n if (art) {\n return generateArtModule(art, realPath);\n }\n }\n return null;\n },\n\n async handleHotUpdate(ctx) {\n const { file } = ctx;\n if (file.endsWith(\".art.vue\") && artFiles.has(file)) {\n await processArtFile(file);\n\n // Invalidate virtual modules\n const virtualId = VIRTUAL_MUSEA_PREFIX + file;\n const modules = server?.moduleGraph.getModulesByFile(virtualId);\n if (modules) {\n return [...modules];\n }\n }\n\n // Inline art: HMR for .vue files with <art> blocks\n if (inlineArt && file.endsWith(\".vue\") && !file.endsWith(\".art.vue\") && artFiles.has(file)) {\n await processArtFile(file);\n\n const virtualId = VIRTUAL_MUSEA_PREFIX + file;\n const modules = server?.moduleGraph.getModulesByFile(virtualId);\n if (modules) {\n return [...modules];\n }\n }\n\n return undefined;\n },\n };\n\n // Helper functions scoped to this plugin instance\n\n async function processArtFile(filePath: string): Promise<void> {\n try {\n const source = await fs.promises.readFile(filePath, \"utf-8\");\n const binding = loadNative();\n const parsed = binding.parseArt(source, { filename: filePath });\n\n // Skip files with no variants (e.g. .vue files without <art> block)\n if (!parsed.variants || parsed.variants.length === 0) return;\n\n const isInline = !filePath.endsWith(\".art.vue\");\n\n const info: ArtFileInfo = {\n path: filePath,\n metadata: {\n title: parsed.metadata.title || (isInline ? path.basename(filePath, \".vue\") : \"\"),\n description: parsed.metadata.description,\n component: isInline ? undefined : parsed.metadata.component,\n category: parsed.metadata.category,\n tags: parsed.metadata.tags,\n status: parsed.metadata.status as \"draft\" | \"ready\" | \"deprecated\",\n order: parsed.metadata.order,\n },\n variants: parsed.variants.map((v) => ({\n name: v.name,\n template: v.template,\n isDefault: v.is_default,\n skipVrt: v.skip_vrt,\n })),\n hasScriptSetup: parsed.has_script_setup,\n hasScript: parsed.has_script,\n styleCount: parsed.style_count,\n isInline,\n componentPath: isInline ? filePath : undefined,\n };\n\n artFiles.set(filePath, info);\n } catch (e) {\n console.error(`[musea] Failed to process ${filePath}:`, e);\n }\n }\n\n return [mainPlugin];\n}\n\n// Utility functions\n\nfunction shouldProcess(file: string, include: string[], exclude: string[], root: string): boolean {\n const relative = path.relative(root, file);\n\n // Check exclude patterns\n for (const pattern of exclude) {\n if (matchGlob(relative, pattern)) {\n return false;\n }\n }\n\n // Check include patterns\n for (const pattern of include) {\n if (matchGlob(relative, pattern)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction matchGlob(filepath: string, pattern: string): boolean {\n // Simple glob matching (supports * and **)\n // Escape . first, then replace glob patterns\n const regex = pattern\n .replace(/\\./g, \"\\\\.\")\n .replace(/\\*\\*/g, \".*\")\n .replace(/\\*(?!\\*)/g, \"[^/]*\");\n\n return new RegExp(`^${regex}$`).test(filepath);\n}\n\nasync function scanArtFiles(\n root: string,\n include: string[],\n exclude: string[],\n scanInlineArt = false,\n): Promise<string[]> {\n const files: string[] = [];\n\n async function scan(dir: string): Promise<void> {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n const relative = path.relative(root, fullPath);\n\n // Check exclude\n let excluded = false;\n for (const pattern of exclude) {\n if (matchGlob(relative, pattern) || matchGlob(entry.name, pattern)) {\n excluded = true;\n break;\n }\n }\n\n if (excluded) continue;\n\n if (entry.isDirectory()) {\n await scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith(\".art.vue\")) {\n // Check include\n for (const pattern of include) {\n if (matchGlob(relative, pattern)) {\n files.push(fullPath);\n break;\n }\n }\n } else if (\n scanInlineArt &&\n entry.isFile() &&\n entry.name.endsWith(\".vue\") &&\n !entry.name.endsWith(\".art.vue\")\n ) {\n // Inline art: check if .vue file contains <art block\n const content = await fs.promises.readFile(fullPath, \"utf-8\");\n if (content.includes(\"<art\")) {\n files.push(fullPath);\n }\n }\n }\n }\n\n await scan(root);\n return files;\n}\n\nfunction generateGalleryHtml(basePath: string, themeConfig?: { default: string; custom?: Record<string, unknown> }): string {\n const themeScript = themeConfig\n ? `window.__MUSEA_THEME_CONFIG__=${JSON.stringify(themeConfig)};`\n : \"\";\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Musea - Component Gallery</title>\n <script>window.__MUSEA_BASE_PATH__='${basePath}';${themeScript}${\"<\"}/script>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n <style>\n :root {\n --musea-bg-primary: #0d0d0d;\n --musea-bg-secondary: #1a1815;\n --musea-bg-tertiary: #252220;\n --musea-bg-elevated: #2d2a27;\n --musea-accent: #a34828;\n --musea-accent-hover: #c45a32;\n --musea-accent-subtle: rgba(163, 72, 40, 0.15);\n --musea-text: #e6e9f0;\n --musea-text-secondary: #c4c9d4;\n --musea-text-muted: #7b8494;\n --musea-border: #3a3530;\n --musea-border-subtle: #2a2725;\n --musea-success: #4ade80;\n --musea-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);\n --musea-radius-sm: 6px;\n --musea-radius-md: 8px;\n --musea-radius-lg: 12px;\n --musea-transition: 0.15s ease;\n }\n\n * { box-sizing: border-box; margin: 0; padding: 0; }\n\n body {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n background: var(--musea-bg-primary);\n color: var(--musea-text);\n min-height: 100vh;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n }\n\n /* Header */\n .header {\n background: var(--musea-bg-secondary);\n border-bottom: 1px solid var(--musea-border);\n padding: 0 1.5rem;\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n position: sticky;\n top: 0;\n z-index: 100;\n }\n\n .header-left {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n }\n\n .logo {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 1.125rem;\n font-weight: 700;\n color: var(--musea-accent);\n text-decoration: none;\n }\n\n .logo-svg {\n width: 32px;\n height: 32px;\n flex-shrink: 0;\n }\n\n .logo-icon svg {\n width: 16px;\n height: 16px;\n color: white;\n }\n\n .header-subtitle {\n color: var(--musea-text-muted);\n font-size: 0.8125rem;\n font-weight: 500;\n padding-left: 1.5rem;\n border-left: 1px solid var(--musea-border);\n }\n\n .search-container {\n position: relative;\n width: 280px;\n }\n\n .search-input {\n width: 100%;\n background: var(--musea-bg-tertiary);\n border: 1px solid var(--musea-border);\n border-radius: var(--musea-radius-md);\n padding: 0.5rem 0.75rem 0.5rem 2.25rem;\n color: var(--musea-text);\n font-size: 0.8125rem;\n outline: none;\n transition: border-color var(--musea-transition), background var(--musea-transition);\n }\n\n .search-input::placeholder {\n color: var(--musea-text-muted);\n }\n\n .search-input:focus {\n border-color: var(--musea-accent);\n background: var(--musea-bg-elevated);\n }\n\n .search-icon {\n position: absolute;\n left: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--musea-text-muted);\n pointer-events: none;\n }\n\n /* Layout */\n .main {\n display: grid;\n grid-template-columns: 260px 1fr;\n min-height: calc(100vh - 56px);\n }\n\n /* Sidebar */\n .sidebar {\n background: var(--musea-bg-secondary);\n border-right: 1px solid var(--musea-border);\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n .sidebar::-webkit-scrollbar {\n width: 6px;\n }\n\n .sidebar::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .sidebar::-webkit-scrollbar-thumb {\n background: var(--musea-border);\n border-radius: 3px;\n }\n\n .sidebar-section {\n padding: 0.75rem;\n }\n\n .category-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.625rem 0.75rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--musea-text-muted);\n cursor: pointer;\n user-select: none;\n border-radius: var(--musea-radius-sm);\n transition: background var(--musea-transition);\n }\n\n .category-header:hover {\n background: var(--musea-bg-tertiary);\n }\n\n .category-icon {\n width: 16px;\n height: 16px;\n transition: transform var(--musea-transition);\n }\n\n .category-header.collapsed .category-icon {\n transform: rotate(-90deg);\n }\n\n .category-count {\n margin-left: auto;\n background: var(--musea-bg-tertiary);\n padding: 0.125rem 0.375rem;\n border-radius: 4px;\n font-size: 0.625rem;\n }\n\n .art-list {\n list-style: none;\n margin-top: 0.25rem;\n }\n\n .art-item {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n padding: 0.5rem 0.75rem 0.5rem 1.75rem;\n border-radius: var(--musea-radius-sm);\n cursor: pointer;\n font-size: 0.8125rem;\n color: var(--musea-text-secondary);\n transition: all var(--musea-transition);\n position: relative;\n }\n\n .art-item::before {\n content: '';\n position: absolute;\n left: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--musea-border);\n transition: background var(--musea-transition);\n }\n\n .art-item:hover {\n background: var(--musea-bg-tertiary);\n color: var(--musea-text);\n }\n\n .art-item:hover::before {\n background: var(--musea-text-muted);\n }\n\n .art-item.active {\n background: var(--musea-accent-subtle);\n color: var(--musea-accent-hover);\n }\n\n .art-item.active::before {\n background: var(--musea-accent);\n }\n\n .art-variant-count {\n margin-left: auto;\n font-size: 0.6875rem;\n color: var(--musea-text-muted);\n opacity: 0;\n transition: opacity var(--musea-transition);\n }\n\n .art-item:hover .art-variant-count {\n opacity: 1;\n }\n\n /* Content */\n .content {\n background: var(--musea-bg-primary);\n overflow-y: auto;\n }\n\n .content-inner {\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n }\n\n .content-header {\n margin-bottom: 2rem;\n }\n\n .content-title {\n font-size: 1.5rem;\n font-weight: 700;\n margin-bottom: 0.5rem;\n }\n\n .content-description {\n color: var(--musea-text-muted);\n font-size: 0.9375rem;\n max-width: 600px;\n }\n\n .content-meta {\n display: flex;\n align-items: center;\n gap: 1rem;\n margin-top: 1rem;\n }\n\n .meta-tag {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.625rem;\n background: var(--musea-bg-secondary);\n border: 1px solid var(--musea-border);\n border-radius: var(--musea-radius-sm);\n font-size: 0.75rem;\n color: var(--musea-text-muted);\n }\n\n .meta-tag svg {\n width: 12px;\n height: 12px;\n }\n\n /* Gallery Grid */\n .gallery {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 1.25rem;\n }\n\n /* Variant Card */\n .variant-card {\n background: var(--musea-bg-secondary);\n border: 1px solid var(--musea-border);\n border-radius: var(--musea-radius-lg);\n overflow: hidden;\n transition: all var(--musea-transition);\n }\n\n .variant-card:hover {\n border-color: var(--musea-text-muted);\n box-shadow: var(--musea-shadow);\n transform: translateY(-2px);\n }\n\n .variant-preview {\n aspect-ratio: 16 / 10;\n background: var(--musea-bg-tertiary);\n display: flex;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n }\n\n .variant-preview iframe {\n width: 100%;\n height: 100%;\n border: none;\n background: white;\n }\n\n .variant-preview-placeholder {\n color: var(--musea-text-muted);\n font-size: 0.8125rem;\n text-align: center;\n padding: 1rem;\n }\n\n .variant-preview-code {\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 0.75rem;\n color: var(--musea-text-muted);\n background: var(--musea-bg-primary);\n padding: 1rem;\n overflow: auto;\n max-height: 100%;\n width: 100%;\n }\n\n .variant-info {\n padding: 1rem;\n border-top: 1px solid var(--musea-border);\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .variant-name {\n font-weight: 600;\n font-size: 0.875rem;\n }\n\n .variant-badge {\n font-size: 0.625rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n padding: 0.1875rem 0.5rem;\n border-radius: 4px;\n background: var(--musea-accent-subtle);\n color: var(--musea-accent);\n }\n\n .variant-actions {\n display: flex;\n gap: 0.5rem;\n }\n\n .variant-action-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: var(--musea-bg-tertiary);\n border-radius: var(--musea-radius-sm);\n color: var(--musea-text-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all var(--musea-transition);\n }\n\n .variant-action-btn:hover {\n background: var(--musea-bg-elevated);\n color: var(--musea-text);\n }\n\n .variant-action-btn svg {\n width: 14px;\n height: 14px;\n }\n\n /* Empty State */\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 400px;\n text-align: center;\n padding: 2rem;\n }\n\n .empty-state-icon {\n width: 80px;\n height: 80px;\n background: var(--musea-bg-secondary);\n border-radius: var(--musea-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 1.5rem;\n }\n\n .empty-state-icon svg {\n width: 40px;\n height: 40px;\n color: var(--musea-text-muted);\n }\n\n .empty-state-title {\n font-size: 1.125rem;\n font-weight: 600;\n margin-bottom: 0.5rem;\n }\n\n .empty-state-text {\n color: var(--musea-text-muted);\n font-size: 0.875rem;\n max-width: 300px;\n }\n\n /* Loading */\n .loading {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n color: var(--musea-text-muted);\n gap: 0.75rem;\n }\n\n .loading-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid var(--musea-border);\n border-top-color: var(--musea-accent);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .main {\n grid-template-columns: 1fr;\n }\n .sidebar {\n display: none;\n }\n .header-subtitle {\n display: none;\n }\n }\n </style>\n</head>\n<body>\n <header class=\"header\">\n <div class=\"header-left\">\n <a href=\"${basePath}\" class=\"logo\">\n <svg class=\"logo-svg\" width=\"32\" height=\"32\" viewBox=\"0 0 200 200\" fill=\"none\">\n <defs>\n <linearGradient id=\"metal-grad\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"20%\">\n <stop offset=\"0%\" stop-color=\"#f0f2f5\"/>\n <stop offset=\"50%\" stop-color=\"#9ca3b0\"/>\n <stop offset=\"100%\" stop-color=\"#e07048\"/>\n </linearGradient>\n <linearGradient id=\"metal-grad-dark\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"30%\">\n <stop offset=\"0%\" stop-color=\"#d0d4dc\"/>\n <stop offset=\"60%\" stop-color=\"#6b7280\"/>\n <stop offset=\"100%\" stop-color=\"#c45530\"/>\n </linearGradient>\n </defs>\n <g transform=\"translate(40, 40)\">\n <g transform=\"skewX(-12)\">\n <path d=\"M 100 0 L 60 120 L 105 30 L 100 0 Z\" fill=\"url(#metal-grad-dark)\" stroke=\"#4b5563\" stroke-width=\"0.5\"/>\n <path d=\"M 30 0 L 60 120 L 80 20 L 30 0 Z\" fill=\"url(#metal-grad)\" stroke-width=\"0.5\" stroke-opacity=\"0.4\"/>\n </g>\n </g>\n <g transform=\"translate(110, 120)\">\n <line x1=\"5\" y1=\"10\" x2=\"5\" y2=\"50\" stroke=\"#e07048\" stroke-width=\"3\" stroke-linecap=\"round\"/>\n <line x1=\"60\" y1=\"10\" x2=\"60\" y2=\"50\" stroke=\"#e07048\" stroke-width=\"3\" stroke-linecap=\"round\"/>\n <path d=\"M 0 10 L 32.5 0 L 65 10\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <rect x=\"15\" y=\"18\" width=\"14\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"1.5\" opacity=\"0.7\"/>\n <rect x=\"36\" y=\"18\" width=\"14\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"1.5\" opacity=\"0.7\"/>\n <rect x=\"23\" y=\"35\" width=\"18\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"#e07048\" stroke-width=\"1.5\" opacity=\"0.6\"/>\n </g>\n </svg>\n Musea\n </a>\n <span class=\"header-subtitle\">Component Gallery</span>\n </div>\n <div class=\"search-container\">\n <svg class=\"search-icon\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"m21 21-4.35-4.35\"/>\n </svg>\n <input type=\"text\" class=\"search-input\" placeholder=\"Search components...\" id=\"search\">\n </div>\n </header>\n\n <main class=\"main\">\n <aside class=\"sidebar\" id=\"sidebar\">\n <div class=\"loading\">\n <div class=\"loading-spinner\"></div>\n Loading...\n </div>\n </aside>\n <section class=\"content\" id=\"content\">\n <div class=\"empty-state\">\n <div class=\"empty-state-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M4 5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5Z\"/>\n <path d=\"M4 13a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-6Z\"/>\n <path d=\"M16 13a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6Z\"/>\n </svg>\n </div>\n <div class=\"empty-state-title\">Select a component</div>\n <div class=\"empty-state-text\">Choose a component from the sidebar to view its variants and documentation</div>\n </div>\n </section>\n </main>\n\n <script type=\"module\">\n const basePath = '${basePath}';\n let arts = [];\n let selectedArt = null;\n let searchQuery = '';\n\n async function loadArts() {\n try {\n const res = await fetch(basePath + '/api/arts');\n arts = await res.json();\n renderSidebar();\n } catch (e) {\n console.error('Failed to load arts:', e);\n document.getElementById('sidebar').innerHTML = '<div class=\"loading\">Failed to load</div>';\n }\n }\n\n function renderSidebar() {\n const sidebar = document.getElementById('sidebar');\n const categories = {};\n\n const filtered = searchQuery\n ? arts.filter(a => a.metadata.title.toLowerCase().includes(searchQuery.toLowerCase()))\n : arts;\n\n for (const art of filtered) {\n const cat = art.metadata.category || 'Components';\n if (!categories[cat]) categories[cat] = [];\n categories[cat].push(art);\n }\n\n if (Object.keys(categories).length === 0) {\n sidebar.innerHTML = '<div class=\"sidebar-section\"><div class=\"loading\">No components found</div></div>';\n return;\n }\n\n let html = '';\n for (const [category, items] of Object.entries(categories)) {\n html += '<div class=\"sidebar-section\">';\n html += '<div class=\"category-header\" data-category=\"' + category + '\">';\n html += '<svg class=\"category-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"m9 18 6-6-6-6\"/></svg>';\n html += '<span>' + category + '</span>';\n html += '<span class=\"category-count\">' + items.length + '</span>';\n html += '</div>';\n html += '<ul class=\"art-list\" data-category=\"' + category + '\">';\n for (const art of items) {\n const active = selectedArt?.path === art.path ? 'active' : '';\n const variantCount = art.variants?.length || 0;\n html += '<li class=\"art-item ' + active + '\" data-path=\"' + art.path + '\">';\n html += '<span>' + escapeHtml(art.metadata.title) + '</span>';\n html += '<span class=\"art-variant-count\">' + variantCount + ' variant' + (variantCount !== 1 ? 's' : '') + '</span>';\n html += '</li>';\n }\n html += '</ul>';\n html += '</div>';\n }\n\n sidebar.innerHTML = html;\n\n sidebar.querySelectorAll('.art-item').forEach(item => {\n item.addEventListener('click', () => {\n const artPath = item.dataset.path;\n selectedArt = arts.find(a => a.path === artPath);\n renderSidebar();\n renderContent();\n });\n });\n\n sidebar.querySelectorAll('.category-header').forEach(header => {\n header.addEventListener('click', () => {\n header.classList.toggle('collapsed');\n const list = sidebar.querySelector('.art-list[data-category=\"' + header.dataset.category + '\"]');\n if (list) list.style.display = header.classList.contains('collapsed') ? 'none' : 'block';\n });\n });\n }\n\n function renderContent() {\n const content = document.getElementById('content');\n if (!selectedArt) {\n content.innerHTML = \\`\n <div class=\"empty-state\">\n <div class=\"empty-state-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M4 5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5Z\"/>\n <path d=\"M4 13a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-6Z\"/>\n <path d=\"M16 13a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-6Z\"/>\n </svg>\n </div>\n <div class=\"empty-state-title\">Select a component</div>\n <div class=\"empty-state-text\">Choose a component from the sidebar to view its variants</div>\n </div>\n \\`;\n return;\n }\n\n const meta = selectedArt.metadata;\n const tags = meta.tags || [];\n const variantCount = selectedArt.variants?.length || 0;\n\n let html = '<div class=\"content-inner\">';\n html += '<div class=\"content-header\">';\n html += '<h1 class=\"content-title\">' + escapeHtml(meta.title) + '</h1>';\n if (meta.description) {\n html += '<p class=\"content-description\">' + escapeHtml(meta.description) + '</p>';\n }\n html += '<div class=\"content-meta\">';\n html += '<span class=\"meta-tag\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"/><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"/><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"/></svg>' + variantCount + ' variant' + (variantCount !== 1 ? 's' : '') + '</span>';\n if (meta.category) {\n html += '<span class=\"meta-tag\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\"/></svg>' + escapeHtml(meta.category) + '</span>';\n }\n for (const tag of tags) {\n html += '<span class=\"meta-tag\">#' + escapeHtml(tag) + '</span>';\n }\n html += '</div>';\n html += '</div>';\n\n html += '<div class=\"gallery\">';\n for (const variant of selectedArt.variants) {\n const previewUrl = basePath + '/preview?art=' + encodeURIComponent(selectedArt.path) + '&variant=' + encodeURIComponent(variant.name);\n\n html += '<div class=\"variant-card\">';\n html += '<div class=\"variant-preview\">';\n html += '<iframe src=\"' + previewUrl + '\" loading=\"lazy\" title=\"' + escapeHtml(variant.name) + '\"></iframe>';\n html += '</div>';\n html += '<div class=\"variant-info\">';\n html += '<div>';\n html += '<span class=\"variant-name\">' + escapeHtml(variant.name) + '</span>';\n if (variant.isDefault) html += ' <span class=\"variant-badge\">Default</span>';\n html += '</div>';\n html += '<div class=\"variant-actions\">';\n html += '<button class=\"variant-action-btn\" title=\"Open in new tab\" onclick=\"window.open(\\\\'' + previewUrl + '\\\\', \\\\'_blank\\\\')\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/><polyline points=\"15 3 21 3 21 9\"/><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"/></svg></button>';\n html += '</div>';\n html += '</div>';\n html += '</div>';\n }\n html += '</div>';\n html += '</div>';\n\n content.innerHTML = html;\n }\n\n function escapeHtml(str) {\n if (!str) return '';\n return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n }\n\n // Search\n document.getElementById('search').addEventListener('input', (e) => {\n searchQuery = e.target.value;\n renderSidebar();\n });\n\n // Keyboard shortcut for search\n document.addEventListener('keydown', (e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n e.preventDefault();\n document.getElementById('search').focus();\n }\n });\n\n loadArts();\n </script>\n</body>\n</html>`;\n}\n\nfunction generateGalleryModule(basePath: string): string {\n return `\nexport const basePath = '${basePath}';\nexport async function loadArts() {\n const res = await fetch(basePath + '/api/arts');\n return res.json();\n}\n`;\n}\n\n// Addon initialization code injected into preview iframe modules.\n// Shared between generatePreviewModule and generatePreviewModuleWithProps.\nconst MUSEA_ADDONS_INIT_CODE = `\nfunction __museaInitAddons(container, variantName) {\n // === DOM event capture ===\n // Note: mousemove, mouseenter, mouseleave, pointermove are excluded as they are too noisy\n const CAPTURE_EVENTS = ['click','dblclick','input','change','submit','focus','blur','keydown','keyup','mousedown','mouseup','wheel','contextmenu','pointerdown','pointerup'];\n for (const evt of CAPTURE_EVENTS) {\n container.addEventListener(evt, (e) => {\n // Extract raw event properties\n const rawEvent = {\n type: e.type,\n bubbles: e.bubbles,\n cancelable: e.cancelable,\n composed: e.composed,\n defaultPrevented: e.defaultPrevented,\n eventPhase: e.eventPhase,\n isTrusted: e.isTrusted,\n timeStamp: e.timeStamp,\n };\n // Mouse/Pointer event properties\n if ('clientX' in e) {\n rawEvent.clientX = e.clientX;\n rawEvent.clientY = e.clientY;\n rawEvent.screenX = e.screenX;\n rawEvent.screenY = e.screenY;\n rawEvent.pageX = e.pageX;\n rawEvent.pageY = e.pageY;\n rawEvent.offsetX = e.offsetX;\n rawEvent.offsetY = e.offsetY;\n rawEvent.button = e.button;\n rawEvent.buttons = e.buttons;\n rawEvent.altKey = e.altKey;\n rawEvent.ctrlKey = e.ctrlKey;\n rawEvent.metaKey = e.metaKey;\n rawEvent.shiftKey = e.shiftKey;\n }\n // Keyboard event properties\n if ('key' in e) {\n rawEvent.key = e.key;\n rawEvent.code = e.code;\n rawEvent.repeat = e.repeat;\n rawEvent.altKey = e.altKey;\n rawEvent.ctrlKey = e.ctrlKey;\n rawEvent.metaKey = e.metaKey;\n rawEvent.shiftKey = e.shiftKey;\n }\n // Input event properties\n if ('inputType' in e) {\n rawEvent.inputType = e.inputType;\n rawEvent.data = e.data;\n }\n // Wheel event properties\n if ('deltaX' in e) {\n rawEvent.deltaX = e.deltaX;\n rawEvent.deltaY = e.deltaY;\n rawEvent.deltaZ = e.deltaZ;\n rawEvent.deltaMode = e.deltaMode;\n }\n const payload = {\n name: evt,\n target: e.target?.tagName,\n timestamp: Date.now(),\n source: 'dom',\n rawEvent,\n variantName\n };\n if (e.target && 'value' in e.target) {\n payload.value = e.target.value;\n }\n window.parent.postMessage({ type: 'musea:event', payload }, '*');\n }, true);\n }\n\n // === Message handler for parent commands ===\n let measureActive = false;\n let measureOverlay = null;\n let measureLabel = null;\n\n function toggleStyleById(id, enabled, css) {\n let el = document.getElementById(id);\n if (enabled) {\n if (!el) {\n el = document.createElement('style');\n el.id = id;\n el.textContent = css;\n document.head.appendChild(el);\n }\n } else {\n if (el) el.remove();\n }\n }\n\n function createMeasureOverlay() {\n if (measureOverlay) return;\n measureOverlay = document.createElement('div');\n measureOverlay.id = 'musea-measure-overlay';\n measureOverlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:99999;';\n document.body.appendChild(measureOverlay);\n\n measureLabel = document.createElement('div');\n measureLabel.className = 'musea-measure-label';\n measureLabel.style.cssText = 'position:fixed;background:#333;color:#fff;font-size:11px;padding:2px 6px;border-radius:3px;pointer-events:none;z-index:100000;display:none;';\n document.body.appendChild(measureLabel);\n }\n\n function removeMeasureOverlay() {\n if (measureOverlay) { measureOverlay.remove(); measureOverlay = null; }\n if (measureLabel) { measureLabel.remove(); measureLabel = null; }\n }\n\n function onMeasureMouseMove(e) {\n if (!measureActive || !measureOverlay) return;\n const el = document.elementFromPoint(e.clientX, e.clientY);\n if (!el || el === measureOverlay || el === measureLabel) return;\n\n const rect = el.getBoundingClientRect();\n const cs = getComputedStyle(el);\n const mt = parseFloat(cs.marginTop) || 0;\n const mr = parseFloat(cs.marginRight) || 0;\n const mb = parseFloat(cs.marginBottom) || 0;\n const ml = parseFloat(cs.marginLeft) || 0;\n const bt = parseFloat(cs.borderTopWidth) || 0;\n const br = parseFloat(cs.borderRightWidth) || 0;\n const bb = parseFloat(cs.borderBottomWidth) || 0;\n const blw = parseFloat(cs.borderLeftWidth) || 0;\n const pt = parseFloat(cs.paddingTop) || 0;\n const pr = parseFloat(cs.paddingRight) || 0;\n const pb = parseFloat(cs.paddingBottom) || 0;\n const pl = parseFloat(cs.paddingLeft) || 0;\n\n const cw = rect.width - blw - br - pl - pr;\n const ch = rect.height - bt - bb - pt - pb;\n\n measureOverlay.innerHTML = ''\n // Margin\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + (rect.left - ml) + 'px;top:' + (rect.top - mt) + 'px;'\n + 'width:' + (rect.width + ml + mr) + 'px;height:' + mt + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + (rect.left - ml) + 'px;top:' + (rect.bottom) + 'px;'\n + 'width:' + (rect.width + ml + mr) + 'px;height:' + mb + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + (rect.left - ml) + 'px;top:' + rect.top + 'px;'\n + 'width:' + ml + 'px;height:' + rect.height + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,165,0,0.3);'\n + 'left:' + rect.right + 'px;top:' + rect.top + 'px;'\n + 'width:' + mr + 'px;height:' + rect.height + 'px;\"></div>'\n // Border\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + rect.left + 'px;top:' + rect.top + 'px;'\n + 'width:' + rect.width + 'px;height:' + bt + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + rect.left + 'px;top:' + (rect.bottom - bb) + 'px;'\n + 'width:' + rect.width + 'px;height:' + bb + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + rect.left + 'px;top:' + (rect.top + bt) + 'px;'\n + 'width:' + blw + 'px;height:' + (rect.height - bt - bb) + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(255,255,0,0.3);'\n + 'left:' + (rect.right - br) + 'px;top:' + (rect.top + bt) + 'px;'\n + 'width:' + br + 'px;height:' + (rect.height - bt - bb) + 'px;\"></div>'\n // Padding\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.left + blw) + 'px;top:' + (rect.top + bt) + 'px;'\n + 'width:' + (rect.width - blw - br) + 'px;height:' + pt + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.left + blw) + 'px;top:' + (rect.bottom - bb - pb) + 'px;'\n + 'width:' + (rect.width - blw - br) + 'px;height:' + pb + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.left + blw) + 'px;top:' + (rect.top + bt + pt) + 'px;'\n + 'width:' + pl + 'px;height:' + (rect.height - bt - bb - pt - pb) + 'px;\"></div>'\n + '<div style=\"position:fixed;background:rgba(144,238,144,0.3);'\n + 'left:' + (rect.right - br - pr) + 'px;top:' + (rect.top + bt + pt) + 'px;'\n + 'width:' + pr + 'px;height:' + (rect.height - bt - bb - pt - pb) + 'px;\"></div>'\n // Content\n + '<div style=\"position:fixed;background:rgba(100,149,237,0.3);'\n + 'left:' + (rect.left + blw + pl) + 'px;top:' + (rect.top + bt + pt) + 'px;'\n + 'width:' + cw + 'px;height:' + ch + 'px;\"></div>';\n\n // Label\n measureLabel.textContent = Math.round(rect.width) + ' x ' + Math.round(rect.height);\n measureLabel.style.display = 'block';\n measureLabel.style.left = (rect.right + 8) + 'px';\n measureLabel.style.top = rect.top + 'px';\n }\n\n window.addEventListener('message', (e) => {\n if (!e.data?.type?.startsWith('musea:')) return;\n const { type, payload } = e.data;\n switch (type) {\n case 'musea:set-background': {\n if (payload.pattern === 'checkerboard') {\n document.body.style.background = '';\n document.body.classList.add('musea-bg-checkerboard');\n } else {\n document.body.classList.remove('musea-bg-checkerboard');\n document.body.style.background = payload.color || '';\n }\n break;\n }\n case 'musea:toggle-outline': {\n toggleStyleById('musea-outline', payload.enabled,\n '* { outline: 1px solid rgba(255, 0, 0, 0.3) !important; }');\n break;\n }\n case 'musea:toggle-measure': {\n measureActive = payload.enabled;\n if (measureActive) {\n createMeasureOverlay();\n document.addEventListener('mousemove', onMeasureMouseMove);\n } else {\n document.removeEventListener('mousemove', onMeasureMouseMove);\n removeMeasureOverlay();\n }\n break;\n }\n case 'musea:set-props': {\n // Store props for remount - handled by preview module\n if (window.__museaSetProps) {\n window.__museaSetProps(payload.props || {});\n }\n break;\n }\n case 'musea:set-slots': {\n // Store slots for remount - handled by preview module\n if (window.__museaSetSlots) {\n window.__museaSetSlots(payload.slots || {});\n }\n break;\n }\n case 'musea:run-a11y': {\n // Run axe-core a11y test\n (async () => {\n try {\n // Dynamically load axe-core from CDN if not already loaded\n if (!window.axe) {\n const script = document.createElement('script');\n script.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js';\n script.crossOrigin = 'anonymous';\n await new Promise((resolve, reject) => {\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n }\n // Run axe-core on the .musea-variant container only (not the full document)\n const context = document.querySelector('.musea-variant') || document;\n const results = await window.axe.run(context, {\n // Run all rules without restrictions for comprehensive testing\n resultTypes: ['violations', 'incomplete', 'passes']\n });\n window.parent.postMessage({\n type: 'musea:a11y-result',\n payload: {\n violations: results.violations.map(v => ({\n id: v.id,\n impact: v.impact,\n description: v.description,\n helpUrl: v.helpUrl,\n nodes: v.nodes.map(n => ({\n html: n.html,\n target: n.target,\n failureSummary: n.failureSummary\n }))\n })),\n passes: results.passes.length,\n incomplete: results.incomplete.length\n }\n }, '*');\n } catch (err) {\n window.parent.postMessage({\n type: 'musea:a11y-result',\n payload: {\n error: err instanceof Error ? err.message : String(err),\n violations: [],\n passes: 0,\n incomplete: 0\n }\n }, '*');\n }\n })();\n break;\n }\n }\n });\n\n // Notify parent that iframe is ready\n window.parent.postMessage({ type: 'musea:ready', payload: {} }, '*');\n}\n`;\n\nfunction generatePreviewModule(\n art: ArtFileInfo,\n variantComponentName: string,\n variantName: string,\n): string {\n const artModuleId = `virtual:musea-art:${art.path}`;\n const escapedVariantName = escapeTemplate(variantName);\n\n return `\nimport { createApp, reactive, h } from 'vue';\nimport * as artModule from '${artModuleId}';\n\nconst container = document.getElementById('app');\n\n${MUSEA_ADDONS_INIT_CODE}\n\nlet currentApp = null;\nconst propsOverride = reactive({});\nconst slotsOverride = reactive({ default: '' });\n\nwindow.__museaSetProps = (props) => {\n // Clear old keys\n for (const key of Object.keys(propsOverride)) {\n delete propsOverride[key];\n }\n Object.assign(propsOverride, props);\n};\n\nwindow.__museaSetSlots = (slots) => {\n Object.assign(slotsOverride, slots);\n};\n\nasync function mount() {\n try {\n // Get the specific variant component\n const VariantComponent = artModule['${variantComponentName}'];\n const RawComponent = artModule.__component__;\n\n if (!VariantComponent) {\n throw new Error('Variant component \"${variantComponentName}\" not found in art module');\n }\n\n // Create and mount the app\n const app = createApp(VariantComponent);\n container.innerHTML = '';\n container.className = 'musea-variant';\n app.mount(container);\n currentApp = app;\n\n console.log('[musea-preview] Mounted variant: ${escapedVariantName}');\n __museaInitAddons(container, '${escapedVariantName}');\n\n // Override set-props to remount with raw component + props\n if (RawComponent) {\n window.__museaSetProps = (props) => {\n for (const key of Object.keys(propsOverride)) {\n delete propsOverride[key];\n }\n Object.assign(propsOverride, props);\n remountWithProps(RawComponent);\n };\n window.__museaSetSlots = (slots) => {\n Object.assign(slotsOverride, slots);\n remountWithProps(RawComponent);\n };\n }\n } catch (error) {\n console.error('[musea-preview] Failed to mount:', error);\n container.innerHTML = \\`\n <div class=\"musea-error\">\n <div class=\"musea-error-title\">Failed to render component</div>\n <div>\\${error.message}</div>\n <pre>\\${error.stack || ''}</pre>\n </div>\n \\`;\n }\n}\n\nfunction remountWithProps(Component) {\n if (currentApp) {\n currentApp.unmount();\n }\n const app = createApp({\n setup() {\n return () => {\n const slotFns = {};\n if (slotsOverride.default) {\n slotFns.default = () => h('span', { innerHTML: slotsOverride.default });\n }\n return h('div', { class: 'musea-variant' }, [\n h(Component, { ...propsOverride }, slotFns)\n ]);\n };\n }\n });\n container.innerHTML = '';\n app.mount(container);\n currentApp = app;\n}\n\nmount();\n`;\n}\n\nfunction generateManifestModule(artFiles: Map<string, ArtFileInfo>): string {\n const arts = Array.from(artFiles.values());\n return `export const arts = ${JSON.stringify(arts, null, 2)};`;\n}\n\nfunction generateArtModule(art: ArtFileInfo, filePath: string): string {\n let componentImportPath: string | undefined;\n let componentName: string | undefined;\n\n if (art.isInline && art.componentPath) {\n // Inline art: import the host .vue file itself as the component\n componentImportPath = art.componentPath;\n componentName = path.basename(art.componentPath, \".vue\");\n } else if (art.metadata.component) {\n // Traditional .art.vue: resolve component from the component attribute\n const comp = art.metadata.component;\n componentImportPath = path.isAbsolute(comp) ? comp : path.resolve(path.dirname(filePath), comp);\n componentName = path.basename(comp, \".vue\");\n }\n\n let code = `\n// Auto-generated module for: ${path.basename(filePath)}\nimport { defineComponent, h } from 'vue';\n`;\n\n if (componentImportPath && componentName) {\n code += `import ${componentName} from '${componentImportPath}';\\n`;\n code += `export const __component__ = ${componentName};\\n`;\n }\n\n code += `\nexport const metadata = ${JSON.stringify(art.metadata)};\nexport const variants = ${JSON.stringify(art.variants)};\n`;\n\n // Generate variant components\n for (const variant of art.variants) {\n const variantComponentName = toPascalCase(variant.name);\n\n let template = variant.template;\n\n // Replace <Self> with the actual component name (for inline art)\n if (componentName) {\n template = template\n .replace(/<Self/g, `<${componentName}`)\n .replace(/<\\/Self>/g, `</${componentName}>`);\n }\n\n // Escape the template for use in a JS string\n const escapedTemplate = template\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/`/g, \"\\\\`\")\n .replace(/\\$/g, \"\\\\$\");\n\n // Wrap template with the variant container\n const fullTemplate = `<div class=\"musea-variant\" data-variant=\"${variant.name}\">${escapedTemplate}</div>`;\n\n if (componentName) {\n code += `\nexport const ${variantComponentName} = {\n name: '${variantComponentName}',\n components: { ${componentName} },\n template: \\`${fullTemplate}\\`,\n};\n`;\n } else {\n code += `\nexport const ${variantComponentName} = {\n name: '${variantComponentName}',\n template: \\`${fullTemplate}\\`,\n};\n`;\n }\n }\n\n // Default export\n const defaultVariant = art.variants.find((v) => v.isDefault) || art.variants[0];\n if (defaultVariant) {\n code += `\nexport default ${toPascalCase(defaultVariant.name)};\n`;\n }\n\n return code;\n}\n\nasync function generateStorybookFiles(\n artFiles: Map<string, ArtFileInfo>,\n root: string,\n outDir: string,\n): Promise<void> {\n const binding = loadNative();\n const outputDir = path.resolve(root, outDir);\n\n // Ensure output directory exists\n await fs.promises.mkdir(outputDir, { recursive: true });\n\n for (const [filePath, _art] of artFiles) {\n try {\n const source = await fs.promises.readFile(filePath, \"utf-8\");\n const csf = binding.artToCsf(source, { filename: filePath });\n\n const outputPath = path.join(outputDir, csf.filename);\n await fs.promises.writeFile(outputPath, csf.code, \"utf-8\");\n\n console.log(`[musea] Generated: ${path.relative(root, outputPath)}`);\n } catch (e) {\n console.error(`[musea] Failed to generate CSF for ${filePath}:`, e);\n }\n }\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .split(/[\\s\\-_]+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n\nfunction escapeTemplate(str: string): string {\n return str.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\").replace(/\\n/g, \"\\\\n\");\n}\n\nfunction generatePreviewModuleWithProps(\n art: ArtFileInfo,\n variantComponentName: string,\n variantName: string,\n propsOverride: Record<string, unknown>,\n): string {\n const artModuleId = `virtual:musea-art:${art.path}`;\n const escapedVariantName = escapeTemplate(variantName);\n const propsJson = JSON.stringify(propsOverride);\n\n return `\nimport { createApp, h } from 'vue';\nimport * as artModule from '${artModuleId}';\n\nconst container = document.getElementById('app');\nconst propsOverride = ${propsJson};\n\n${MUSEA_ADDONS_INIT_CODE}\n\nasync function mount() {\n try {\n const VariantComponent = artModule['${variantComponentName}'];\n if (!VariantComponent) {\n throw new Error('Variant component \"${variantComponentName}\" not found');\n }\n\n const WrappedComponent = {\n render() {\n return h(VariantComponent, propsOverride);\n }\n };\n\n const app = createApp(WrappedComponent);\n container.innerHTML = '';\n container.className = 'musea-variant';\n app.mount(container);\n console.log('[musea-preview] Mounted variant: ${escapedVariantName} with props override');\n __museaInitAddons(container, '${escapedVariantName}');\n } catch (error) {\n console.error('[musea-preview] Failed to mount:', error);\n container.innerHTML = '<div class=\"musea-error\"><div class=\"musea-error-title\">Failed to render</div><div>' + error.message + '</div></div>';\n }\n}\n\nmount();\n`;\n}\n\nfunction generatePreviewHtml(art: ArtFileInfo, variant: ArtVariant, basePath: string): string {\n // Create a unique module URL for each variant to avoid caching issues\n const previewModuleUrl = `${basePath}/preview-module?art=${encodeURIComponent(art.path)}&variant=${encodeURIComponent(variant.name)}`;\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(art.metadata.title)} - ${escapeHtml(variant.name)}</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n html, body {\n width: 100%;\n height: 100%;\n }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n }\n .musea-variant {\n padding: 1.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .musea-error {\n color: #dc2626;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n padding: 1rem;\n font-size: 0.875rem;\n max-width: 400px;\n }\n .musea-error-title {\n font-weight: 600;\n margin-bottom: 0.5rem;\n }\n .musea-error pre {\n font-family: monospace;\n font-size: 0.75rem;\n white-space: pre-wrap;\n word-break: break-all;\n margin-top: 0.5rem;\n padding: 0.5rem;\n background: #fff;\n border-radius: 4px;\n }\n .musea-loading {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n color: #6b7280;\n font-size: 0.875rem;\n }\n .musea-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid #e5e7eb;\n border-top-color: #3b82f6;\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n }\n @keyframes spin { to { transform: rotate(360deg); } }\n\n /* Musea Addons: Checkerboard background for transparent mode */\n .musea-bg-checkerboard {\n background-image:\n linear-gradient(45deg, #ccc 25%, transparent 25%),\n linear-gradient(-45deg, #ccc 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, #ccc 75%),\n linear-gradient(-45deg, transparent 75%, #ccc 75%) !important;\n background-size: 20px 20px !important;\n background-position: 0 0, 0 10px, 10px -10px, -10px 0 !important;\n }\n\n /* Musea Addons: Measure label */\n .musea-measure-label {\n position: fixed;\n background: #333;\n color: #fff;\n font-size: 11px;\n padding: 2px 6px;\n border-radius: 3px;\n pointer-events: none;\n z-index: 100000;\n }\n </style>\n</head>\n<body>\n <div id=\"app\" class=\"musea-variant\" data-art=\"${escapeHtml(art.path)}\" data-variant=\"${escapeHtml(variant.name)}\">\n <div class=\"musea-loading\">\n <div class=\"musea-spinner\"></div>\n Loading component...\n </div>\n </div>\n <script type=\"module\" src=\"${previewModuleUrl}\"></script>\n</body>\n</html>`;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nexport default musea;\n"],"mappings":"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"}
|
|
@@ -2,8 +2,43 @@ import { BrowserContext, Page } from "playwright";
|
|
|
2
2
|
|
|
3
3
|
//#region src/types.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* Musea
|
|
5
|
+
* Theme color definitions for Musea gallery UI.
|
|
6
|
+
* All properties are optional — unspecified colors inherit from the `base` built-in theme.
|
|
6
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* Theme color definitions for Musea gallery UI.
|
|
10
|
+
* All properties are optional — unspecified colors inherit from the `base` built-in theme.
|
|
11
|
+
*/
|
|
12
|
+
interface MuseaThemeColors {
|
|
13
|
+
bgPrimary?: string;
|
|
14
|
+
bgSecondary?: string;
|
|
15
|
+
bgTertiary?: string;
|
|
16
|
+
bgElevated?: string;
|
|
17
|
+
accent?: string;
|
|
18
|
+
accentHover?: string;
|
|
19
|
+
accentSubtle?: string;
|
|
20
|
+
text?: string;
|
|
21
|
+
textSecondary?: string;
|
|
22
|
+
textMuted?: string;
|
|
23
|
+
border?: string;
|
|
24
|
+
borderSubtle?: string;
|
|
25
|
+
success?: string;
|
|
26
|
+
error?: string;
|
|
27
|
+
info?: string;
|
|
28
|
+
warning?: string;
|
|
29
|
+
shadow?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Custom theme definition.
|
|
33
|
+
*/
|
|
34
|
+
interface MuseaTheme {
|
|
35
|
+
/** Unique name for this theme. */
|
|
36
|
+
name: string;
|
|
37
|
+
/** Built-in theme to inherit unspecified colors from. @default 'dark' */
|
|
38
|
+
base?: "dark" | "light";
|
|
39
|
+
/** Color overrides. */
|
|
40
|
+
colors: MuseaThemeColors;
|
|
41
|
+
}
|
|
7
42
|
/**
|
|
8
43
|
* Musea plugin options.
|
|
9
44
|
*/
|
|
@@ -44,6 +79,21 @@ interface MuseaOptions {
|
|
|
44
79
|
* VRT (Visual Regression Testing) configuration.
|
|
45
80
|
*/
|
|
46
81
|
vrt?: VrtOptions;
|
|
82
|
+
/**
|
|
83
|
+
* Path to Style Dictionary tokens JSON file or directory.
|
|
84
|
+
* Supports standard Style Dictionary format.
|
|
85
|
+
* @example 'src/tokens.json' or 'src/tokens/'
|
|
86
|
+
*/
|
|
87
|
+
tokensPath?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Gallery theme configuration.
|
|
90
|
+
*
|
|
91
|
+
* - `'dark'` / `'light'` — use a built-in theme (default: `'dark'`)
|
|
92
|
+
* - `'system'` — follow the OS color-scheme preference
|
|
93
|
+
* - `MuseaTheme` — single custom theme (replaces defaults)
|
|
94
|
+
* - `MuseaTheme[]` — multiple custom themes (first is default, user can switch)
|
|
95
|
+
*/
|
|
96
|
+
theme?: "dark" | "light" | "system" | MuseaTheme | MuseaTheme[];
|
|
47
97
|
}
|
|
48
98
|
/**
|
|
49
99
|
* VRT configuration options.
|
|
@@ -385,5 +435,5 @@ declare function generateVrtReport(results: VrtResult[], summary: VrtSummary): s
|
|
|
385
435
|
declare function generateVrtJsonReport(results: VrtResult[], summary: VrtSummary): string;
|
|
386
436
|
|
|
387
437
|
//#endregion
|
|
388
|
-
export { A11yOptions, A11yResult, AnalysisApiResponse, ArtFileInfo, ArtMetadata, ArtVariant, CaptureConfig, CiConfig, ComparisonConfig, CsfOutput, ExtendedVrtOptions, MuseaOptions, MuseaVrtRunner as MuseaVrtRunner$1, PaletteApiResponse, PixelCompareOptions, ViewportConfig, VrtOptions, VrtResult, VrtSummary, generateVrtJsonReport as generateVrtJsonReport$1, generateVrtReport as generateVrtReport$1 };
|
|
389
|
-
//# sourceMappingURL=vrt-
|
|
438
|
+
export { A11yOptions, A11yResult, AnalysisApiResponse, ArtFileInfo, ArtMetadata, ArtVariant, CaptureConfig, CiConfig, ComparisonConfig, CsfOutput, ExtendedVrtOptions, MuseaOptions, MuseaTheme, MuseaThemeColors, MuseaVrtRunner as MuseaVrtRunner$1, PaletteApiResponse, PixelCompareOptions, ViewportConfig, VrtOptions, VrtResult, VrtSummary, generateVrtJsonReport as generateVrtJsonReport$1, generateVrtReport as generateVrtReport$1 };
|
|
439
|
+
//# sourceMappingURL=vrt-m01uFerp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vrt-m01uFerp.d.ts","names":[],"sources":["../src/types.ts","../src/vrt.ts"],"sourcesContent":null,"mappings":"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"}
|
package/dist/vrt.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ExtendedVrtOptions, MuseaVrtRunner$1 as MuseaVrtRunner, PixelCompareOptions, VrtResult, VrtSummary, generateVrtJsonReport$1 as generateVrtJsonReport, generateVrtReport$1 as generateVrtReport } from "./vrt-
|
|
1
|
+
import { ExtendedVrtOptions, MuseaVrtRunner$1 as MuseaVrtRunner, PixelCompareOptions, VrtResult, VrtSummary, generateVrtJsonReport$1 as generateVrtJsonReport, generateVrtReport$1 as generateVrtReport } from "./vrt-m01uFerp.js";
|
|
2
2
|
export { ExtendedVrtOptions, MuseaVrtRunner, PixelCompareOptions, VrtResult, VrtSummary, MuseaVrtRunner as default, generateVrtJsonReport, generateVrtReport };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizejs/vite-plugin-musea",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.83",
|
|
4
4
|
"description": "Vite plugin for Musea - Component gallery for Vue components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,27 +52,29 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"pngjs": "^7.0.0",
|
|
55
|
-
"@vizejs/native": "0.0.1-alpha.
|
|
55
|
+
"@vizejs/native": "0.0.1-alpha.83"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
+
"@mdi/js": "^7.4.47",
|
|
58
59
|
"@types/node": "^22.14.0",
|
|
59
60
|
"@types/pngjs": "^6.0.5",
|
|
60
61
|
"@vitejs/plugin-vue": "^6.0.4",
|
|
61
62
|
"highlight.js": "^11.11.1",
|
|
62
63
|
"marked": "^17.0.1",
|
|
63
64
|
"marked-highlight": "^2.2.3",
|
|
65
|
+
"monaco-editor": "^0.52.0",
|
|
64
66
|
"tsdown": "^0.9.0",
|
|
65
67
|
"typescript": "^5.7.0",
|
|
66
68
|
"vite": "^8.0.0-beta.0",
|
|
67
69
|
"vue": "^3.5.0",
|
|
68
70
|
"vue-router": "^4.5.0",
|
|
69
|
-
"@vizejs/vite-plugin": "0.0.1-alpha.
|
|
71
|
+
"@vizejs/vite-plugin": "0.0.1-alpha.83"
|
|
70
72
|
},
|
|
71
73
|
"peerDependencies": {
|
|
72
74
|
"axe-core": "^4.7.0",
|
|
73
75
|
"playwright": "^1.40.0",
|
|
74
76
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0",
|
|
75
|
-
"@vizejs/vite-plugin": "0.0.1-alpha.
|
|
77
|
+
"@vizejs/vite-plugin": "0.0.1-alpha.83"
|
|
76
78
|
},
|
|
77
79
|
"peerDependenciesMeta": {
|
|
78
80
|
"playwright": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vrt-CC29JrCN.d.ts","names":[],"sources":["../src/types.ts","../src/vrt.ts"],"sourcesContent":null,"mappings":"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"}
|