@vizejs/vite-plugin-musea 0.269.0 → 0.271.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.
Files changed (34) hide show
  1. package/README.md +14 -0
  2. package/dist/gallery/assets/{MonacoEditor-D6vHGjOV.js → MonacoEditor-DMhf_fqm.js} +2 -2
  3. package/dist/gallery/assets/{cssMode-COwrxII5.js → cssMode-CrF0DU5e.js} +1 -1
  4. package/dist/gallery/assets/{editor.api2-CJZ9tF6K.js → editor.api2-C8DOVkz6.js} +1 -1
  5. package/dist/gallery/assets/{editor.main-Dt6-6pas.js → editor.main-CkA1G89l.js} +2 -2
  6. package/dist/gallery/assets/{freemarker2-Dnb1g0Jo.js → freemarker2-BO_2Ds_l.js} +1 -1
  7. package/dist/gallery/assets/{handlebars-DOmT_A6M.js → handlebars-Bcw0MhoR.js} +1 -1
  8. package/dist/gallery/assets/{html-Qempe7xt.js → html-B0dZkq95.js} +1 -1
  9. package/dist/gallery/assets/{htmlMode-CKgIR73L.js → htmlMode-DfFDTMZk.js} +1 -1
  10. package/dist/gallery/assets/index-DVSHNlTs.css +1 -0
  11. package/dist/gallery/assets/{index-Dtsku8dI.js → index-LuE0osBT.js} +4 -4
  12. package/dist/gallery/assets/{javascript-o8yJHIsv.js → javascript-Casxevk_.js} +1 -1
  13. package/dist/gallery/assets/{jsonMode-DDj5uiry.js → jsonMode-BrpIDLOb.js} +1 -1
  14. package/dist/gallery/assets/{liquid-GihPC2aI.js → liquid-BmBJ7H5X.js} +1 -1
  15. package/dist/gallery/assets/{lspLanguageFeatures-Cj9PuIZx.js → lspLanguageFeatures-CLfNwybK.js} +1 -1
  16. package/dist/gallery/assets/{mdx-B0KQLOVD.js → mdx-BZG_rPXe.js} +1 -1
  17. package/dist/gallery/assets/{monaco.contribution-BUitKtul.js → monaco.contribution-BZGuloqf.js} +2 -2
  18. package/dist/gallery/assets/{python-DaeXews5.js → python-jua_xfGg.js} +1 -1
  19. package/dist/gallery/assets/{razor-D7eowHXw.js → razor-CeK1pL1V.js} +1 -1
  20. package/dist/gallery/assets/{tsMode-DAcic1g_.js → tsMode-CedHUSbT.js} +1 -1
  21. package/dist/gallery/assets/{typescript-DZzujlOz.js → typescript-Bnz8OSWC.js} +1 -1
  22. package/dist/gallery/assets/{workers-M0x9Vvdl.js → workers-DDHNiHmb.js} +1 -1
  23. package/dist/gallery/assets/{xml-CaKMy0Ek.js → xml-B8g70rk3.js} +1 -1
  24. package/dist/gallery/assets/{yaml-Cop9p_yY.js → yaml-CirrspT2.js} +1 -1
  25. package/dist/gallery/index.html +2 -2
  26. package/dist/{gallery-DIBlUrB6.mjs → gallery-qM8Q_21C.mjs} +30 -5
  27. package/dist/gallery-qM8Q_21C.mjs.map +1 -0
  28. package/dist/index.d.mts +111 -70
  29. package/dist/index.d.mts.map +1 -1
  30. package/dist/index.mjs +149 -18
  31. package/dist/index.mjs.map +1 -1
  32. package/package.json +4 -4
  33. package/dist/gallery/assets/index-D67uewr9.css +0 -1
  34. package/dist/gallery-DIBlUrB6.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gallery-qM8Q_21C.mjs","names":["stylesBase","stylesLayout","stylesComponents"],"sources":["../src/security.ts","../src/gallery/globals.ts","../src/gallery/styles-base.css?inline","../src/gallery/styles-layout.css?inline","../src/gallery/styles-components.css?inline","../src/gallery/styles.ts","../src/gallery/template.ts","../src/gallery/index.ts"],"sourcesContent":["import { randomBytes, timingSafeEqual } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport type { IncomingMessage } from \"node:http\";\nimport path from \"node:path\";\n\nexport const DEFAULT_API_BODY_LIMIT_BYTES = 1024 * 1024;\n\nexport class HttpError extends Error {\n readonly status: number;\n\n constructor(message: string, status: number) {\n super(message);\n this.name = \"HttpError\";\n this.status = status;\n }\n}\n\nexport function createDevSessionToken(): string {\n return randomBytes(32).toString(\"base64url\");\n}\n\nfunction realpathNearest(targetPath: string): string {\n let current = path.resolve(targetPath);\n const missingParts: string[] = [];\n\n while (true) {\n try {\n const real = fs.realpathSync.native(current);\n return missingParts.length > 0 ? path.join(real, ...missingParts.reverse()) : real;\n } catch {\n const parent = path.dirname(current);\n if (parent === current) {\n return path.resolve(targetPath);\n }\n missingParts.push(path.basename(current));\n current = parent;\n }\n }\n}\n\nfunction isResolvedPathInside(parentDir: string, candidatePath: string): boolean {\n const parent = path.resolve(parentDir);\n const candidate = path.resolve(candidatePath);\n const relative = path.relative(parent, candidate);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nexport function isPathInside(parentDir: string, candidatePath: string): boolean {\n return isResolvedPathInside(realpathNearest(parentDir), realpathNearest(candidatePath));\n}\n\nexport function isPathInsideAny(parentDirs: string[], candidatePath: string): boolean {\n const candidate = realpathNearest(candidatePath);\n return parentDirs.some((parentDir) =>\n isResolvedPathInside(realpathNearest(parentDir), candidate),\n );\n}\n\nexport function resolveInside(parentDir: string, candidatePath: string, label = \"path\"): string {\n return resolveInsideAny([parentDir], candidatePath, label);\n}\n\nexport function resolveInsideAny(\n parentDirs: string[],\n candidatePath: string,\n label = \"path\",\n): string {\n if (candidatePath.includes(\"\\0\")) {\n throw new HttpError(`${label} contains an invalid character`, 400);\n }\n\n if (parentDirs.length === 0) {\n throw new HttpError(`No allowed directories configured for ${label}`, 500);\n }\n\n const parent = path.resolve(parentDirs[0] ?? \".\");\n const resolved = path.isAbsolute(candidatePath)\n ? path.resolve(candidatePath)\n : path.resolve(parent, candidatePath);\n\n if (!isPathInsideAny(parentDirs, resolved)) {\n throw new HttpError(`${label} escapes the allowed directory`, 400);\n }\n\n return resolved;\n}\n\nexport function resolveUrlPathInside(\n parentDir: string,\n requestUrl: string,\n label = \"path\",\n): string {\n const rawPath = requestUrl.split(/[?#]/, 1)[0] || \"/\";\n let pathname = decodeUrlComponent(rawPath, label);\n\n pathname = pathname.replaceAll(\"\\\\\", \"/\");\n if (pathname.split(\"/\").includes(\"..\")) {\n throw new HttpError(`${label} must not contain parent directory segments`, 400);\n }\n\n const relativePath = `.${pathname}`;\n return resolveInside(parentDir, relativePath, label);\n}\n\nexport function decodeUrlComponent(value: string, label = \"path\"): string {\n try {\n return decodeURIComponent(value);\n } catch {\n throw new HttpError(`${label} is not valid URL encoding`, 400);\n }\n}\n\nexport function collectRequestBody(\n req: IncomingMessage,\n limit = DEFAULT_API_BODY_LIMIT_BYTES,\n): Promise<string> {\n return new Promise((resolve, reject) => {\n let body = \"\";\n let size = 0;\n let completed = false;\n\n req.on(\"data\", (chunk: Buffer | string) => {\n if (completed) return;\n\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n size += buffer.byteLength;\n if (size > limit) {\n completed = true;\n reject(new HttpError(`Request body exceeds ${limit} bytes`, 413));\n return;\n }\n\n body += buffer.toString(\"utf-8\");\n });\n\n req.on(\"end\", () => {\n if (!completed) {\n completed = true;\n resolve(body);\n }\n });\n\n req.on(\"error\", (error) => {\n if (!completed) {\n completed = true;\n reject(error);\n }\n });\n });\n}\n\nexport function parseJsonBody<T = unknown>(body: string): T {\n try {\n return JSON.parse(body) as T;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new HttpError(\"Malformed JSON body\", 400);\n }\n throw error;\n }\n}\n\nexport function validateDevApiRequest(\n req: IncomingMessage,\n sessionToken: string,\n): HttpError | null {\n const originError = validateOrigin(req);\n if (originError) return originError;\n\n if (!isUnsafeMethod(req.method)) {\n return null;\n }\n\n if (!hasValidSessionToken(req, sessionToken)) {\n return new HttpError(\"Invalid Musea dev session token\", 403);\n }\n\n if (!isJsonRequest(req)) {\n return new HttpError(\"Content-Type must be application/json\", 415);\n }\n\n return null;\n}\n\nexport function serializeScriptValue(value: unknown): string {\n return (JSON.stringify(value) ?? \"undefined\").replace(/[<>&\\u2028\\u2029]/g, (char) => {\n switch (char) {\n case \"<\":\n return \"\\\\u003C\";\n case \">\":\n return \"\\\\u003E\";\n case \"&\":\n return \"\\\\u0026\";\n case \"\\u2028\":\n return \"\\\\u2028\";\n case \"\\u2029\":\n return \"\\\\u2029\";\n default:\n return char;\n }\n });\n}\n\nfunction isUnsafeMethod(method: string | undefined): boolean {\n return method === \"POST\" || method === \"PUT\" || method === \"PATCH\" || method === \"DELETE\";\n}\n\nfunction isJsonRequest(req: IncomingMessage): boolean {\n const contentType = getHeader(req, \"content-type\");\n return contentType?.split(\";\")[0]?.trim().toLowerCase() === \"application/json\";\n}\n\nfunction validateOrigin(req: IncomingMessage): HttpError | null {\n const secFetchSite = getHeader(req, \"sec-fetch-site\");\n if (secFetchSite === \"cross-site\") {\n return new HttpError(\"Cross-origin Musea API requests are not allowed\", 403);\n }\n\n const origin = getHeader(req, \"origin\");\n if (!origin) return null;\n\n const host = getHeader(req, \"host\");\n if (!host) {\n return new HttpError(\"Missing Host header\", 400);\n }\n\n try {\n const originUrl = new URL(origin);\n if (originUrl.host !== host) {\n return new HttpError(\"Cross-origin Musea API requests are not allowed\", 403);\n }\n } catch {\n return new HttpError(\"Invalid Origin header\", 400);\n }\n\n return null;\n}\n\nfunction hasValidSessionToken(req: IncomingMessage, expectedToken: string): boolean {\n const actualToken = getHeader(req, \"x-musea-session\");\n if (!actualToken) return false;\n\n const actual = Buffer.from(actualToken);\n const expected = Buffer.from(expectedToken);\n return actual.length === expected.length && timingSafeEqual(actual, expected);\n}\n\nfunction getHeader(req: IncomingMessage, name: string): string | undefined {\n const value = req.headers[name];\n if (Array.isArray(value)) return value[0];\n return value;\n}\n","import { serializeScriptValue } from \"../security.js\";\nimport type { MuseaTokenPreviewConfig } from \"../tokens/preview.js\";\n\nexport interface MuseaGalleryGlobals {\n basePath: string;\n devSessionToken?: string;\n staticPreviews?: Record<string, Record<string, string>>;\n themeConfig?: { default: string; custom?: Record<string, unknown> };\n tokenPreviewConfig?: MuseaTokenPreviewConfig;\n}\n\nexport function generateGalleryGlobalsScript(globals: MuseaGalleryGlobals): string {\n const parts = [`window.__MUSEA_BASE_PATH__=${serializeScriptValue(globals.basePath)};`];\n if (globals.devSessionToken !== undefined) {\n parts.push(`window.__MUSEA_SESSION_TOKEN__=${serializeScriptValue(globals.devSessionToken)};`);\n }\n if (globals.staticPreviews !== undefined) {\n parts.push(\"window.__MUSEA_STATIC__=true;\");\n parts.push(`window.__MUSEA_STATIC_PREVIEWS__=${serializeScriptValue(globals.staticPreviews)};`);\n }\n if (globals.themeConfig) {\n parts.push(`window.__MUSEA_THEME_CONFIG__=${serializeScriptValue(globals.themeConfig)};`);\n }\n if (globals.tokenPreviewConfig) {\n parts.push(\n `window.__MUSEA_TOKEN_PREVIEWS__=${serializeScriptValue(globals.tokenPreviewConfig)};`,\n );\n }\n return parts.join(\"\");\n}\n\nexport function generateDevGlobalsScript(\n basePath: string,\n devSessionToken: string,\n themeConfig?: MuseaGalleryGlobals[\"themeConfig\"],\n tokenPreviewConfig?: MuseaTokenPreviewConfig,\n): string {\n return generateGalleryGlobalsScript({\n basePath,\n devSessionToken,\n themeConfig,\n tokenPreviewConfig,\n });\n}\n",":root {\n --musea-bg-primary: #e6e2d6;\n --musea-bg-secondary: #ddd9cd;\n --musea-bg-tertiary: #d4d0c4;\n --musea-bg-elevated: #e6e2d6;\n --musea-accent: #121212;\n --musea-accent-hover: #2a2a2a;\n --musea-accent-subtle: rgba(18, 18, 18, 0.08);\n --musea-text: #121212;\n --musea-text-secondary: #3a3a3a;\n --musea-text-muted: #6b6b6b;\n --musea-border: #c8c4b8;\n --musea-border-subtle: #d4d0c4;\n --musea-success: #16a34a;\n --musea-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);\n --musea-radius-sm: 4px;\n --musea-radius-md: 6px;\n --musea-radius-lg: 8px;\n --musea-transition: 0.15s ease;\n}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, 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","/* 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: var(--musea-text);\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:\n border-color var(--musea-transition),\n 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","/* 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}\n\n.variant-preview {\n aspect-ratio: 16 / 7;\n background: var(--musea-bg-tertiary);\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n position: relative;\n overflow: hidden;\n}\n\n.variant-preview iframe {\n width: 70%;\n height: 100%;\n max-width: 100%;\n max-height: 100%;\n border: none;\n background: white;\n border-radius: var(--musea-radius-md);\n box-shadow: 0 12px 30px rgba(13, 13, 13, 0.12);\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: \"JetBrains Mono\", \"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 {\n transform: rotate(360deg);\n }\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","/**\n * CSS theme variables and style definitions for the Musea gallery.\n *\n * CSS is split into separate .css files and imported as text\n * via tsdown's `?inline` support.\n */\n\n// @ts-expect-error -- CSS imported as text via tsdown `?inline`\nimport stylesBase from \"./styles-base.css?inline\";\n// @ts-expect-error -- CSS imported as text via tsdown `?inline`\nimport stylesLayout from \"./styles-layout.css?inline\";\n// @ts-expect-error -- CSS imported as text via tsdown `?inline`\nimport stylesComponents from \"./styles-components.css?inline\";\n\n/**\n * Generate the full gallery CSS styles string.\n */\nexport function generateGalleryStyles(): string {\n return `${stylesBase}\\n${stylesLayout}\\n${stylesComponents}`;\n}\n","/**\n * HTML structure and inline JS generation for the Musea gallery.\n *\n * Extracted from gallery.ts to keep file sizes manageable.\n */\n\nimport { serializeScriptValue } from \"../security.js\";\n\nfunction escapeHtmlAttribute(value: string): string {\n return value.replace(/[&<>\"']/g, (char) => {\n switch (char) {\n case \"&\":\n return \"&amp;\";\n case \"<\":\n return \"&lt;\";\n case \">\":\n return \"&gt;\";\n case '\"':\n return \"&quot;\";\n case \"'\":\n return \"&#39;\";\n default:\n return char;\n }\n });\n}\n\n/**\n * Generate the gallery HTML body (header, sidebar, content, and inline script).\n */\nexport function generateGalleryBody(basePath: string): string {\n const escapedBasePath = escapeHtmlAttribute(basePath);\n\n return `\n <header class=\"header\">\n <div class=\"header-left\">\n <a href=\"${escapedBasePath}\" class=\"logo\">\n <svg class=\"logo-svg\" width=\"32\" height=\"32\" viewBox=\"0 0 200 200\" fill=\"none\">\n <g transform=\"translate(30, 25) scale(1.2)\">\n <g transform=\"translate(15, 10) skewX(-15)\">\n <path d=\"M 65 0 L 40 60 L 70 20 L 65 0 Z\" fill=\"currentColor\"/>\n <path d=\"M 20 0 L 40 60 L 53 13 L 20 0 Z\" fill=\"currentColor\"/>\n </g>\n </g>\n <g transform=\"translate(110, 120)\">\n <line x1=\"5\" y1=\"10\" x2=\"5\" y2=\"50\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\"/>\n <line x1=\"60\" y1=\"10\" x2=\"60\" y2=\"50\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\"/>\n <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\"/>\n <rect x=\"15\" y=\"18\" width=\"14\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" opacity=\"0.7\"/>\n <rect x=\"36\" y=\"18\" width=\"14\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" opacity=\"0.7\"/>\n <rect x=\"23\" y=\"35\" width=\"18\" height=\"12\" rx=\"1\" fill=\"none\" stroke=\"currentColor\" 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\n/**\n * Generate the gallery inline script (SPA logic).\n */\nexport function generateGalleryScript(basePath: string): string {\n return `\n const basePath = ${serializeScriptValue(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 const escapedCategory = escapeHtml(category);\n html += '<div class=\"sidebar-section\">';\n html += '<div class=\"category-header\" data-category=\"' + escapedCategory + '\">';\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>' + escapedCategory + '</span>';\n html += '<span class=\"category-count\">' + items.length + '</span>';\n html += '</div>';\n html += '<ul class=\"art-list\" data-category=\"' + escapedCategory + '\">';\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=\"' + escapeHtml(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 = header.parentElement?.querySelector('.art-list');\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 const escapedPreviewUrl = escapeHtml(previewUrl);\n\n html += '<div class=\"variant-card\">';\n html += '<div class=\"variant-preview\">';\n html += '<iframe src=\"' + escapedPreviewUrl + '\" 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\" data-preview-url=\"' + escapedPreviewUrl + '\"><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 content.querySelectorAll('.variant-action-btn[data-preview-url]').forEach(button => {\n button.addEventListener('click', () => {\n const previewUrl = button.dataset.previewUrl;\n if (previewUrl) window.open(previewUrl, '_blank', 'noopener');\n });\n });\n }\n\n function escapeHtml(str) {\n if (!str) return '';\n return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;').replace(/'/g, '&#39;');\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}\n","/**\n * Gallery HTML generation for the Musea component gallery.\n *\n * Contains the inline gallery SPA template (used as a fallback when the\n * pre-built gallery is not available) and the gallery virtual module.\n */\n\nimport { generateGalleryStyles } from \"./styles.js\";\nimport { generateGalleryBody, generateGalleryScript } from \"./template.js\";\nimport { generateGalleryGlobalsScript } from \"./globals.js\";\nimport { serializeScriptValue } from \"../security.js\";\nimport type { MuseaTokenPreviewConfig } from \"../tokens/preview.js\";\n\n/**\n * Generate the inline gallery HTML page.\n */\nexport function generateGalleryHtml(\n basePath: string,\n devSessionToken: string,\n themeConfig?: { default: string; custom?: Record<string, unknown> },\n tokenPreviewConfig?: MuseaTokenPreviewConfig,\n): string {\n const globalsScript = generateGalleryGlobalsScript({\n basePath,\n devSessionToken,\n themeConfig,\n tokenPreviewConfig,\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>${globalsScript}${\"<\"}/script>\n <style>${generateGalleryStyles()}\n </style>\n</head>\n<body>${generateGalleryBody(basePath)}\n\n <script type=\"module\">${generateGalleryScript(basePath)}\n </script>\n</body>\n</html>`;\n}\n\n/**\n * Generate the virtual gallery module code.\n */\nexport function generateGalleryModule(basePath: string): string {\n return `\nexport const basePath = ${serializeScriptValue(basePath)};\nexport async function loadArts() {\n const res = await fetch(basePath + '/api/arts');\n return res.json();\n}\n`;\n}\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -3,6 +3,111 @@ import { c as AnalysisApiResponse, l as PaletteApiResponse, n as MuseaA11yRunner
