UNPKG

shadcn-vue

Version:
660 lines (659 loc) 17 kB
//#region src/registry/constants.ts const SHADCN_VUE_URL = process.env.SHADCN_VUE_URL ?? "https://shadcn-vue.com"; const REGISTRY_URL = process.env.REGISTRY_URL ?? `${SHADCN_VUE_URL}/r`; const FALLBACK_STYLE = "new-york-v4"; const BASES = [{ name: "reka", label: "Reka UI", description: "Optimized for fast development, easy maintenance, and accessibility.", dependencies: ["reka-ui"] }]; const STYLES = [ { name: "vega", label: "Vega", description: "The classic shadcn/ui look. Clean, neutral, and familiar." }, { name: "nova", label: "Nova", description: "Reduced padding and margins for compact layouts." }, { name: "maia", label: "Maia", description: "Soft and rounded, with generous spacing." }, { name: "lyra", label: "Lyra", description: "Boxy and sharp. Pairs well with mono fonts." }, { name: "mira", label: "Mira", description: "Compact. Made for dense interfaces." }, { name: "luma", label: "Luma", description: "Fluid, luminous, and glassy." }, { name: "sera", label: "Sera", description: "Editorial and typographic." } ]; const FONTS = [ { name: "inter", label: "Inter", family: "Inter", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "geist-sans", label: "Geist", family: "Geist", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "noto-sans", label: "Noto Sans", family: "Noto Sans", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "nunito-sans", label: "Nunito Sans", family: "Nunito Sans", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "figtree", label: "Figtree", family: "Figtree", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Figtree:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "roboto", label: "Roboto", family: "Roboto", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "raleway", label: "Raleway", family: "Raleway", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "dm-sans", label: "DM Sans", family: "DM Sans", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "public-sans", label: "Public Sans", family: "Public Sans", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Public+Sans:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "outfit", label: "Outfit", family: "Outfit", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "jetbrains-mono", label: "JetBrains Mono", family: "JetBrains Mono", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap');", variable: "--font-mono", weight: [ "400", "500", "600", "700" ] }, { name: "playfair-display", label: "Playfair Display", family: "Playfair Display", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700;800;900&display=swap');", variable: "--font-serif", weight: [ "400", "500", "600", "700", "800", "900" ] }, { name: "oxanium", label: "Oxanium", family: "Oxanium", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Oxanium:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "manrope", label: "Manrope", family: "Manrope", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "space-grotesk", label: "Space Grotesk", family: "Space Grotesk", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "montserrat", label: "Montserrat", family: "Montserrat", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "ibm-plex-sans", label: "IBM Plex Sans", family: "IBM Plex Sans", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "source-sans-3", label: "Source Sans 3", family: "Source Sans 3", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Source+Sans+3:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "instrument-sans", label: "Instrument Sans", family: "Instrument Sans", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600;700&display=swap');", variable: "--font-sans", weight: [ "400", "500", "600", "700" ] }, { name: "geist-mono", label: "Geist Mono", family: "Geist Mono", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&display=swap');", variable: "--font-mono", weight: [ "400", "500", "600", "700" ] }, { name: "noto-serif", label: "Noto Serif", family: "Noto Serif", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Noto+Serif:wght@400;500;600;700&display=swap');", variable: "--font-serif", weight: [ "400", "500", "600", "700" ] }, { name: "roboto-slab", label: "Roboto Slab", family: "Roboto Slab", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;500;600;700&display=swap');", variable: "--font-serif", weight: [ "400", "500", "600", "700" ] }, { name: "merriweather", label: "Merriweather", family: "Merriweather", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Merriweather:wght@400;500;600;700&display=swap');", variable: "--font-serif", weight: [ "400", "500", "600", "700" ] }, { name: "lora", label: "Lora", family: "Lora", provider: "google", import: "@import url('https://fonts.googleapis.com/css2?family=Lora:wght@400;500;600;700&display=swap');", variable: "--font-serif", weight: [ "400", "500", "600", "700" ] } ]; const ICON_LIBRARIES$1 = [ { name: "lucide", label: "Lucide", packages: ["@lucide/vue"] }, { name: "tabler", label: "Tabler Icons", packages: ["@tabler/icons-vue"] }, { name: "hugeicons", label: "HugeIcons", packages: ["@hugeicons/vue", "@hugeicons/core-free-icons"] }, { name: "phosphor", label: "Phosphor Icons", packages: ["@phosphor-icons/vue"] }, { name: "remixicon", label: "Remix Icon", packages: ["@remixicon/vue"] } ]; const BASE_COLORS = [ { name: "neutral", label: "Neutral" }, { name: "stone", label: "Stone" }, { name: "zinc", label: "Zinc" }, { name: "mauve", label: "Mauve" }, { name: "olive", label: "Olive" }, { name: "mist", label: "Mist" }, { name: "taupe", label: "Taupe" } ]; const BUILTIN_REGISTRIES = { "@shadcn": `${REGISTRY_URL}/styles/{style}/{name}.json` }; const DEPRECATED_COMPONENTS = [{ name: "toast", deprecatedBy: "sonner", message: "The toast component is deprecated. Use the sonner component instead." }, { name: "toaster", deprecatedBy: "sonner", message: "The toaster component is deprecated. Use the sonner component instead." }]; //#endregion //#region src/utils/icon-libraries.ts const LEGACY_ICON_LIBRARY_PACKAGES = ["lucide-vue-next"]; /** * Get an icon library by name. */ function getIconLibrary(name) { return ICON_LIBRARIES$1.find((lib) => lib.name === name); } /** * Get packages for an icon library. */ function getIconLibraryPackages(name) { const lib = getIconLibrary(name); return lib?.packages ? [...lib.packages] : []; } /** * Set of every package name owned by any supported icon library (including * legacy/renamed ones). Used to scrub icon-library deps from registry-supplied * dependency lists so we can replace them with the user's chosen library. */ function getAllIconLibraryPackages() { const all = new Set(LEGACY_ICON_LIBRARY_PACKAGES); for (const lib of ICON_LIBRARIES$1) for (const pkg of lib.packages) all.add(pkg); return all; } /** * Registry style items (e.g. `styles/<style>/index.json`) hardcode `@lucide/vue` * in their `dependencies` array regardless of which icon library the user * picked. This swaps any known icon-library package in `dependencies` for the * packages of `iconLibrary`, so a user who picked Phosphor doesn't end up with * Lucide installed. * * Returns a new array; the input is not mutated. Falls back to the input * unchanged when `iconLibrary` is unknown so we never silently strip deps. */ function replaceIconLibraryInDependencies(dependencies, iconLibrary) { if (!dependencies?.length) return dependencies ? [...dependencies] : []; if (!iconLibrary) return [...dependencies]; const chosenPackages = getIconLibraryPackages(iconLibrary); if (chosenPackages.length === 0) return [...dependencies]; const knownIconPackages = getAllIconLibraryPackages(); const filtered = dependencies.filter((dep) => !knownIconPackages.has(dep)); for (const pkg of chosenPackages) if (!filtered.includes(pkg)) filtered.push(pkg); return filtered; } const ICON_LIBRARIES = { lucide: { name: "@lucide/vue", package: "@lucide/vue", import: "@lucide/vue" }, radix: { name: "@radix-icons/vue", package: "@radix-icons/vue", import: "@radix-icons/vue" }, tabler: { name: "@tabler/icons-vue", package: "@tabler/icons-vue", import: "@tabler/icons-vue" }, phosphor: { name: "@phosphor-icons/vue", package: "@phosphor-icons/vue", import: "@phosphor-icons/vue" }, hugeicons: { name: "@hugeicons/vue", package: "@hugeicons/vue", import: "@hugeicons/vue" }, remixicon: { name: "@remixicon/vue", package: "@remixicon/vue", import: "@remixicon/vue" } }; //#endregion //#region src/utils/transformers/transform-icons.ts const SOURCE_LIBRARY = "lucide"; const ICON_LIBRARY_IMPORTS = Object.values(ICON_LIBRARIES).map((l) => l.import).filter(Boolean); function transformIcons(opts, registryIcons) { return { type: "codemod", name: "modify import of icon library on user config", transform({ scriptASTs, sfcAST, utils: { traverseScriptAST, traverseTemplateAST } }) { let transformCount = 0; const { config } = opts; if (!config.iconLibrary || !(config.iconLibrary in ICON_LIBRARIES)) return transformCount; const sourceLibrary = SOURCE_LIBRARY; const targetLibrary = config.iconLibrary; if (sourceLibrary === targetLibrary) return transformCount; const targetedIconsMap = /* @__PURE__ */ new Map(); for (const scriptAST of scriptASTs) traverseScriptAST(scriptAST, { visitImportDeclaration(path) { const source = String(path.node.source.value); if (!ICON_LIBRARY_IMPORTS.some((prefix) => source.startsWith(prefix))) return this.traverse(path); let hasChanges = false; for (const specifier of path.node.specifiers ?? []) if (specifier.type === "ImportSpecifier") { const iconName = specifier.imported.name; if (typeof iconName !== "string") continue; const targetedIcon = registryIcons[iconName]?.[targetLibrary] ?? registryIcons[iconName.replace(/Icon$/, "")]?.[targetLibrary]; if (!targetedIcon || targetedIconsMap.has(iconName)) continue; targetedIconsMap.set(iconName, targetedIcon); specifier.imported.name = targetedIcon; hasChanges = true; } if (hasChanges) { path.node.source.value = ICON_LIBRARIES[targetLibrary].import; transformCount++; } return this.traverse(path); } }); if (sfcAST && targetedIconsMap.size > 0) traverseTemplateAST(sfcAST, { enterNode(node) { if (node.type === "VElement" && targetedIconsMap.has(node.rawName)) { node.rawName = targetedIconsMap.get(node.rawName) ?? ""; transformCount++; } } }); return transformCount; } }; } //#endregion //#region src/utils/transformers/transform-menu.ts function transformMenu(opts) { return { type: "codemod", name: "transform menu color classes", transform({ scriptASTs, sfcAST, utils: { traverseScriptAST, traverseTemplateAST } }) { let transformCount = 0; const { config } = opts; const replacement = config.menuColor === "inverted" ? "dark" : ""; const processClassString = (classString) => { if (!classString.includes("cn-menu-target")) return classString; let newText = classString.replace(/cn-menu-target/g, replacement); if (!replacement) { newText = newText.replace(/\s{2,}/g, " "); newText = newText.trim(); } return newText; }; for (const scriptAST of scriptASTs) traverseScriptAST(scriptAST, { visitLiteral(path) { if (path.parent.value.type === "ImportDeclaration") return this.traverse(path); if (typeof path.node.value === "string" && path.node.value.includes("cn-menu-target")) { const original = path.node.value; const processed = processClassString(original); if (processed !== original) { path.node.value = processed; transformCount++; } } return this.traverse(path); }, visitJSXAttribute(path) { if (path.node.name?.name !== "className") return this.traverse(path); const value = path.node.value; if (!value) return this.traverse(path); if (value.type === "Literal" && typeof value.value === "string") { if (value.value.includes("cn-menu-target")) { const original = value.value; const processed = processClassString(original); if (processed !== original) { value.value = processed; transformCount++; } } } return this.traverse(path); } }); if (sfcAST) traverseTemplateAST(sfcAST, { enterNode(node) { if (node.type === "VLiteral" && typeof node.value === "string") { if (node.parent?.type === "VAttribute" && node.parent.key?.type === "VIdentifier" && ["class", "className"].includes(node.parent.key.name)) { if (node.value.includes("cn-menu-target")) { const cleanValue = node.value.replace(/"/g, ""); const processed = processClassString(cleanValue); if (processed !== cleanValue) { node.value = processed; transformCount++; } } } } else if (node.type === "Literal" && typeof node.value === "string") { if (node.value.includes("cn-menu-target")) { const original = node.value; const processed = processClassString(original); if (processed !== original) { node.value = processed; transformCount++; } } } }, leaveNode() {} }); return transformCount; } }; } //#endregion export { BASES as a, DEPRECATED_COMPONENTS as c, ICON_LIBRARIES$1 as d, REGISTRY_URL as f, replaceIconLibraryInDependencies as i, FALLBACK_STYLE as l, STYLES as m, transformIcons as n, BASE_COLORS as o, SHADCN_VUE_URL as p, ICON_LIBRARIES as r, BUILTIN_REGISTRIES as s, transformMenu as t, FONTS as u }; //# sourceMappingURL=transform-menu-CLNZ5vUh.js.map