@vizejs/vite-plugin-musea 0.0.1-alpha.99 → 0.2.0
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-CHcxz6UR.d.ts → a11y-Bvx5TJb8.d.ts} +2 -2
- package/dist/{a11y-CHcxz6UR.d.ts.map → a11y-Bvx5TJb8.d.ts.map} +1 -1
- package/dist/a11y.d.ts +2 -2
- package/dist/gallery/assets/abap-Cry0R76c.js +1 -0
- package/dist/gallery/assets/apex-GS4zZi0I.js +1 -0
- package/dist/gallery/assets/azcli-DMImymmY.js +1 -0
- package/dist/gallery/assets/bat-D6epFECU.js +1 -0
- package/dist/gallery/assets/bicep-7klDZ283.js +2 -0
- package/dist/gallery/assets/cameligo-PvLD8t4t.js +1 -0
- package/dist/gallery/assets/clojure-BTbSGpb3.js +1 -0
- package/dist/gallery/assets/codicon-DCmgc-ay.ttf +0 -0
- package/dist/gallery/assets/coffee-Bhl_9YuJ.js +1 -0
- package/dist/gallery/assets/cpp-CM5j04eT.js +1 -0
- package/dist/gallery/assets/csharp-Dh0Ee7SY.js +1 -0
- package/dist/gallery/assets/csp-CLRC61y6.js +1 -0
- package/dist/gallery/assets/css-B0t_muXd.js +3 -0
- package/dist/gallery/assets/css.worker-Cbw1kvi8.js +88 -0
- package/dist/gallery/assets/cssMode-CJhQ5_ix.js +4 -0
- package/dist/gallery/assets/cypher-C5e5inIh.js +1 -0
- package/dist/gallery/assets/dart-DIK3l8YT.js +1 -0
- package/dist/gallery/assets/dockerfile-D7OAO0hl.js +1 -0
- package/dist/gallery/assets/ecl-CP7nM2KN.js +1 -0
- package/dist/gallery/assets/editor-B55U_qvj.css +1 -0
- package/dist/gallery/assets/editor-F8AxQWwE.css +1 -0
- package/dist/gallery/assets/editor.api-ASE8WyAM.js +644 -0
- package/dist/gallery/assets/editor.main-Cma4vQHs.js +63 -0
- package/dist/gallery/assets/editor.worker-Cs7HTPcl.js +12 -0
- package/dist/gallery/assets/elixir-DNRIIj6-.js +1 -0
- package/dist/gallery/assets/flow9-BC5Cr9X0.js +1 -0
- package/dist/gallery/assets/freemarker2-DBfUbCzr.js +3 -0
- package/dist/gallery/assets/fsharp-52P4yqMh.js +1 -0
- package/dist/gallery/assets/go-yKE3zUfB.js +1 -0
- package/dist/gallery/assets/graphql-D3sNVCLc.js +1 -0
- package/dist/gallery/assets/handlebars-D8J8fxvx.js +1 -0
- package/dist/gallery/assets/hcl-BB7aW7AX.js +1 -0
- package/dist/gallery/assets/html-CV__5YWO.js +1 -0
- package/dist/gallery/assets/html.worker-CYmk49z4.js +495 -0
- package/dist/gallery/assets/htmlMode-Bf6TSizS.js +4 -0
- package/dist/gallery/assets/index-0yy-2NJQ.js +63 -0
- package/dist/gallery/assets/index-DLBj3lpz.css +1 -0
- package/dist/gallery/assets/ini-BdRufzJj.js +1 -0
- package/dist/gallery/assets/java-CeUu-z7Y.js +1 -0
- package/dist/gallery/assets/javascript-Bgcd5n0p.js +1 -0
- package/dist/gallery/assets/json.worker-CWR6J9Qf.js +51 -0
- package/dist/gallery/assets/jsonMode-C3cW8QC6.js +10 -0
- package/dist/gallery/assets/julia-CXu-Fn93.js +1 -0
- package/dist/gallery/assets/kotlin-TwsjxLJ3.js +1 -0
- package/dist/gallery/assets/less-CviwWNG4.js +2 -0
- package/dist/gallery/assets/lexon-BTOivnjP.js +1 -0
- package/dist/gallery/assets/liquid-B-CbADyN.js +1 -0
- package/dist/gallery/assets/lua-6W3WJOvj.js +1 -0
- package/dist/gallery/assets/m3-tlthQ8Fo.js +1 -0
- package/dist/gallery/assets/markdown-CPR4Kr9O.js +1 -0
- package/dist/gallery/assets/mdx-wbp4TmId.js +1 -0
- package/dist/gallery/assets/mips-BfxZbsD8.js +1 -0
- package/dist/gallery/assets/monaco.contribution-xYWKV-A3.js +2 -0
- package/dist/gallery/assets/msdax-eKsr2VtO.js +1 -0
- package/dist/gallery/assets/mysql-D6-LO0bt.js +1 -0
- package/dist/gallery/assets/objective-c-DYtfYpNc.js +1 -0
- package/dist/gallery/assets/pascal-CPGyHbal.js +1 -0
- package/dist/gallery/assets/pascaligo-Dsp_VKxo.js +1 -0
- package/dist/gallery/assets/perl-CUVa2_Cu.js +1 -0
- package/dist/gallery/assets/pgsql-C2nbbU56.js +1 -0
- package/dist/gallery/assets/php-DxX2tlkL.js +1 -0
- package/dist/gallery/assets/pla-D55LHImG.js +1 -0
- package/dist/gallery/assets/postiats-Dw_nWtoT.js +1 -0
- package/dist/gallery/assets/powerquery-BldVOeNZ.js +1 -0
- package/dist/gallery/assets/powershell-fdqyoMut.js +1 -0
- package/dist/gallery/assets/protobuf-C-2cnAYL.js +2 -0
- package/dist/gallery/assets/pug-bDrVOc6m.js +1 -0
- package/dist/gallery/assets/python-DFBsc7m6.js +1 -0
- package/dist/gallery/assets/qsharp-B83Ol6AR.js +1 -0
- package/dist/gallery/assets/r-DAxg6zn-.js +1 -0
- package/dist/gallery/assets/razor-KMe1wwP0.js +1 -0
- package/dist/gallery/assets/redis-BSRYxJDu.js +1 -0
- package/dist/gallery/assets/redshift-BrtVU4Ki.js +1 -0
- package/dist/gallery/assets/restructuredtext-DdU6AjLQ.js +1 -0
- package/dist/gallery/assets/ruby-C-s7ovR-.js +1 -0
- package/dist/gallery/assets/rust-CmSb_pkG.js +1 -0
- package/dist/gallery/assets/sb-Bfo5Ukmr.js +1 -0
- package/dist/gallery/assets/scala-Cx2bkddK.js +1 -0
- package/dist/gallery/assets/scheme-DkT6GPaV.js +1 -0
- package/dist/gallery/assets/scss-DOPngiM2.js +3 -0
- package/dist/gallery/assets/shell-NYt6Xulf.js +1 -0
- package/dist/gallery/assets/solidity-CUiq_T3F.js +1 -0
- package/dist/gallery/assets/sophia-B4sI8Ij-.js +1 -0
- package/dist/gallery/assets/sparql-BNfhekQe.js +1 -0
- package/dist/gallery/assets/sql-Bzn3OZV3.js +1 -0
- package/dist/gallery/assets/st-CV0zI_0P.js +1 -0
- package/dist/gallery/assets/swift-CR3-zK7D.js +1 -0
- package/dist/gallery/assets/systemverilog-BxgPwTIi.js +1 -0
- package/dist/gallery/assets/tcl-BSnnsp36.js +1 -0
- package/dist/gallery/assets/ts.worker-B_5n269U.js +51339 -0
- package/dist/gallery/assets/tsMode-Bh__KITB.js +11 -0
- package/dist/gallery/assets/twig-Bx06vatZ.js +1 -0
- package/dist/gallery/assets/typescript-Dueie-TY.js +1 -0
- package/dist/gallery/assets/typespec-COSap3s7.js +1 -0
- package/dist/gallery/assets/vb-DU0VXhXP.js +1 -0
- package/dist/gallery/assets/wgsl-BegdTer-.js +298 -0
- package/dist/gallery/assets/xml-JPuKTaLo.js +1 -0
- package/dist/gallery/assets/yaml-ChmKv6PR.js +1 -0
- package/dist/gallery/index.html +16 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +328 -112
- package/dist/index.js.map +1 -1
- package/dist/{vrt-m01uFerp.d.ts → vrt-Vb4aqPZE.d.ts} +23 -1
- package/dist/vrt-Vb4aqPZE.d.ts.map +1 -0
- package/dist/vrt.d.ts +1 -1
- package/package.json +4 -5
- package/dist/vrt-m01uFerp.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -86,15 +86,15 @@ function extractSubcategories(obj) {
|
|
|
86
86
|
function isTokenValue(value) {
|
|
87
87
|
if (typeof value !== "object" || value === null) return false;
|
|
88
88
|
const obj = value;
|
|
89
|
-
return "value" in obj && (typeof obj.value === "string" || typeof obj.value === "number");
|
|
89
|
+
return "value" in obj && (typeof obj.value === "string" || typeof obj.value === "number") || "$value" in obj && (typeof obj.$value === "string" || typeof obj.$value === "number");
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
92
|
* Normalize token to DesignToken interface.
|
|
93
93
|
*/
|
|
94
94
|
function normalizeToken(raw) {
|
|
95
95
|
const token = {
|
|
96
|
-
value: raw.value,
|
|
97
|
-
type: raw.type,
|
|
96
|
+
value: raw.value ?? raw.$value,
|
|
97
|
+
type: raw.type ?? raw.$type,
|
|
98
98
|
description: raw.description,
|
|
99
99
|
attributes: raw.attributes
|
|
100
100
|
};
|
|
@@ -549,6 +549,71 @@ function loadNative() {
|
|
|
549
549
|
}
|
|
550
550
|
}
|
|
551
551
|
/**
|
|
552
|
+
* JS-based fallback for SFC analysis when native `analyzeSfc` is not available.
|
|
553
|
+
* Uses regex parsing to extract props and emits from Vue SFC source.
|
|
554
|
+
*/
|
|
555
|
+
function analyzeSfcFallback(source, _options) {
|
|
556
|
+
try {
|
|
557
|
+
const props = [];
|
|
558
|
+
const emits = [];
|
|
559
|
+
const scriptSetupMatch = source.match(/<script\s+[^>]*setup[^>]*>([\s\S]*?)<\/script>/);
|
|
560
|
+
if (!scriptSetupMatch) {
|
|
561
|
+
const scriptMatch = source.match(/<script[^>]*>([\s\S]*?)<\/script>/);
|
|
562
|
+
if (!scriptMatch) return {
|
|
563
|
+
props: [],
|
|
564
|
+
emits: []
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
const scriptContent = scriptSetupMatch?.[1] || "";
|
|
568
|
+
const propsMatch = scriptContent.match(/defineProps\s*<\s*\{([\s\S]*?)\}>\s*\(/);
|
|
569
|
+
const propsMatch2 = scriptContent.match(/defineProps\s*<\s*\{([\s\S]*?)\}>/);
|
|
570
|
+
const propsBody = propsMatch?.[1] || propsMatch2?.[1];
|
|
571
|
+
if (propsBody) {
|
|
572
|
+
const lines = propsBody.split("\n");
|
|
573
|
+
let i = 0;
|
|
574
|
+
while (i < lines.length) {
|
|
575
|
+
const line = lines[i].trim();
|
|
576
|
+
if (line.startsWith("/**") || line.startsWith("*") || line.startsWith("*/")) {
|
|
577
|
+
i++;
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
const propMatch = line.match(/^(\w+)(\?)?:\s*(.+?)(?:;?\s*)$/);
|
|
581
|
+
if (propMatch) {
|
|
582
|
+
const name = propMatch[1];
|
|
583
|
+
const optional = !!propMatch[2];
|
|
584
|
+
let type = propMatch[3].replace(/;$/, "").trim();
|
|
585
|
+
const defaultPattern = new RegExp(`\\b${name}\\s*=\\s*([^,}\\n]+)`);
|
|
586
|
+
const defaultMatch = scriptContent.match(defaultPattern);
|
|
587
|
+
const defaultValue = defaultMatch ? defaultMatch[1].trim() : void 0;
|
|
588
|
+
props.push({
|
|
589
|
+
name,
|
|
590
|
+
type,
|
|
591
|
+
required: !optional && defaultValue === void 0,
|
|
592
|
+
...defaultValue !== void 0 ? { default_value: defaultValue } : {}
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
i++;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const emitsMatch = scriptContent.match(/defineEmits\s*<\s*\{([\s\S]*?)\}>/);
|
|
599
|
+
if (emitsMatch) {
|
|
600
|
+
const emitsBody = emitsMatch[1];
|
|
601
|
+
const emitRegex = /(\w+)\s*:/g;
|
|
602
|
+
let match;
|
|
603
|
+
while ((match = emitRegex.exec(emitsBody)) !== null) emits.push(match[1]);
|
|
604
|
+
}
|
|
605
|
+
return {
|
|
606
|
+
props,
|
|
607
|
+
emits
|
|
608
|
+
};
|
|
609
|
+
} catch {
|
|
610
|
+
return {
|
|
611
|
+
props: [],
|
|
612
|
+
emits: []
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
552
617
|
* Build the theme config object from plugin options for runtime injection.
|
|
553
618
|
*/
|
|
554
619
|
function buildThemeConfig(theme) {
|
|
@@ -577,9 +642,13 @@ function musea(options = {}) {
|
|
|
577
642
|
let inlineArt = options.inlineArt ?? false;
|
|
578
643
|
const tokensPath = options.tokensPath;
|
|
579
644
|
const themeConfig = buildThemeConfig(options.theme);
|
|
645
|
+
const previewCss = options.previewCss ?? [];
|
|
646
|
+
const previewSetup = options.previewSetup;
|
|
580
647
|
let config;
|
|
581
648
|
let server = null;
|
|
582
649
|
const artFiles = new Map();
|
|
650
|
+
let resolvedPreviewCss = [];
|
|
651
|
+
let resolvedPreviewSetup = null;
|
|
583
652
|
const mainPlugin = {
|
|
584
653
|
name: "vite-plugin-musea",
|
|
585
654
|
enforce: "pre",
|
|
@@ -597,12 +666,14 @@ function musea(options = {}) {
|
|
|
597
666
|
if (options.storybookCompat === void 0 && mc.storybookCompat !== void 0) storybookCompat = mc.storybookCompat;
|
|
598
667
|
if (options.inlineArt === void 0 && mc.inlineArt !== void 0) inlineArt = mc.inlineArt;
|
|
599
668
|
}
|
|
669
|
+
resolvedPreviewCss = previewCss.map((cssPath) => path.isAbsolute(cssPath) ? cssPath : path.resolve(resolvedConfig.root, cssPath));
|
|
670
|
+
if (previewSetup) resolvedPreviewSetup = path.isAbsolute(previewSetup) ? previewSetup : path.resolve(resolvedConfig.root, previewSetup);
|
|
600
671
|
},
|
|
601
672
|
configureServer(devServer) {
|
|
602
673
|
server = devServer;
|
|
603
674
|
devServer.middlewares.use(basePath, async (req, res, next) => {
|
|
604
675
|
const url = req.url || "/";
|
|
605
|
-
if (url === "/" || url === "/index.html" || url.startsWith("/tokens") || url.startsWith("/component/")) {
|
|
676
|
+
if (url === "/" || url === "/index.html" || url.startsWith("/tokens") || url.startsWith("/component/") || url.startsWith("/tests")) {
|
|
606
677
|
const galleryDistDir = path.resolve(path.dirname(new URL(import.meta.url).pathname), "gallery");
|
|
607
678
|
const indexHtmlPath = path.join(galleryDistDir, "index.html");
|
|
608
679
|
try {
|
|
@@ -610,7 +681,6 @@ function musea(options = {}) {
|
|
|
610
681
|
let html = await fs.promises.readFile(indexHtmlPath, "utf-8");
|
|
611
682
|
const themeScript = themeConfig ? `window.__MUSEA_THEME_CONFIG__=${JSON.stringify(themeConfig)};` : "";
|
|
612
683
|
html = html.replace("</head>", `<script>window.__MUSEA_BASE_PATH__='${basePath}';${themeScript}</script></head>`);
|
|
613
|
-
html = await devServer.transformIndexHtml(basePath + url, html);
|
|
614
684
|
res.setHeader("Content-Type", "text/html");
|
|
615
685
|
res.end(html);
|
|
616
686
|
return;
|
|
@@ -647,6 +717,19 @@ function musea(options = {}) {
|
|
|
647
717
|
}
|
|
648
718
|
next();
|
|
649
719
|
});
|
|
720
|
+
devServer.middlewares.use(`${basePath}/vendor/axe-core.min.js`, async (_req, res, _next) => {
|
|
721
|
+
try {
|
|
722
|
+
const require = createRequire(import.meta.url);
|
|
723
|
+
const axeCorePath = require.resolve("axe-core/axe.min.js");
|
|
724
|
+
const content = await fs.promises.readFile(axeCorePath, "utf-8");
|
|
725
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
726
|
+
res.setHeader("Cache-Control", "public, max-age=86400");
|
|
727
|
+
res.end(content);
|
|
728
|
+
} catch {
|
|
729
|
+
res.statusCode = 404;
|
|
730
|
+
res.end("axe-core not installed");
|
|
731
|
+
}
|
|
732
|
+
});
|
|
650
733
|
devServer.middlewares.use(`${basePath}/preview-module`, async (req, res, _next) => {
|
|
651
734
|
const url = new URL(req.url || "", `http://localhost`);
|
|
652
735
|
const artPath = url.searchParams.get("art");
|
|
@@ -669,7 +752,7 @@ function musea(options = {}) {
|
|
|
669
752
|
return;
|
|
670
753
|
}
|
|
671
754
|
const variantComponentName = toPascalCase(variant.name);
|
|
672
|
-
const moduleCode = generatePreviewModule(art, variantComponentName, variant.name);
|
|
755
|
+
const moduleCode = generatePreviewModule(art, variantComponentName, variant.name, resolvedPreviewCss, resolvedPreviewSetup);
|
|
673
756
|
try {
|
|
674
757
|
const result = await devServer.transformRequest(`virtual:musea-preview:${artPath}:${variantName}`);
|
|
675
758
|
if (result) {
|
|
@@ -704,8 +787,7 @@ function musea(options = {}) {
|
|
|
704
787
|
res.end("Variant not found");
|
|
705
788
|
return;
|
|
706
789
|
}
|
|
707
|
-
const
|
|
708
|
-
const html = await devServer.transformIndexHtml(`${basePath}/preview?art=${encodeURIComponent(artPath)}&variant=${encodeURIComponent(variantName)}`, rawHtml);
|
|
790
|
+
const html = generatePreviewHtml(art, variant, basePath, config.base);
|
|
709
791
|
res.setHeader("Content-Type", "text/html");
|
|
710
792
|
res.end(html);
|
|
711
793
|
});
|
|
@@ -1021,16 +1103,57 @@ function musea(options = {}) {
|
|
|
1021
1103
|
try {
|
|
1022
1104
|
const source = await fs.promises.readFile(artPath$1, "utf-8");
|
|
1023
1105
|
const binding = loadNative();
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
} else sendJson({
|
|
1106
|
+
let palette;
|
|
1107
|
+
if (binding.generateArtPalette) palette = binding.generateArtPalette(source, { filename: artPath$1 });
|
|
1108
|
+
else palette = {
|
|
1028
1109
|
title: art$1.metadata.title,
|
|
1029
1110
|
controls: [],
|
|
1030
1111
|
groups: [],
|
|
1031
1112
|
json: "{}",
|
|
1032
1113
|
typescript: ""
|
|
1033
|
-
}
|
|
1114
|
+
};
|
|
1115
|
+
if (palette.controls.length === 0 && art$1.metadata.component) {
|
|
1116
|
+
const resolvedComponentPath = path.isAbsolute(art$1.metadata.component) ? art$1.metadata.component : path.resolve(path.dirname(artPath$1), art$1.metadata.component);
|
|
1117
|
+
try {
|
|
1118
|
+
const componentSource = await fs.promises.readFile(resolvedComponentPath, "utf-8");
|
|
1119
|
+
const analysis = binding.analyzeSfc ? binding.analyzeSfc(componentSource, { filename: resolvedComponentPath }) : analyzeSfcFallback(componentSource, { filename: resolvedComponentPath });
|
|
1120
|
+
if (analysis.props.length > 0) {
|
|
1121
|
+
palette.controls = analysis.props.map((prop) => {
|
|
1122
|
+
let control = "text";
|
|
1123
|
+
if (prop.type === "boolean") control = "boolean";
|
|
1124
|
+
else if (prop.type === "number") control = "number";
|
|
1125
|
+
else if (prop.type.includes("|") && !prop.type.includes("=>")) control = "select";
|
|
1126
|
+
const options$1 = [];
|
|
1127
|
+
if (control === "select") {
|
|
1128
|
+
const optionMatches = prop.type.match(/"([^"]+)"/g);
|
|
1129
|
+
if (optionMatches) for (const opt of optionMatches) {
|
|
1130
|
+
const val = opt.replace(/"/g, "");
|
|
1131
|
+
options$1.push({
|
|
1132
|
+
label: val,
|
|
1133
|
+
value: val
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return {
|
|
1138
|
+
name: prop.name,
|
|
1139
|
+
control,
|
|
1140
|
+
default_value: prop.default_value !== void 0 ? prop.default_value === "true" ? true : prop.default_value === "false" ? false : typeof prop.default_value === "string" && prop.default_value.startsWith("\"") ? prop.default_value.replace(/^"|"$/g, "") : prop.default_value : void 0,
|
|
1141
|
+
description: void 0,
|
|
1142
|
+
required: prop.required,
|
|
1143
|
+
options: options$1,
|
|
1144
|
+
range: void 0,
|
|
1145
|
+
group: void 0
|
|
1146
|
+
};
|
|
1147
|
+
});
|
|
1148
|
+
palette.json = JSON.stringify({
|
|
1149
|
+
title: palette.title,
|
|
1150
|
+
controls: palette.controls
|
|
1151
|
+
}, null, 2);
|
|
1152
|
+
palette.typescript = `export interface ${palette.title}Props {\n${palette.controls.map((c) => ` ${c.name}${c.required ? "" : "?"}: ${c.control === "boolean" ? "boolean" : c.control === "number" ? "number" : c.control === "select" ? c.options.map((o) => `"${String(o.value)}"`).join(" | ") : "string"};`).join("\n")}\n}\n`;
|
|
1153
|
+
}
|
|
1154
|
+
} catch {}
|
|
1155
|
+
}
|
|
1156
|
+
sendJson(palette);
|
|
1034
1157
|
} catch (e) {
|
|
1035
1158
|
sendError(e instanceof Error ? e.message : String(e));
|
|
1036
1159
|
}
|
|
@@ -1051,10 +1174,10 @@ function musea(options = {}) {
|
|
|
1051
1174
|
if (binding.analyzeSfc) {
|
|
1052
1175
|
const analysis = binding.analyzeSfc(source, { filename: resolvedComponentPath });
|
|
1053
1176
|
sendJson(analysis);
|
|
1054
|
-
} else
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
}
|
|
1177
|
+
} else {
|
|
1178
|
+
const analysis = analyzeSfcFallback(source, { filename: resolvedComponentPath });
|
|
1179
|
+
sendJson(analysis);
|
|
1180
|
+
}
|
|
1058
1181
|
} else sendJson({
|
|
1059
1182
|
props: [],
|
|
1060
1183
|
emits: []
|
|
@@ -1087,7 +1210,17 @@ function musea(options = {}) {
|
|
|
1087
1210
|
minIndent = Math.min(minIndent, indent);
|
|
1088
1211
|
}
|
|
1089
1212
|
if (minIndent === Infinity) minIndent = 0;
|
|
1090
|
-
|
|
1213
|
+
let formatted;
|
|
1214
|
+
if (minIndent > 0) formatted = lines.map((line) => line.slice(minIndent)).join("\n");
|
|
1215
|
+
else {
|
|
1216
|
+
let restIndent = Infinity;
|
|
1217
|
+
for (let i = 1; i < lines.length; i++) if (lines[i].trim()) {
|
|
1218
|
+
const indent = lines[i].match(/^(\s*)/)?.[1].length || 0;
|
|
1219
|
+
restIndent = Math.min(restIndent, indent);
|
|
1220
|
+
}
|
|
1221
|
+
if (restIndent === Infinity || restIndent === 0) formatted = lines.join("\n");
|
|
1222
|
+
else formatted = lines.map((line, i) => i === 0 ? line : line.slice(restIndent)).join("\n");
|
|
1223
|
+
}
|
|
1091
1224
|
return "```" + lang + "\n" + formatted + "```";
|
|
1092
1225
|
});
|
|
1093
1226
|
sendJson({
|
|
@@ -1144,7 +1277,7 @@ function musea(options = {}) {
|
|
|
1144
1277
|
return;
|
|
1145
1278
|
}
|
|
1146
1279
|
const variantComponentName = toPascalCase(variant.name);
|
|
1147
|
-
const moduleCode = generatePreviewModuleWithProps(art, variantComponentName, variant.name, propsOverride);
|
|
1280
|
+
const moduleCode = generatePreviewModuleWithProps(art, variantComponentName, variant.name, propsOverride, resolvedPreviewCss, resolvedPreviewSetup);
|
|
1148
1281
|
res.setHeader("Content-Type", "application/javascript");
|
|
1149
1282
|
res.end(moduleCode);
|
|
1150
1283
|
} catch (e) {
|
|
@@ -1266,6 +1399,7 @@ function musea(options = {}) {
|
|
|
1266
1399
|
};
|
|
1267
1400
|
},
|
|
1268
1401
|
async buildStart() {
|
|
1402
|
+
console.log(`[musea] config.root: ${config.root}, include: ${JSON.stringify(include)}`);
|
|
1269
1403
|
const files = await scanArtFiles(config.root, include, exclude, inlineArt);
|
|
1270
1404
|
console.log(`[musea] Found ${files.length} art files`);
|
|
1271
1405
|
for (const file of files) await processArtFile(file);
|
|
@@ -1277,15 +1411,15 @@ function musea(options = {}) {
|
|
|
1277
1411
|
if (id.startsWith("virtual:musea-preview:")) return "\0musea-preview:" + id.slice(22);
|
|
1278
1412
|
if (id.startsWith("virtual:musea-art:")) {
|
|
1279
1413
|
const artPath = id.slice(18);
|
|
1280
|
-
if (artFiles.has(artPath)) return "\0musea-art:" + artPath;
|
|
1414
|
+
if (artFiles.has(artPath)) return "\0musea-art:" + artPath + "?musea-virtual";
|
|
1281
1415
|
}
|
|
1282
1416
|
if (id.endsWith(".art.vue")) {
|
|
1283
1417
|
const resolved = path.resolve(config.root, id);
|
|
1284
|
-
if (artFiles.has(resolved)) return VIRTUAL_MUSEA_PREFIX + resolved;
|
|
1418
|
+
if (artFiles.has(resolved)) return VIRTUAL_MUSEA_PREFIX + resolved + "?musea-virtual";
|
|
1285
1419
|
}
|
|
1286
1420
|
if (inlineArt && id.endsWith(".vue") && !id.endsWith(".art.vue")) {
|
|
1287
1421
|
const resolved = path.resolve(config.root, id);
|
|
1288
|
-
if (artFiles.has(resolved)) return VIRTUAL_MUSEA_PREFIX + resolved;
|
|
1422
|
+
if (artFiles.has(resolved)) return VIRTUAL_MUSEA_PREFIX + resolved + "?musea-virtual";
|
|
1289
1423
|
}
|
|
1290
1424
|
return null;
|
|
1291
1425
|
},
|
|
@@ -1301,17 +1435,17 @@ function musea(options = {}) {
|
|
|
1301
1435
|
const art = artFiles.get(artPath);
|
|
1302
1436
|
if (art) {
|
|
1303
1437
|
const variantComponentName = toPascalCase(variantName);
|
|
1304
|
-
return generatePreviewModule(art, variantComponentName, variantName);
|
|
1438
|
+
return generatePreviewModule(art, variantComponentName, variantName, resolvedPreviewCss, resolvedPreviewSetup);
|
|
1305
1439
|
}
|
|
1306
1440
|
}
|
|
1307
1441
|
}
|
|
1308
1442
|
if (id.startsWith("\0musea-art:")) {
|
|
1309
|
-
const artPath = id.slice(11);
|
|
1443
|
+
const artPath = id.slice(11).replace(/\?musea-virtual$/, "");
|
|
1310
1444
|
const art = artFiles.get(artPath);
|
|
1311
1445
|
if (art) return generateArtModule(art, artPath);
|
|
1312
1446
|
}
|
|
1313
1447
|
if (id.startsWith(VIRTUAL_MUSEA_PREFIX)) {
|
|
1314
|
-
const realPath = id.slice(VIRTUAL_MUSEA_PREFIX.length);
|
|
1448
|
+
const realPath = id.slice(VIRTUAL_MUSEA_PREFIX.length).replace(/\?musea-virtual$/, "");
|
|
1315
1449
|
const art = artFiles.get(realPath);
|
|
1316
1450
|
if (art) return generateArtModule(art, realPath);
|
|
1317
1451
|
}
|
|
@@ -1321,7 +1455,7 @@ function musea(options = {}) {
|
|
|
1321
1455
|
const { file } = ctx;
|
|
1322
1456
|
if (file.endsWith(".art.vue") && artFiles.has(file)) {
|
|
1323
1457
|
await processArtFile(file);
|
|
1324
|
-
const virtualId = VIRTUAL_MUSEA_PREFIX + file;
|
|
1458
|
+
const virtualId = VIRTUAL_MUSEA_PREFIX + file + "?musea-virtual";
|
|
1325
1459
|
const modules = server?.moduleGraph.getModulesByFile(virtualId);
|
|
1326
1460
|
if (modules) return [...modules];
|
|
1327
1461
|
}
|
|
@@ -1355,12 +1489,13 @@ function musea(options = {}) {
|
|
|
1355
1489
|
variants: parsed.variants.map((v) => ({
|
|
1356
1490
|
name: v.name,
|
|
1357
1491
|
template: v.template,
|
|
1358
|
-
isDefault: v.
|
|
1359
|
-
skipVrt: v.
|
|
1492
|
+
isDefault: v.isDefault,
|
|
1493
|
+
skipVrt: v.skipVrt
|
|
1360
1494
|
})),
|
|
1361
|
-
hasScriptSetup: parsed.
|
|
1362
|
-
|
|
1363
|
-
|
|
1495
|
+
hasScriptSetup: isInline ? false : parsed.hasScriptSetup,
|
|
1496
|
+
scriptSetupContent: !isInline && parsed.hasScriptSetup ? extractScriptSetupContent(source) : void 0,
|
|
1497
|
+
hasScript: parsed.hasScript,
|
|
1498
|
+
styleCount: parsed.styleCount,
|
|
1364
1499
|
isInline,
|
|
1365
1500
|
componentPath: isInline ? filePath : void 0
|
|
1366
1501
|
};
|
|
@@ -1378,7 +1513,8 @@ function shouldProcess(file, include, exclude, root) {
|
|
|
1378
1513
|
return false;
|
|
1379
1514
|
}
|
|
1380
1515
|
function matchGlob(filepath, pattern) {
|
|
1381
|
-
const
|
|
1516
|
+
const PLACEHOLDER = "<<GLOBSTAR>>";
|
|
1517
|
+
const regex = pattern.replaceAll("**", PLACEHOLDER).replace(/\./g, "\\.").replace(/\*/g, "[^/]*").replaceAll(PLACEHOLDER, ".*");
|
|
1382
1518
|
return new RegExp(`^${regex}$`).test(filepath);
|
|
1383
1519
|
}
|
|
1384
1520
|
async function scanArtFiles(root, include, exclude, scanInlineArt = false) {
|
|
@@ -1418,35 +1554,32 @@ function generateGalleryHtml(basePath, themeConfig) {
|
|
|
1418
1554
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1419
1555
|
<title>Musea - Component Gallery</title>
|
|
1420
1556
|
<script>window.__MUSEA_BASE_PATH__='${basePath}';${themeScript}</script>
|
|
1421
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
1422
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
1423
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
1424
1557
|
<style>
|
|
1425
1558
|
:root {
|
|
1426
|
-
--musea-bg-primary: #
|
|
1427
|
-
--musea-bg-secondary: #
|
|
1428
|
-
--musea-bg-tertiary: #
|
|
1429
|
-
--musea-bg-elevated: #
|
|
1430
|
-
--musea-accent: #
|
|
1431
|
-
--musea-accent-hover: #
|
|
1432
|
-
--musea-accent-subtle: rgba(
|
|
1433
|
-
--musea-text: #
|
|
1434
|
-
--musea-text-secondary: #
|
|
1435
|
-
--musea-text-muted: #
|
|
1436
|
-
--musea-border: #
|
|
1437
|
-
--musea-border-subtle: #
|
|
1438
|
-
--musea-success: #
|
|
1439
|
-
--musea-shadow: 0 4px 24px rgba(0, 0, 0, 0.
|
|
1440
|
-
--musea-radius-sm:
|
|
1441
|
-
--musea-radius-md:
|
|
1442
|
-
--musea-radius-lg:
|
|
1559
|
+
--musea-bg-primary: #E6E2D6;
|
|
1560
|
+
--musea-bg-secondary: #ddd9cd;
|
|
1561
|
+
--musea-bg-tertiary: #d4d0c4;
|
|
1562
|
+
--musea-bg-elevated: #E6E2D6;
|
|
1563
|
+
--musea-accent: #121212;
|
|
1564
|
+
--musea-accent-hover: #2a2a2a;
|
|
1565
|
+
--musea-accent-subtle: rgba(18, 18, 18, 0.08);
|
|
1566
|
+
--musea-text: #121212;
|
|
1567
|
+
--musea-text-secondary: #3a3a3a;
|
|
1568
|
+
--musea-text-muted: #6b6b6b;
|
|
1569
|
+
--musea-border: #c8c4b8;
|
|
1570
|
+
--musea-border-subtle: #d4d0c4;
|
|
1571
|
+
--musea-success: #16a34a;
|
|
1572
|
+
--musea-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
|
|
1573
|
+
--musea-radius-sm: 4px;
|
|
1574
|
+
--musea-radius-md: 6px;
|
|
1575
|
+
--musea-radius-lg: 8px;
|
|
1443
1576
|
--musea-transition: 0.15s ease;
|
|
1444
1577
|
}
|
|
1445
1578
|
|
|
1446
1579
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1447
1580
|
|
|
1448
1581
|
body {
|
|
1449
|
-
font-family: '
|
|
1582
|
+
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
1450
1583
|
background: var(--musea-bg-primary);
|
|
1451
1584
|
color: var(--musea-text);
|
|
1452
1585
|
min-height: 100vh;
|
|
@@ -1493,7 +1626,7 @@ function generateGalleryHtml(basePath, themeConfig) {
|
|
|
1493
1626
|
.logo-icon svg {
|
|
1494
1627
|
width: 16px;
|
|
1495
1628
|
height: 16px;
|
|
1496
|
-
color:
|
|
1629
|
+
color: var(--musea-text);
|
|
1497
1630
|
}
|
|
1498
1631
|
|
|
1499
1632
|
.header-subtitle {
|
|
@@ -1769,7 +1902,7 @@ function generateGalleryHtml(basePath, themeConfig) {
|
|
|
1769
1902
|
}
|
|
1770
1903
|
|
|
1771
1904
|
.variant-preview-code {
|
|
1772
|
-
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
1905
|
+
font-family: 'JetBrains Mono', 'SF Mono', 'Fira Code', monospace;
|
|
1773
1906
|
font-size: 0.75rem;
|
|
1774
1907
|
color: var(--musea-text-muted);
|
|
1775
1908
|
background: var(--musea-bg-primary);
|
|
@@ -1914,31 +2047,19 @@ function generateGalleryHtml(basePath, themeConfig) {
|
|
|
1914
2047
|
<div class="header-left">
|
|
1915
2048
|
<a href="${basePath}" class="logo">
|
|
1916
2049
|
<svg class="logo-svg" width="32" height="32" viewBox="0 0 200 200" fill="none">
|
|
1917
|
-
<
|
|
1918
|
-
<
|
|
1919
|
-
<
|
|
1920
|
-
<
|
|
1921
|
-
<stop offset="100%" stop-color="#e07048"/>
|
|
1922
|
-
</linearGradient>
|
|
1923
|
-
<linearGradient id="metal-grad-dark" x1="0%" y1="0%" x2="100%" y2="30%">
|
|
1924
|
-
<stop offset="0%" stop-color="#d0d4dc"/>
|
|
1925
|
-
<stop offset="60%" stop-color="#6b7280"/>
|
|
1926
|
-
<stop offset="100%" stop-color="#c45530"/>
|
|
1927
|
-
</linearGradient>
|
|
1928
|
-
</defs>
|
|
1929
|
-
<g transform="translate(40, 40)">
|
|
1930
|
-
<g transform="skewX(-12)">
|
|
1931
|
-
<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"/>
|
|
1932
|
-
<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"/>
|
|
2050
|
+
<g transform="translate(30, 25) scale(1.2)">
|
|
2051
|
+
<g transform="translate(15, 10) skewX(-15)">
|
|
2052
|
+
<path d="M 65 0 L 40 60 L 70 20 L 65 0 Z" fill="currentColor"/>
|
|
2053
|
+
<path d="M 20 0 L 40 60 L 53 13 L 20 0 Z" fill="currentColor"/>
|
|
1933
2054
|
</g>
|
|
1934
2055
|
</g>
|
|
1935
2056
|
<g transform="translate(110, 120)">
|
|
1936
|
-
<line x1="5" y1="10" x2="5" y2="50" stroke="
|
|
1937
|
-
<line x1="60" y1="10" x2="60" y2="50" stroke="
|
|
1938
|
-
<path d="M 0 10 L 32.5 0 L 65 10" fill="none" stroke="
|
|
1939
|
-
<rect x="15" y="18" width="14" height="12" rx="1" fill="none" stroke="
|
|
1940
|
-
<rect x="36" y="18" width="14" height="12" rx="1" fill="none" stroke="
|
|
1941
|
-
<rect x="23" y="35" width="18" height="12" rx="1" fill="none" stroke="
|
|
2057
|
+
<line x1="5" y1="10" x2="5" y2="50" stroke="currentColor" stroke-width="3" stroke-linecap="round"/>
|
|
2058
|
+
<line x1="60" y1="10" x2="60" y2="50" stroke="currentColor" stroke-width="3" stroke-linecap="round"/>
|
|
2059
|
+
<path d="M 0 10 L 32.5 0 L 65 10" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
2060
|
+
<rect x="15" y="18" width="14" height="12" rx="1" fill="none" stroke="currentColor" stroke-width="1.5" opacity="0.7"/>
|
|
2061
|
+
<rect x="36" y="18" width="14" height="12" rx="1" fill="none" stroke="currentColor" stroke-width="1.5" opacity="0.7"/>
|
|
2062
|
+
<rect x="23" y="35" width="18" height="12" rx="1" fill="none" stroke="currentColor" stroke-width="1.5" opacity="0.6"/>
|
|
1942
2063
|
</g>
|
|
1943
2064
|
</svg>
|
|
1944
2065
|
Musea
|
|
@@ -2382,11 +2503,11 @@ function __museaInitAddons(container, variantName) {
|
|
|
2382
2503
|
// Run axe-core a11y test
|
|
2383
2504
|
(async () => {
|
|
2384
2505
|
try {
|
|
2385
|
-
// Dynamically load axe-core from
|
|
2506
|
+
// Dynamically load axe-core from local vendor route if not already loaded
|
|
2386
2507
|
if (!window.axe) {
|
|
2387
2508
|
const script = document.createElement('script');
|
|
2388
|
-
|
|
2389
|
-
script.
|
|
2509
|
+
const _basePath = location.pathname.replace(/\\/preview$/, '');
|
|
2510
|
+
script.src = _basePath + '/vendor/axe-core.min.js';
|
|
2390
2511
|
await new Promise((resolve, reject) => {
|
|
2391
2512
|
script.onload = resolve;
|
|
2392
2513
|
script.onerror = reject;
|
|
@@ -2438,10 +2559,15 @@ function __museaInitAddons(container, variantName) {
|
|
|
2438
2559
|
window.parent.postMessage({ type: 'musea:ready', payload: {} }, '*');
|
|
2439
2560
|
}
|
|
2440
2561
|
`;
|
|
2441
|
-
function generatePreviewModule(art, variantComponentName, variantName) {
|
|
2562
|
+
function generatePreviewModule(art, variantComponentName, variantName, cssImports = [], previewSetup = null) {
|
|
2442
2563
|
const artModuleId = `virtual:musea-art:${art.path}`;
|
|
2443
2564
|
const escapedVariantName = escapeTemplate(variantName);
|
|
2565
|
+
const cssImportStatements = cssImports.map((cssPath) => `import '${cssPath}';`).join("\n");
|
|
2566
|
+
const setupImport = previewSetup ? `import __museaPreviewSetup from '${previewSetup}';` : "";
|
|
2567
|
+
const setupCall = previewSetup ? "await __museaPreviewSetup(app);" : "";
|
|
2444
2568
|
return `
|
|
2569
|
+
${cssImportStatements}
|
|
2570
|
+
${setupImport}
|
|
2445
2571
|
import { createApp, reactive, h } from 'vue';
|
|
2446
2572
|
import * as artModule from '${artModuleId}';
|
|
2447
2573
|
|
|
@@ -2462,6 +2588,9 @@ window.__museaSetProps = (props) => {
|
|
|
2462
2588
|
};
|
|
2463
2589
|
|
|
2464
2590
|
window.__museaSetSlots = (slots) => {
|
|
2591
|
+
for (const key of Object.keys(slotsOverride)) {
|
|
2592
|
+
delete slotsOverride[key];
|
|
2593
|
+
}
|
|
2465
2594
|
Object.assign(slotsOverride, slots);
|
|
2466
2595
|
};
|
|
2467
2596
|
|
|
@@ -2477,6 +2606,7 @@ async function mount() {
|
|
|
2477
2606
|
|
|
2478
2607
|
// Create and mount the app
|
|
2479
2608
|
const app = createApp(VariantComponent);
|
|
2609
|
+
${setupCall}
|
|
2480
2610
|
container.innerHTML = '';
|
|
2481
2611
|
container.className = 'musea-variant';
|
|
2482
2612
|
app.mount(container);
|
|
@@ -2486,19 +2616,21 @@ async function mount() {
|
|
|
2486
2616
|
__museaInitAddons(container, '${escapedVariantName}');
|
|
2487
2617
|
|
|
2488
2618
|
// Override set-props to remount with raw component + props
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
}
|
|
2501
|
-
|
|
2619
|
+
const TargetComponent = RawComponent || VariantComponent;
|
|
2620
|
+
window.__museaSetProps = (props) => {
|
|
2621
|
+
for (const key of Object.keys(propsOverride)) {
|
|
2622
|
+
delete propsOverride[key];
|
|
2623
|
+
}
|
|
2624
|
+
Object.assign(propsOverride, props);
|
|
2625
|
+
remountWithProps(TargetComponent);
|
|
2626
|
+
};
|
|
2627
|
+
window.__museaSetSlots = (slots) => {
|
|
2628
|
+
for (const key of Object.keys(slotsOverride)) {
|
|
2629
|
+
delete slotsOverride[key];
|
|
2630
|
+
}
|
|
2631
|
+
Object.assign(slotsOverride, slots);
|
|
2632
|
+
remountWithProps(TargetComponent);
|
|
2633
|
+
};
|
|
2502
2634
|
} catch (error) {
|
|
2503
2635
|
console.error('[musea-preview] Failed to mount:', error);
|
|
2504
2636
|
container.innerHTML = \`
|
|
@@ -2511,7 +2643,7 @@ async function mount() {
|
|
|
2511
2643
|
}
|
|
2512
2644
|
}
|
|
2513
2645
|
|
|
2514
|
-
function remountWithProps(Component) {
|
|
2646
|
+
async function remountWithProps(Component) {
|
|
2515
2647
|
if (currentApp) {
|
|
2516
2648
|
currentApp.unmount();
|
|
2517
2649
|
}
|
|
@@ -2519,15 +2651,14 @@ function remountWithProps(Component) {
|
|
|
2519
2651
|
setup() {
|
|
2520
2652
|
return () => {
|
|
2521
2653
|
const slotFns = {};
|
|
2522
|
-
|
|
2523
|
-
slotFns
|
|
2654
|
+
for (const [name, content] of Object.entries(slotsOverride)) {
|
|
2655
|
+
if (content) slotFns[name] = () => h('span', { innerHTML: content });
|
|
2524
2656
|
}
|
|
2525
|
-
return h(
|
|
2526
|
-
h(Component, { ...propsOverride }, slotFns)
|
|
2527
|
-
]);
|
|
2657
|
+
return h(Component, { ...propsOverride }, slotFns);
|
|
2528
2658
|
};
|
|
2529
2659
|
}
|
|
2530
2660
|
});
|
|
2661
|
+
${setupCall}
|
|
2531
2662
|
container.innerHTML = '';
|
|
2532
2663
|
app.mount(container);
|
|
2533
2664
|
currentApp = app;
|
|
@@ -2540,6 +2671,57 @@ function generateManifestModule(artFiles) {
|
|
|
2540
2671
|
const arts = Array.from(artFiles.values());
|
|
2541
2672
|
return `export const arts = ${JSON.stringify(arts, null, 2)};`;
|
|
2542
2673
|
}
|
|
2674
|
+
/**
|
|
2675
|
+
* Extract the content of the first <script setup> block from a Vue SFC source.
|
|
2676
|
+
*/
|
|
2677
|
+
function extractScriptSetupContent(source) {
|
|
2678
|
+
const match = source.match(/<script\s+[^>]*setup[^>]*>([\s\S]*?)<\/script>/);
|
|
2679
|
+
return match?.[1]?.trim();
|
|
2680
|
+
}
|
|
2681
|
+
/**
|
|
2682
|
+
* Parse script setup content into imports and setup body.
|
|
2683
|
+
* Returns the import lines, setup body lines, and all identifiers to expose.
|
|
2684
|
+
*/
|
|
2685
|
+
function parseScriptSetupForArt(content) {
|
|
2686
|
+
const lines = content.split("\n");
|
|
2687
|
+
const imports = [];
|
|
2688
|
+
const setupBody = [];
|
|
2689
|
+
const returnNames = new Set();
|
|
2690
|
+
for (const line of lines) {
|
|
2691
|
+
const trimmed = line.trim();
|
|
2692
|
+
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
2693
|
+
if (trimmed.startsWith("import ")) {
|
|
2694
|
+
imports.push(line);
|
|
2695
|
+
const defaultMatch = trimmed.match(/^import\s+(\w+)/);
|
|
2696
|
+
if (defaultMatch && defaultMatch[1] !== "type") returnNames.add(defaultMatch[1]);
|
|
2697
|
+
const namedMatch = trimmed.match(/\{([^}]+)\}/);
|
|
2698
|
+
if (namedMatch) for (const part of namedMatch[1].split(",")) {
|
|
2699
|
+
const name = part.trim().split(/\s+as\s+/).pop()?.trim();
|
|
2700
|
+
if (name && !name.startsWith("type ")) returnNames.add(name);
|
|
2701
|
+
}
|
|
2702
|
+
} else {
|
|
2703
|
+
setupBody.push(line);
|
|
2704
|
+
const constMatch = trimmed.match(/^(?:const|let|var)\s+(\w+)/);
|
|
2705
|
+
if (constMatch) returnNames.add(constMatch[1]);
|
|
2706
|
+
const destructMatch = trimmed.match(/^(?:const|let|var)\s+\{([^}]+)\}/);
|
|
2707
|
+
if (destructMatch) for (const part of destructMatch[1].split(",")) {
|
|
2708
|
+
const name = part.trim().split(/\s*:\s*/).shift()?.trim();
|
|
2709
|
+
if (name) returnNames.add(name);
|
|
2710
|
+
}
|
|
2711
|
+
const arrayMatch = trimmed.match(/^(?:const|let|var)\s+\[([^\]]+)\]/);
|
|
2712
|
+
if (arrayMatch) for (const part of arrayMatch[1].split(",")) {
|
|
2713
|
+
const name = part.trim();
|
|
2714
|
+
if (name && name !== "...") returnNames.add(name);
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
returnNames.delete("type");
|
|
2719
|
+
return {
|
|
2720
|
+
imports,
|
|
2721
|
+
setupBody,
|
|
2722
|
+
returnNames: [...returnNames]
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2543
2725
|
function generateArtModule(art, filePath) {
|
|
2544
2726
|
let componentImportPath;
|
|
2545
2727
|
let componentName;
|
|
@@ -2551,12 +2733,27 @@ function generateArtModule(art, filePath) {
|
|
|
2551
2733
|
componentImportPath = path.isAbsolute(comp) ? comp : path.resolve(path.dirname(filePath), comp);
|
|
2552
2734
|
componentName = path.basename(comp, ".vue");
|
|
2553
2735
|
}
|
|
2736
|
+
const scriptSetup = art.scriptSetupContent ? parseScriptSetupForArt(art.scriptSetupContent) : null;
|
|
2554
2737
|
let code = `
|
|
2555
2738
|
// Auto-generated module for: ${path.basename(filePath)}
|
|
2556
2739
|
import { defineComponent, h } from 'vue';
|
|
2557
2740
|
`;
|
|
2741
|
+
if (scriptSetup) {
|
|
2742
|
+
const artDir = path.dirname(filePath);
|
|
2743
|
+
for (const imp of scriptSetup.imports) {
|
|
2744
|
+
const resolved = imp.replace(/from\s+(['"])(\.[^'"]+)\1/, (_match, quote, relPath) => {
|
|
2745
|
+
const absPath = path.resolve(artDir, relPath);
|
|
2746
|
+
return `from ${quote}${absPath}${quote}`;
|
|
2747
|
+
});
|
|
2748
|
+
code += `${resolved}\n`;
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2558
2751
|
if (componentImportPath && componentName) {
|
|
2559
|
-
|
|
2752
|
+
const alreadyImported = scriptSetup?.imports.some((imp) => {
|
|
2753
|
+
if (imp.includes(`from '${componentImportPath}'`) || imp.includes(`from "${componentImportPath}"`)) return true;
|
|
2754
|
+
return new RegExp(`^import\\s+${componentName}[\\s,]`).test(imp.trim());
|
|
2755
|
+
});
|
|
2756
|
+
if (!alreadyImported) code += `import ${componentName} from '${componentImportPath}';\n`;
|
|
2560
2757
|
code += `export const __component__ = ${componentName};\n`;
|
|
2561
2758
|
}
|
|
2562
2759
|
code += `
|
|
@@ -2568,12 +2765,27 @@ export const variants = ${JSON.stringify(art.variants)};
|
|
|
2568
2765
|
let template = variant.template;
|
|
2569
2766
|
if (componentName) template = template.replace(/<Self/g, `<${componentName}`).replace(/<\/Self>/g, `</${componentName}>`);
|
|
2570
2767
|
const escapedTemplate = template.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
2571
|
-
const fullTemplate = `<div
|
|
2572
|
-
|
|
2573
|
-
|
|
2768
|
+
const fullTemplate = `<div data-variant="${variant.name}">${escapedTemplate}</div>`;
|
|
2769
|
+
const componentNames = new Set();
|
|
2770
|
+
if (componentName) componentNames.add(componentName);
|
|
2771
|
+
if (scriptSetup) {
|
|
2772
|
+
for (const name of scriptSetup.returnNames) if (/^[A-Z]/.test(name)) componentNames.add(name);
|
|
2773
|
+
}
|
|
2774
|
+
const components = componentNames.size > 0 ? ` components: { ${[...componentNames].join(", ")} },\n` : "";
|
|
2775
|
+
if (scriptSetup && scriptSetup.setupBody.length > 0) code += `
|
|
2776
|
+
export const ${variantComponentName} = defineComponent({
|
|
2574
2777
|
name: '${variantComponentName}',
|
|
2575
|
-
|
|
2778
|
+
${components} setup() {
|
|
2779
|
+
${scriptSetup.setupBody.map((l) => ` ${l}`).join("\n")}
|
|
2780
|
+
return { ${scriptSetup.returnNames.join(", ")} };
|
|
2781
|
+
},
|
|
2576
2782
|
template: \`${fullTemplate}\`,
|
|
2783
|
+
});
|
|
2784
|
+
`;
|
|
2785
|
+
else if (componentName) code += `
|
|
2786
|
+
export const ${variantComponentName} = {
|
|
2787
|
+
name: '${variantComponentName}',
|
|
2788
|
+
${components} template: \`${fullTemplate}\`,
|
|
2577
2789
|
};
|
|
2578
2790
|
`;
|
|
2579
2791
|
else code += `
|
|
@@ -2609,11 +2821,16 @@ function toPascalCase(str) {
|
|
|
2609
2821
|
function escapeTemplate(str) {
|
|
2610
2822
|
return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n");
|
|
2611
2823
|
}
|
|
2612
|
-
function generatePreviewModuleWithProps(art, variantComponentName, variantName, propsOverride) {
|
|
2824
|
+
function generatePreviewModuleWithProps(art, variantComponentName, variantName, propsOverride, cssImports = [], previewSetup = null) {
|
|
2613
2825
|
const artModuleId = `virtual:musea-art:${art.path}`;
|
|
2614
2826
|
const escapedVariantName = escapeTemplate(variantName);
|
|
2615
2827
|
const propsJson = JSON.stringify(propsOverride);
|
|
2828
|
+
const cssImportStatements = cssImports.map((cssPath) => `import '${cssPath}';`).join("\n");
|
|
2829
|
+
const setupImport = previewSetup ? `import __museaPreviewSetup from '${previewSetup}';` : "";
|
|
2830
|
+
const setupCall = previewSetup ? "await __museaPreviewSetup(app);" : "";
|
|
2616
2831
|
return `
|
|
2832
|
+
${cssImportStatements}
|
|
2833
|
+
${setupImport}
|
|
2617
2834
|
import { createApp, h } from 'vue';
|
|
2618
2835
|
import * as artModule from '${artModuleId}';
|
|
2619
2836
|
|
|
@@ -2636,6 +2853,7 @@ async function mount() {
|
|
|
2636
2853
|
};
|
|
2637
2854
|
|
|
2638
2855
|
const app = createApp(WrappedComponent);
|
|
2856
|
+
${setupCall}
|
|
2639
2857
|
container.innerHTML = '';
|
|
2640
2858
|
container.className = 'musea-variant';
|
|
2641
2859
|
app.mount(container);
|
|
@@ -2650,14 +2868,16 @@ async function mount() {
|
|
|
2650
2868
|
mount();
|
|
2651
2869
|
`;
|
|
2652
2870
|
}
|
|
2653
|
-
function generatePreviewHtml(art, variant,
|
|
2654
|
-
const previewModuleUrl = `${
|
|
2871
|
+
function generatePreviewHtml(art, variant, _basePath, viteBase) {
|
|
2872
|
+
const previewModuleUrl = `${_basePath}/preview-module?art=${encodeURIComponent(art.path)}&variant=${encodeURIComponent(variant.name)}`;
|
|
2873
|
+
const base = (viteBase || "/").replace(/\/$/, "");
|
|
2655
2874
|
return `<!DOCTYPE html>
|
|
2656
2875
|
<html lang="en">
|
|
2657
2876
|
<head>
|
|
2658
2877
|
<meta charset="UTF-8">
|
|
2659
2878
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2660
2879
|
<title>${escapeHtml(art.metadata.title)} - ${escapeHtml(variant.name)}</title>
|
|
2880
|
+
<script type="module" src="${base}/@vite/client"></script>
|
|
2661
2881
|
<style>
|
|
2662
2882
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
2663
2883
|
html, body {
|
|
@@ -2669,10 +2889,6 @@ function generatePreviewHtml(art, variant, basePath) {
|
|
|
2669
2889
|
background: #ffffff;
|
|
2670
2890
|
}
|
|
2671
2891
|
.musea-variant {
|
|
2672
|
-
padding: 1.5rem;
|
|
2673
|
-
display: flex;
|
|
2674
|
-
align-items: center;
|
|
2675
|
-
justify-content: center;
|
|
2676
2892
|
min-height: 100vh;
|
|
2677
2893
|
}
|
|
2678
2894
|
.musea-error {
|