3
3
  import { AutogenOptions, AutogenOutput, GeneratedVariant, PropDefinition, generateArtFile, writeArtFile } from "./autogen/index.mjs";
4
4
  import { Plugin } from "vite";
5
5
 
6
+ //#region src/tokens/parser.d.ts
7
+ /**
8
+ * Token parsing utilities for Style Dictionary integration.
9
+ *
10
+ * Thin native binding for design token files (JSON) and directories.
11
+ */
12
+ /**
13
+ * Design token value.
14
+ */
15
+ interface DesignToken {
16
+ value: string | number;
17
+ type?: string;
18
+ description?: string;
19
+ attributes?: Record<string, unknown>;
20
+ $tier?: "primitive" | "semantic";
21
+ $reference?: string;
22
+ $resolvedValue?: string | number;
23
+ }
24
+ /**
25
+ * Token category (e.g., colors, spacing, typography).
26
+ */
27
+ interface TokenCategory {
28
+ name: string;
29
+ tokens: Record<string, DesignToken>;
30
+ subcategories?: TokenCategory[];
31
+ }
32
+ /**
33
+ * Style Dictionary output format.
34
+ */
35
+ interface StyleDictionaryOutput {
36
+ categories: TokenCategory[];
37
+ metadata: {
38
+ name: string;
39
+ version?: string;
40
+ generatedAt: string;
41
+ };
42
+ }
43
+ /**
44
+ * Configuration for Style Dictionary integration.
45
+ */
46
+ interface StyleDictionaryConfig {
47
+ /**
48
+ * Path to tokens JSON file/directory or Tailwind CSS theme file.
49
+ */
50
+ tokensPath: string;
51
+ /**
52
+ * Output format for documentation.
53
+ * @default 'html'
54
+ */
55
+ outputFormat?: "html" | "json" | "markdown";
56
+ /**
57
+ * Output directory for generated documentation.
58
+ * @default '.vize/tokens'
59
+ */
60
+ outputDir?: string;
61
+ /**
62
+ * Custom token transformations.
63
+ */
64
+ transforms?: TokenTransform[];
65
+ }
66
+ /**
67
+ * Token transformation function.
68
+ */
69
+ type TokenTransform = (token: DesignToken, path: string[]) => DesignToken;
70
+ /**
71
+ * Parse Style Dictionary tokens file/directory or Tailwind CSS theme variables.
72
+ */
73
+ declare function parseTokens(tokensPath: string): Promise<TokenCategory[]>;
74
+ //#endregion
75
+ //#region src/tokens/preview.d.ts
76
+ type MuseaTokenPreviewKind = "color" | "spacing" | "fontSize" | "fontWeight" | "lineHeight" | "shadow" | "radius" | "opacity" | "zIndex" | "generic";
77
+ interface MuseaTokenPreviewRule {
78
+ kind: MuseaTokenPreviewKind;
79
+ type?: string | string[];
80
+ pathIncludes?: string | string[];
81
+ nameIncludes?: string | string[];
82
+ referencePathIncludes?: string | string[];
83
+ }
84
+ interface MuseaTokenPreviewConfig {
85
+ /**
86
+ * User rules are evaluated before Musea's built-in token preview heuristics.
87
+ * Use `kind: "generic"` to intentionally suppress a preview for matching tokens.
88
+ */
89
+ rules?: MuseaTokenPreviewRule[];
90
+ /** Disable selected preview kinds after custom and built-in rules are evaluated. */
91
+ disabledKinds?: MuseaTokenPreviewKind[];
92
+ }
93
+ interface ResolvedTokenPreview {
94
+ kind: MuseaTokenPreviewKind;
95
+ value: string | number;
96
+ tokenPath: string;
97
+ reference?: {
98
+ path: string;
99
+ token?: DesignToken;
100
+ value?: string | number;
101
+ };
102
+ }
103
+ interface ResolveTokenPreviewInput {
104
+ tokenPath: string;
105
+ token: DesignToken;
106
+ tokenMap?: Record<string, DesignToken>;
107
+ config?: MuseaTokenPreviewConfig;
108
+ }
109
+ declare function resolveTokenPreview(input: ResolveTokenPreviewInput): ResolvedTokenPreview;
110
+ //#endregion
6
111
  //#region src/types/plugin.d.ts
