vibe-design-system 2.8.2 → 2.8.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-design-system",
3
- "version": "2.8.2",
3
+ "version": "2.8.3",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -951,6 +951,17 @@ function writeVdsGeneratedComponents(suggestions) {
951
951
 
952
952
  let bodyJsx;
953
953
  const tokens = [];
954
+ // Known shadcn/UI component names — not Lucide icons
955
+ const KNOWN_UI_COMPONENTS = new Set([
956
+ "Button", "Card", "CardHeader", "CardTitle", "CardContent", "CardFooter",
957
+ "Input", "Label", "Textarea", "Select", "Checkbox", "Switch", "Badge",
958
+ "Avatar", "Dialog", "Sheet", "Drawer", "Tooltip", "Popover", "Tabs",
959
+ "Table", "Accordion", "Alert", "Toast", "Form", "Skeleton", "Separator",
960
+ "Progress", "Slider", "RadioGroup", "Toggle", "Command", "Calendar",
961
+ "DropdownMenu", "ContextMenu", "NavigationMenu", "Menubar", "HoverCard",
962
+ "Collapsible", "ScrollArea", "AspectRatio", "Carousel", "Resizable",
963
+ "Link", "Nav", "Header", "Footer", "Section", "Container", "Wrapper",
964
+ ]);
954
965
  if (s.fullJsx && s.fullJsx.trim().length > 0) {
955
966
  bodyJsx = flattenJsx(s.fullJsx);
956
967
  bodyJsx = convertHtmlStyleToReact(bodyJsx);
@@ -958,17 +969,28 @@ function writeVdsGeneratedComponents(suggestions) {
958
969
  const lucideTags = [];
959
970
  const uiTags = [];
960
971
  for (const tag of componentTags) {
961
- if (/^[A-Z][a-z0-9]+$/.test(tag) && tag.length > 2) lucideTags.push(tag);
962
- else uiTags.push(tag);
972
+ if (KNOWN_UI_COMPONENTS.has(tag)) {
973
+ uiTags.push(tag);
974
+ } else if (/^[A-Z][a-zA-Z0-9]+$/.test(tag) && tag.length > 2) {
975
+ lucideTags.push(tag); // likely a Lucide icon or unknown component
976
+ } else {
977
+ uiTags.push(tag);
978
+ }
979
+ }
980
+ if (lucideTags.length > 0) {
981
+ bodyJsx = applyLucideNamespace(bodyJsx, lucideTags);
982
+ }
983
+ const importLines = ['import React from "react";'];
984
+ if (bodyJsx.includes("motion.") || bodyJsx.includes("<motion")) {
985
+ importLines.push('import { motion } from "framer-motion";');
986
+ }
987
+ if (lucideTags.length > 0) {
988
+ importLines.push('import * as LucideIcons from "lucide-react";');
989
+ }
990
+ for (const tag of uiTags) {
991
+ if (!KNOWN_UI_COMPONENTS.has(tag)) continue;
992
+ importLines.push(`import { ${tag} } from "@/components/ui/${toKebab(tag)}";`);
963
993
  }
964
- bodyJsx = applyLucideNamespace(bodyJsx, lucideTags);
965
- const standardImports = [
966
- 'import React from "react";',
967
- 'import { motion } from "framer-motion";',
968
- 'import * as LucideIcons from "lucide-react";',
969
- ];
970
- const uiImportLines = uiTags.map((tag) => `import { ${tag} } from "@/components/ui/${toKebab(tag)}";`);
971
- const importLines = [...standardImports, ...uiImportLines];
972
994
  const content = importLines.join("\n") + "\n\n" +
973
995
  `export function ${componentName}() {\n return (\n ` +
974
996
  bodyJsx.replace(/\n/g, "\n ") + "\n );\n}\n";
@@ -978,16 +1000,7 @@ function writeVdsGeneratedComponents(suggestions) {
978
1000
  const tagName = s.tagName || "div";
979
1001
  const className = s.pattern || "";
980
1002
  bodyJsx = `<${tagName} className="${className.replace(/"/g, '\\"')}">\n {null}\n </${tagName}>`;
981
- const content = `import React from "react";
982
- import { motion } from "framer-motion";
983
- import * as LucideIcons from "lucide-react";
984
-
985
- export function ${componentName}() {
986
- return (
987
- ${bodyJsx}
988
- );
989
- }
990
- `;
1003
+ const content = `import React from "react";\n\nexport function ${componentName}() {\n return (\n ${bodyJsx}\n );\n}\n`;
991
1004
  fs.writeFileSync(fullPath, content, "utf-8");
992
1005
  tokens.push(...(className || "").split(/\s+/).filter(Boolean));
993
1006
  }
@@ -995,8 +1008,9 @@ export function ${componentName}() {
995
1008
  entries.push({
996
1009
  file: relPath,
997
1010
  name: componentName.replace(/([A-Z])/g, " $1").trim(),
998
- group: "VDS Generated",
999
- category: "Extracted",
1011
+ exportName: componentName,
1012
+ group: "Generated",
1013
+ category: "Generated",
1000
1014
  description: "Auto-extracted from repeated className patterns.",
1001
1015
  tokens: [...new Set(tokens)],
1002
1016
  occurrences: s.occurrences ?? 0,
@@ -1635,6 +1649,7 @@ function scan() {
1635
1649
  engineer: getGitEngineer(),
1636
1650
  scannedAt: new Date().toISOString(),
1637
1651
  totalComponents: results.length,
1652
+ componentsRelDir: COMPONENTS_DIR ? path.relative(PROJECT_ROOT, COMPONENTS_DIR).replace(/\\/g, "/") : "src/components",
1638
1653
  components: results,
1639
1654
  foundations,
1640
1655
  componentSuggestions,
@@ -22,6 +22,8 @@ const STORIES_DIR = path.join(SRC_DIR, "stories");
22
22
 
23
23
  // Filled in main() after reading vds-output.json so helpers (buildSpecialStories) can see foundations data (e.g. buttonUsage).
24
24
  let FOUNDATIONS_DATA = null;
25
+ // componentsRelDir from vds-output.json — defaults to "src/components"
26
+ let COMPONENTS_REL_DIR = "src/components";
25
27
 
26
28
  // CSS is loaded from .storybook/preview.tsx — never add CSS import to story files.
27
29
 
@@ -1052,12 +1054,18 @@ function buildRecipeStoryContent(comp, componentName, importPath, title, source,
1052
1054
  function buildStoryFileContent(comp) {
1053
1055
  const componentName = toSafeComponentName(comp.name, comp.file);
1054
1056
  const fileNoExt = comp.file.replace(/\.(tsx|jsx)$/, "");
1057
+ // Compute import path relative to src/stories/ using the actual components directory.
1055
1058
  let importPath = "";
1056
- if (fileNoExt.startsWith("pages/")) {
1057
- importPath = "../" + fileNoExt; // Sonuç: "../pages/Home" olacak
1059
+ const isPageFile = fileNoExt.startsWith("pages/") || fileNoExt.startsWith("src/pages/");
1060
+ if (isPageFile) {
1061
+ const normalized = fileNoExt.replace(/^src\//, "");
1062
+ importPath = path.posix.relative("src/stories", normalized);
1058
1063
  } else {
1059
- importPath = "../components/" + fileNoExt; // Sonuç: "../components/ui/button" olacak
1064
+ const targetPath = path.posix.join(COMPONENTS_REL_DIR, fileNoExt);
1065
+ importPath = path.posix.relative("src/stories", targetPath);
1060
1066
  }
1067
+ if (!importPath.startsWith(".")) importPath = "./" + importPath;
1068
+
1061
1069
  const group = comp.group || "Components";
1062
1070
  const category = comp.category || null;
1063
1071
  const titleParts = [group, category, componentName].filter(Boolean);
@@ -1067,9 +1075,9 @@ function buildStoryFileContent(comp) {
1067
1075
  const variantProp = props.find((p) => p.name === "variant");
1068
1076
  let variants = parseUnionLiterals(variantProp && variantProp.type);
1069
1077
 
1070
- const srcPath = comp.file.startsWith("pages/")
1071
- ? path.join(SRC_DIR, comp.file)
1072
- : path.join(SRC_DIR, "components", comp.file);
1078
+ const srcPath = isPageFile
1079
+ ? path.join(PROJECT_ROOT, fileNoExt.replace(/^src\//, "src/") + ".tsx")
1080
+ : path.join(PROJECT_ROOT, COMPONENTS_REL_DIR, comp.file);
1073
1081
 
1074
1082
  // Fallback: if manifest doesn't have variant metadata yet, parse cva() directly from component file.
1075
1083
  if (!variants.length) {
@@ -1105,7 +1113,7 @@ function buildStoryFileContent(comp) {
1105
1113
  }
1106
1114
  const exportStyle = detectExportStyle(source, componentName);
1107
1115
  const omitChildren = componentWrapsVoidElement(source);
1108
- const isPage = comp.file.startsWith("pages/");
1116
+ const isPage = isPageFile;
1109
1117
 
1110
1118
  // Props: manifest or parse from source for default args (LucideIcon, array types, ReactNode, contextual placeholders)
1111
1119
  const effectiveProps = Array.isArray(comp.props) && comp.props.length > 0 ? comp.props : parsePropsFromSource(source);
@@ -1499,6 +1507,7 @@ function main() {
1499
1507
  }
1500
1508
  const raw = fs.readFileSync(VDS_OUTPUT, "utf-8");
1501
1509
  const data = JSON.parse(raw);
1510
+ COMPONENTS_REL_DIR = data.componentsRelDir || "src/components";
1502
1511
  const components = Array.isArray(data.components) ? data.components : [];
1503
1512
  const foundations = data.foundations || null;
1504
1513
  FOUNDATIONS_DATA = foundations;