7
112
  type MuseaVueVersion = 0.11 | 1 | 2 | "2.7" | 3 | "legacy";
8
113
  /**
@@ -86,6 +191,11 @@ interface MuseaOptions {
86
191
  * @example 'src/tokens.json', 'src/tokens/', or 'src/styles/main.css'
87
192
  */
88
193
  tokensPath?: string;
194
+ /**
195
+ * Design token preview rules for the gallery.
196
+ * Custom rules run before Musea's built-in previews.
197
+ */
198
+ tokenPreviews?: MuseaTokenPreviewConfig;
89
199
  /**
90
200
  * Project root that should be treated as the outer boundary for path resolution
91
201
  * (notably `tokensPath`). When set, sibling directories of the Vite root that
@@ -137,75 +247,6 @@ interface MuseaOptions {
137
247
  //#region src/plugin/index.d.ts
138
248
  declare function musea(options?: MuseaOptions): Plugin[];
139
249
  //#endregion
140
- //#region src/tokens/parser.d.ts
141
- /**
142
- * Token parsing utilities for Style Dictionary integration.
143
- *
144
- * Thin native binding for design token files (JSON) and directories.
145
- */
146
- /**
147
- * Design token value.
148
- */
149
- interface DesignToken {
150
- value: string | number;
151
- type?: string;
152
- description?: string;
153
- attributes?: Record<string, unknown>;
154
- $tier?: "primitive" | "semantic";
155
- $reference?: string;
156
- $resolvedValue?: string | number;
157
- }
158
- /**
159
- * Token category (e.g., colors, spacing, typography).
160
- */
161
- interface TokenCategory {
162
- name: string;
163
- tokens: Record<string, DesignToken>;
164
- subcategories?: TokenCategory[];
165
- }
166
- /**
167
- * Style Dictionary output format.
168
- */
169
- interface StyleDictionaryOutput {
170
- categories: TokenCategory[];
171
- metadata: {
172
- name: string;
173
- version?: string;
174
- generatedAt: string;
175
- };
176
- }
177
- /**
178
- * Configuration for Style Dictionary integration.
179
- */
180
- interface StyleDictionaryConfig {
181
- /**
182
- * Path to tokens JSON file/directory or Tailwind CSS theme file.
183
- */
184
- tokensPath: string;
185
- /**
186
- * Output format for documentation.
187
- * @default 'html'
188
- */
189
- outputFormat?: "html" | "json" | "markdown";
190
- /**
191
- * Output directory for generated documentation.
192
- * @default '.vize/tokens'
193
- */
194
- outputDir?: string;
195
- /**
196
- * Custom token transformations.
197
- */
198
- transforms?: TokenTransform[];
199
- }
200
- /**
201
- * Token transformation function.
202
- */
203
- type TokenTransform = (token: DesignToken, path: string[]) => DesignToken;
204
- /**
205
- * Parse Style Dictionary tokens file/directory or Tailwind CSS theme variables.
206
- */
207
- declare function parseTokens(tokensPath: string): Promise<TokenCategory[]>;
208
- //#endregion
209
250
  //#region src/tokens/usage.d.ts
210
251
  /**
211
252
  * Scan art file sources for token value matches in `<style>` blocks.
@@ -264,5 +305,5 @@ declare function generateTokensMarkdown(categories: TokenCategory[]): string;
264
305
  */
265
306
  declare function processStyleDictionary(config: StyleDictionaryConfig): Promise<StyleDictionaryOutput>;
266
307
  //#endregion
267
- export { type A11yOptions, type A11yResult, type A11ySummary, type AnalysisApiResponse, type ArtFileInfo, type ArtMetadata, type ArtVariant, type AutogenOptions, type AutogenOutput, type CaptureConfig, type CiConfig, type ComparisonConfig, type CsfOutput, type DesignToken, type GeneratedVariant, MuseaA11yRunner, type MuseaOptions, type MuseaTheme, type MuseaThemeColors, MuseaVrtRunner, type PaletteApiResponse, type PropDefinition, type StyleDictionaryConfig, type StyleDictionaryOutput, type TokenCategory, type TokenUsageMap, type ViewportConfig, type VrtOptions, type VrtResult, type VrtSummary, buildTokenMap, musea as default, musea, generateArtFile, generateTokensHtml, generateTokensMarkdown, generateVrtJsonReport, generateVrtReport, parseTokens, processStyleDictionary, resolveReferences, scanTokenUsage, writeArtFile };
308
+ export { type A11yOptions, type A11yResult, type A11ySummary, type AnalysisApiResponse, type ArtFileInfo, type ArtMetadata, type ArtVariant, type AutogenOptions, type AutogenOutput, type CaptureConfig, type CiConfig, type ComparisonConfig, type CsfOutput, type DesignToken, type GeneratedVariant, MuseaA11yRunner, type MuseaOptions, type MuseaTheme, type MuseaThemeColors, type MuseaTokenPreviewConfig, type MuseaTokenPreviewKind, type MuseaTokenPreviewRule, MuseaVrtRunner, type PaletteApiResponse, type PropDefinition, type ResolvedTokenPreview, type StyleDictionaryConfig, type StyleDictionaryOutput, type TokenCategory, type TokenUsageMap, type ViewportConfig, type VrtOptions, type VrtResult, type VrtSummary, buildTokenMap, musea as default, musea, generateArtFile, generateTokensHtml, generateTokensMarkdown, generateVrtJsonReport, generateVrtReport, parseTokens, processStyleDictionary, resolveReferences, resolveTokenPreview, scanTokenUsage, writeArtFile };
268
309
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/plugin.ts","../src/plugin/index.ts","../src/tokens/parser.ts","../src/tokens/usage.ts","../src/tokens/resolver.ts","../src/tokens/generator.ts"],"mappings":";;;;;;KAEY,eAAA;;;;;UAMK,gBAAA;EACf,SAAA;EACA,WAAA;EACA,UAAA;EACA,UAAA;EACA,MAAA;EACA,WAAA;EACA,cAAA;EACA,YAAA;EACA,IAAA;EACA,aAAA;EACA,SAAA;EACA,MAAA;EACA,YAAA;EACA,OAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA;EACA,MAAA;AAAA;;;;UAMe,UAAA;EARf;EAUA,IAAA;EARA;EAUA,IAAA;EAVM;EAYN,MAAA,EAAQ,gBAAA;AAAA;;;;UAMO,YAAA;EANf;;;;EAWA,OAAA;EAL2B;;;;EAW3B,OAAA;EAyFa;;;;EAnFb,QAAA;EAAA;;;;EAMA,eAAA;EAmBM;;;;EAbN,eAAA;EA0CmD;;;;;;EAlCnD,SAAA;;;;EAKA,GAAA,GAAM,UAAA;EC3Ca;;;;;EDkDnB,UAAA;EClDuD;;;;;AC/BzD;;;;;EF6FE,WAAA;EE1FA;;;;;;;;EFoGA,KAAA,iCAAsC,UAAA,GAAa,UAAA;EE1FvB;;;;;;;;EFoG5B,UAAA;EElGQ;;;;;;AAOV;;;;EFuGE,YAAA;EEtGY;;;;;EF6GZ,UAAA,GAAa,eAAA;AAAA;;;iBCrGC,KAAA,CAAM,OAAA,GAAS,YAAA,GAAoB,MAAA;;;;;;;;;ADzCnD;;UEUiB,WAAA;EACf,KAAA;EACA,IAAA;EACA,WAAA;EACA,UAAA,GAAa,MAAA;EACb,KAAA;EACA,UAAA;EACA,cAAA;AAAA;;;;UAMe,aAAA;EACf,IAAA;EACA,MAAA,EAAQ,MAAA,SAAe,WAAA;EACvB,aAAA,GAAgB,aAAA;AAAA;;;;UAMD,qBAAA;EACf,UAAA,EAAY,aAAA;EACZ,QAAA;IACE,IAAA;IACA,OAAA;IACA,WAAA;EAAA;AAAA;;;;UAOa,qBAAA;EFVf;;;EEcA,UAAA;EFZwB;AAM1B;;;EEYE,YAAA;EF2DsC;;;;EErDtC,SAAA;EFbA;;;EEkBA,UAAA,GAAa,cAAA;AAAA;;;;KAMH,cAAA,IAAkB,KAAA,EAAO,WAAA,EAAa,IAAA,eAAmB,WAAA;;;;iBAK/C,WAAA,CAAY,UAAA,WAAqB,OAAA,CAAQ,aAAA;;;;;;iBCtC/C,cAAA,CACd,QAAA,EAAU,GAAA;EAAc,IAAA;EAAc,QAAA;IAAY,KAAA;IAAe,QAAA;EAAA;AAAA,IACjE,QAAA,EAAU,MAAA,SAAe,WAAA,IACxB,aAAA;;;;;;UCtBc,eAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;AAAA;;;;UAMe,eAAA;EACf,OAAA;EACA,QAAA;EACA,WAAA;EACA,OAAA,EAAS,eAAA;AAAA;;;;KAMC,aAAA,GAAgB,MAAA,SAAe,eAAA;;;;iBAqB3B,aAAA,CAAc,UAAA,EAAY,aAAA,KAAkB,MAAA,SAAe,WAAA;;;AJ7B3E;iBIoCgB,iBAAA,CACd,UAAA,EAAY,aAAA,IACZ,SAAA,EAAW,MAAA,SAAe,WAAA;;;;;;iBC/BZ,kBAAA,CAAmB,UAAA,EAAY,aAAA;AL/B/C;;;AAAA,iBK+JgB,sBAAA,CAAuB,UAAA,EAAY,aAAA;;;;;iBAQ7B,sBAAA,CACpB,MAAA,EAAQ,qBAAA,GACP,OAAA,CAAQ,qBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/tokens/parser.ts","../src/tokens/preview.ts","../src/types/plugin.ts","../src/plugin/index.ts","../src/tokens/usage.ts","../src/tokens/resolver.ts","../src/tokens/generator.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { c as createDevSessionToken, d as resolveInside, f as resolveInsideAny, h as validateDevApiRequest, i as generateGalleryScript, l as decodeUrlComponent, m as serializeScriptValue, n as generateGalleryModule, o as HttpError, p as resolveUrlPathInside, r as generateGalleryBody, s as collectRequestBody, u as parseJsonBody } from "./gallery-DIBlUrB6.mjs";
1
+ import { _ as validateDevApiRequest, a as generateDevGlobalsScript, c as HttpError, d as decodeUrlComponent, f as parseJsonBody, g as serializeScriptValue, h as resolveUrlPathInside, i as generateGalleryScript, l as collectRequestBody, m as resolveInsideAny, n as generateGalleryModule, o as generateGalleryGlobalsScript, p as resolveInside, r as generateGalleryBody, u as createDevSessionToken } from "./gallery-qM8Q_21C.mjs";
2
2
  import { i as MuseaVrtRunner, n as generateVrtJsonReport, r as generateVrtReport } from "./vrt-Cv1PK1EF.mjs";
3
3
  import { t as MuseaA11yRunner } from "./a11y-62l8G1tr.mjs";
4
4
  import { n as writeArtFile, t as generateArtFile } from "./autogen-B7_TO0n5.mjs";
@@ -1405,11 +1405,7 @@ function resolveGallerySourceDir() {
1405
1405
  function toViteFsPath(filePath) {
1406
1406
  return encodeURI(`/@fs${filePath.split(path.sep).join("/")}`);
1407
1407
  }
1408
- function generateDevGlobalsScript(basePath, devSessionToken, themeConfig) {
1409
- const themeScript = themeConfig ? `window.__MUSEA_THEME_CONFIG__=${serializeScriptValue(themeConfig)};` : "";
1410
- return `window.__MUSEA_BASE_PATH__=${serializeScriptValue(basePath)};window.__MUSEA_SESSION_TOKEN__=${serializeScriptValue(devSessionToken)};${themeScript}`;
1411
- }
1412
- async function tryLoadSourceGalleryHtml(devServer, url, basePath, devSessionToken, themeConfig) {
1408
+ async function tryLoadSourceGalleryHtml(devServer, url, basePath, devSessionToken, themeConfig, tokenPreviewConfig) {
1413
1409
  const gallerySourceDir = resolveGallerySourceDir();
1414
1410
  const indexHtmlPath = path.join(gallerySourceDir, "index.html");
1415
1411
  try {
@@ -1420,12 +1416,12 @@ async function tryLoadSourceGalleryHtml(devServer, url, basePath, devSessionToke
1420
1416
  const sourceEntryPath = toViteFsPath(path.join(gallerySourceDir, "main.ts"));
1421
1417
  let html = await fs.promises.readFile(indexHtmlPath, "utf-8");
1422
1418
  html = html.replace("src=\"./main.ts\"", `src="${sourceEntryPath}"`);
1423
- html = html.replace("</head>", `<script>${generateDevGlobalsScript(basePath, devSessionToken, themeConfig)}<\/script></head>`);
1419
+ html = html.replace("</head>", `<script>${generateDevGlobalsScript(basePath, devSessionToken, themeConfig, tokenPreviewConfig)}<\/script></head>`);
1424
1420
  return devServer.transformIndexHtml(url, html);
1425
1421
  }
1426
- async function generateFallbackGalleryHtml(basePath, devSessionToken, themeConfig) {
1427
- const { generateGalleryHtml } = await import("./gallery-DIBlUrB6.mjs").then((n) => n.t);
1428
- return generateGalleryHtml(basePath, devSessionToken, themeConfig);
1422
+ async function generateFallbackGalleryHtml(basePath, devSessionToken, themeConfig, tokenPreviewConfig) {
1423
+ const { generateGalleryHtml } = await import("./gallery-qM8Q_21C.mjs").then((n) => n.t);
1424
+ return generateGalleryHtml(basePath, devSessionToken, themeConfig, tokenPreviewConfig);
1429
1425
  }
1430
1426
  async function serveGalleryAsset(galleryDistDir, requestUrl, res) {
1431
1427
  try {
@@ -1458,7 +1454,7 @@ async function serveGalleryAsset(galleryDistDir, requestUrl, res) {
1458
1454
  * - Art module route
1459
1455
  */
1460
1456
  function registerMiddleware(devServer, ctx) {
1461
- const { basePath, devSessionToken, themeConfig, artFiles } = ctx;
1457
+ const { basePath, devSessionToken, themeConfig, tokenPreviewConfig, artFiles } = ctx;
1462
1458
  devServer.middlewares.use(basePath, async (req, res, next) => {
1463
1459
  const url = req.url || "/";
1464
1460
  if (url === "/" || url === "/index.html" || url.startsWith("/tokens") || url.startsWith("/component/") || url.startsWith("/tests")) {
@@ -1467,18 +1463,18 @@ function registerMiddleware(devServer, ctx) {
1467
1463
  try {
1468
1464
  await fs.promises.access(indexHtmlPath);
1469
1465
  let html = await fs.promises.readFile(indexHtmlPath, "utf-8");
1470
- html = html.replace("</head>", `<script>${generateDevGlobalsScript(basePath, devSessionToken, themeConfig)}<\/script></head>`);
1466
+ html = html.replace("</head>", `<script>${generateDevGlobalsScript(basePath, devSessionToken, themeConfig, tokenPreviewConfig)}<\/script></head>`);
1471
1467
  res.setHeader("Content-Type", "text/html");
1472
1468
  res.end(html);
1473
1469
  return;
1474
1470
  } catch {
1475
- const sourceHtml = await tryLoadSourceGalleryHtml(devServer, url, basePath, devSessionToken, themeConfig);
1471
+ const sourceHtml = await tryLoadSourceGalleryHtml(devServer, url, basePath, devSessionToken, themeConfig, tokenPreviewConfig);
1476
1472
  if (sourceHtml) {
1477
1473
  res.setHeader("Content-Type", "text/html");
1478
1474
  res.end(sourceHtml);
1479
1475
  return;
1480
1476
  }
1481
- const html = await generateFallbackGalleryHtml(basePath, devSessionToken, themeConfig);
1477
+ const html = await generateFallbackGalleryHtml(basePath, devSessionToken, themeConfig, tokenPreviewConfig);
1482
1478
  res.setHeader("Content-Type", "text/html");
1483
1479
  res.end(html);
1484
1480
  return;
@@ -2274,6 +2270,133 @@ async function processStyleDictionary(config) {
2274
2270
  };
2275
2271
  }
2276
2272
  //#endregion
2273
+ //#region src/tokens/preview.ts
2274
+ function resolveTokenPreview(input) {
2275
+ const reference = resolveReference(input.token, input.tokenMap);
2276
+ const value = input.token.$resolvedValue ?? reference?.value ?? input.token.value;
2277
+ const candidates = buildCandidates(input.tokenPath, input.token, reference);
2278
+ const kind = resolveCustomKind(candidates, reference?.path, input.config?.rules) ?? inferPreviewKind(candidates, value);
2279
+ return {
2280
+ kind: new Set(input.config?.disabledKinds ?? []).has(kind) ? "generic" : kind,
2281
+ value,
2282
+ tokenPath: input.tokenPath,
2283
+ reference
2284
+ };
2285
+ }
2286
+ function resolveReference(token, tokenMap) {
2287
+ if (!token.$reference) return void 0;
2288
+ const referencedToken = tokenMap?.[token.$reference];
2289
+ return {
2290
+ path: token.$reference,
2291
+ token: referencedToken,
2292
+ value: referencedToken ? referencedToken.$resolvedValue ?? referencedToken.value : void 0
2293
+ };
2294
+ }
2295
+ function buildCandidates(tokenPath, token, reference) {
2296
+ const candidates = [{
2297
+ tokenPath,
2298
+ name: pathName(tokenPath),
2299
+ token
2300
+ }];
2301
+ if (reference?.token) candidates.push({
2302
+ tokenPath: reference.path,
2303
+ name: pathName(reference.path),
2304
+ token: reference.token
2305
+ });
2306
+ return candidates;
2307
+ }
2308
+ function resolveCustomKind(candidates, referencePath, rules) {
2309
+ for (const rule of rules ?? []) if (matchesRule(rule, candidates, referencePath)) return rule.kind;
2310
+ }
2311
+ function matchesRule(rule, candidates, referencePath) {
2312
+ const checks = [];
2313
+ if (rule.type !== void 0) checks.push(candidates.some((candidate) => typeMatches(candidate, rule.type)));
2314
+ if (rule.pathIncludes !== void 0) checks.push(candidates.some((candidate) => includesAny(candidate.tokenPath, rule.pathIncludes)));
2315
+ if (rule.nameIncludes !== void 0) checks.push(candidates.some((candidate) => includesAny(candidate.name, rule.nameIncludes)));
2316
+ if (rule.referencePathIncludes !== void 0) checks.push(referencePath !== void 0 && includesAny(referencePath, rule.referencePathIncludes));
2317
+ return checks.length > 0 && checks.every(Boolean);
2318
+ }
2319
+ function inferPreviewKind(candidates, value) {
2320
+ if (hasType(candidates, ["color"]) || isColorValue(value)) return "color";
2321
+ if (hasType(candidates, ["shadow", "box-shadow"]) || hasSignal(candidates, ["shadow", "box-shadow"])) return "shadow";
2322
+ if (hasType(candidates, [
2323
+ "z-index",
2324
+ "zindex",
2325
+ "zIndex"
2326
+ ]) || hasSignal(candidates, [
2327
+ "z-index",
2328
+ "zindex",
2329
+ "stacking-order"
2330
+ ])) return "zIndex";
2331
+ if (hasType(candidates, ["opacity"]) || hasSignal(candidates, ["opacity", "alpha"])) return "opacity";
2332
+ if (hasType(candidates, [
2333
+ "border-radius",
2334
+ "borderradius",
2335
+ "radius"
2336
+ ]) || hasSignal(candidates, [
2337
+ "border-radius",
2338
+ "borderradius",
2339
+ "radius",
2340
+ "round",
2341
+ "rounded"
2342
+ ])) return "radius";
2343
+ if (hasType(candidates, ["spacing", "space"]) || hasSignal(candidates, [
2344
+ "spacing",
2345
+ "spasing",
2346
+ "space",
2347
+ "gap",
2348
+ "padding",
2349
+ "margin",
2350
+ "inset"
2351
+ ])) return "spacing";
2352
+ if (hasSignal(candidates, [
2353
+ "font-size",
2354
+ "fontsize",
2355
+ "text-size"
2356
+ ])) return "fontSize";
2357
+ if (hasType(candidates, ["fontweight", "font-weight"]) || hasSignal(candidates, [
2358
+ "font-weight",
2359
+ "fontweight",
2360
+ "weight"
2361
+ ])) return "fontWeight";
2362
+ if (hasType(candidates, ["lineheight", "line-height"]) || hasSignal(candidates, ["line-height", "lineheight"])) return "lineHeight";
2363
+ return "generic";
2364
+ }
2365
+ function hasType(candidates, terms) {
2366
+ return candidates.some((candidate) => typeMatches(candidate, terms));
2367
+ }
2368
+ function hasSignal(candidates, terms) {
2369
+ return candidates.some((candidate) => includesAny(candidate.tokenPath, terms) || includesAny(candidate.name, terms) || candidate.token.type !== void 0 && includesAny(candidate.token.type, terms));
2370
+ }
2371
+ function typeMatches(candidate, expected) {
2372
+ if (!candidate.token.type) return false;
2373
+ return toArray(expected).some((term) => normalize(candidate.token.type) === normalize(term));
2374
+ }
2375
+ function includesAny(value, expected) {
2376
+ const normalizedValue = normalize(value);
2377
+ const compactValue = compact(normalizedValue);
2378
+ return toArray(expected).some((term) => {
2379
+ const normalizedTerm = normalize(term);
2380
+ return normalizedValue.includes(normalizedTerm) || compactValue.includes(compact(normalizedTerm));
2381
+ });
2382
+ }
2383
+ function isColorValue(value) {
2384
+ if (typeof value !== "string") return false;
2385
+ return /^(#|rgb\(|rgba\(|hsl\(|hsla\(|oklch\(|oklab\(|lab\(|lch\(|color\()/i.test(value.trim());
2386
+ }
2387
+ function pathName(tokenPath) {
2388
+ return tokenPath.split(".").at(-1) ?? tokenPath;
2389
+ }
2390
+ function normalize(value) {
2391
+ return value.trim().toLowerCase().replace(/[_\s]+/g, "-");
2392
+ }
2393
+ function compact(value) {
2394
+ return value.replace(/[-.]/g, "");
2395
+ }
2396
+ function toArray(value) {
2397
+ return Array.isArray(value) ? value : [value];
2398
+ }
2399
+ //#endregion
2277
2400
  //#region src/api-tokens.ts
2278
2401
  function resolveTokensPath(ctx) {
2279
2402
  const allowedRoots = [ctx.config.root, ...ctx.scanRoots];
@@ -3423,8 +3546,12 @@ function generateStaticPreviewHtml(art, variantName, previewId, basePath, runtim
3423
3546
  </html>`;
3424
3547
  }
3425
3548
  function injectStaticGlobals(html, ctx, payload) {
3426
- const themeScript = ctx.themeConfig ? `window.__MUSEA_THEME_CONFIG__=${serializeScriptValue(ctx.themeConfig)};` : "";
3427
- const script = `<script>window.__MUSEA_BASE_PATH__=${serializeScriptValue(ctx.basePath)};window.__MUSEA_STATIC__=true;window.__MUSEA_STATIC_PREVIEWS__=${serializeScriptValue(payload.previews)};${themeScript}<\/script>`;
3549
+ const script = `<script>${generateGalleryGlobalsScript({
3550
+ basePath: ctx.basePath,
3551
+ staticPreviews: payload.previews,
3552
+ themeConfig: ctx.themeConfig,
3553
+ tokenPreviewConfig: ctx.tokenPreviewConfig
3554
+ })}<\/script>`;
3428
3555
  return html.includes("</head>") ? html.replace("</head>", `${script}</head>`) : `${script}${html}`;
3429
3556
  }
3430
3557
  function rewriteGalleryBase(html, basePath) {
@@ -3631,6 +3758,7 @@ function musea(options = {}) {
3631
3758
  const storybookOutDir = options.storybookOutDir ?? ".storybook/stories";
3632
3759
  let inlineArt = options.inlineArt ?? false;
3633
3760
  const tokensPath = options.tokensPath;
3761
+ let tokenPreviewConfig = options.tokenPreviews;
3634
3762
  const projectRootOption = options.projectRoot;
3635
3763
  const themeConfig = buildThemeConfig(options.theme);
3636
3764
  const previewCss = options.previewCss ?? [];
@@ -3684,6 +3812,7 @@ function musea(options = {}) {
3684
3812
  if (!options.basePath && mc.basePath) basePath = mc.basePath;
3685
3813
  if (options.storybookCompat === void 0 && mc.storybookCompat !== void 0) storybookCompat = mc.storybookCompat;
3686
3814
  if (options.inlineArt === void 0 && mc.inlineArt !== void 0) inlineArt = mc.inlineArt;
3815
+ if (options.tokenPreviews === void 0 && mc.tokenPreviews !== void 0) tokenPreviewConfig = mc.tokenPreviews;
3687
3816
  }
3688
3817
  vueVersion = resolveStaticPreviewVueVersion(vueVersion, resolvedConfig.plugins);
3689
3818
  virtualState.basePath = basePath;
@@ -3699,6 +3828,7 @@ function musea(options = {}) {
3699
3828
  basePath,
3700
3829
  devSessionToken,
3701
3830
  themeConfig,
3831
+ tokenPreviewConfig,
3702
3832
  artFiles,
3703
3833
  scanRoots,
3704
3834
  resolvedPreviewCss,
@@ -3797,7 +3927,8 @@ function musea(options = {}) {
3797
3927
  resolvedPreviewCss,
3798
3928
  resolvedPreviewSetup,
3799
3929
  devSessionToken,
3800
- themeConfig
3930
+ themeConfig,
3931
+ tokenPreviewConfig
3801
3932
  });
3802
3933
  },
3803
3934
  async transform(code, id) {
@@ -3826,6 +3957,6 @@ function resolveProjectRoot(projectRoot, viteRoot) {
3826
3957
  //#region src/index.ts
3827
3958
  var src_default = musea;
3828
3959
  //#endregion
3829
- export { MuseaA11yRunner, MuseaVrtRunner, buildTokenMap, src_default as default, generateArtFile, generateTokensHtml, generateTokensMarkdown, generateVrtJsonReport, generateVrtReport, musea, parseTokens, processStyleDictionary, resolveReferences, scanTokenUsage, writeArtFile };
3960
+ export { MuseaA11yRunner, MuseaVrtRunner, buildTokenMap, src_default as default, generateArtFile, generateTokensHtml, generateTokensMarkdown, generateVrtJsonReport, generateVrtReport, musea, parseTokens, processStyleDictionary, resolveReferences, resolveTokenPreview, scanTokenUsage, writeArtFile };
3830
3961
 
3831
3962
  //# sourceMappingURL=index.mjs.map