vibe-design-system 2.8.53 → 2.8.56
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/bin/init.js +11 -3
- package/package.json +1 -1
- package/vds-core-template/story-generator.mjs +63 -25
package/bin/init.js
CHANGED
|
@@ -606,9 +606,17 @@ function runStorybookAdapt(projectRoot) {
|
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
// ADIM 9b — vds.config.js oluştur (yoksa)
|
|
609
|
-
function ensureVdsConfig(projectRoot) {
|
|
609
|
+
function ensureVdsConfig(projectRoot, srcPrefix) {
|
|
610
610
|
const configPath = path.join(projectRoot, "vds.config.js");
|
|
611
611
|
if (fs.existsSync(configPath)) return;
|
|
612
|
+
|
|
613
|
+
// Detect shadcn/ui: if components/ui/ directory exists, add includeGroups by default
|
|
614
|
+
const uiDir = path.join(projectRoot, srcPrefix || "src", "components", "ui");
|
|
615
|
+
const hasShadcn = fs.existsSync(uiDir);
|
|
616
|
+
const includeGroupsLine = hasShadcn
|
|
617
|
+
? ` includeGroups: ["shadcn", "UI", "ui"], // Auto-detected shadcn/ui: generate stories for UI components\n`
|
|
618
|
+
: ` // includeGroups: ["shadcn", "UI"], // Uncomment to generate stories for shadcn/ui primitives\n`;
|
|
619
|
+
|
|
612
620
|
const content = `/**
|
|
613
621
|
* VDS Configuration — auto-created by VDS installer
|
|
614
622
|
* All fields are optional. Remove comments to activate overrides.
|
|
@@ -617,7 +625,7 @@ module.exports = {
|
|
|
617
625
|
// skipList: ["MyHeavyPage"], // Replace the default story skip list entirely
|
|
618
626
|
// extraSkipList: ["OrderCard"], // Add to the default skip list
|
|
619
627
|
// extraIgnoreDirs: ["fixtures"], // Additional dirs to skip during component scan
|
|
620
|
-
};
|
|
628
|
+
${includeGroupsLine}};
|
|
621
629
|
`;
|
|
622
630
|
fs.writeFileSync(configPath, content, "utf-8");
|
|
623
631
|
console.log("⚙️ vds.config.js oluşturuldu.");
|
|
@@ -697,7 +705,7 @@ ensureStoriesDir(projectRoot, srcPrefix);
|
|
|
697
705
|
removeStorybookExamples(projectRoot, srcPrefix);
|
|
698
706
|
|
|
699
707
|
// ADIM 9b
|
|
700
|
-
ensureVdsConfig(projectRoot);
|
|
708
|
+
ensureVdsConfig(projectRoot, srcPrefix);
|
|
701
709
|
|
|
702
710
|
// ADIM 7
|
|
703
711
|
runScan(projectRoot);
|
package/package.json
CHANGED
|
@@ -425,13 +425,21 @@ function componentWrapsVoidElement(source) {
|
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
function toSafeComponentName(name, file) {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
428
|
+
// Convert any string (spaces, hyphens, underscores) to PascalCase.
|
|
429
|
+
// If no separators present, treat as already-PascalCase and just capitalise the first letter.
|
|
430
|
+
const toPascal = (s) => {
|
|
431
|
+
if (!s) return "Component";
|
|
432
|
+
if (!/[-\s_]/.test(s)) return s.charAt(0).toUpperCase() + s.slice(1); // already camel/PascalCase
|
|
433
|
+
return s.replace(/[^A-Za-z0-9]+/g, " ").trim()
|
|
434
|
+
.split(" ").filter(Boolean)
|
|
435
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
436
|
+
.join("") || "Component";
|
|
437
|
+
};
|
|
438
|
+
if (name && typeof name === "string") return toPascal(name);
|
|
431
439
|
const base = (file || "").replace(/\.[^.]+$/, "");
|
|
432
440
|
const parts = base.split(/[\\/]/g);
|
|
433
441
|
const last = parts[parts.length - 1] || "Component";
|
|
434
|
-
return
|
|
442
|
+
return toPascal(last);
|
|
435
443
|
}
|
|
436
444
|
|
|
437
445
|
function parseUnionLiterals(type) {
|
|
@@ -1686,16 +1694,26 @@ function buildProfileChildrenArgLine(profile) {
|
|
|
1686
1694
|
|
|
1687
1695
|
function buildStoryFileContent(comp) {
|
|
1688
1696
|
const componentName = toSafeComponentName(comp.name, comp.file);
|
|
1689
|
-
const fileNoExt = comp.file.replace(/\.(tsx|jsx)$/, "");
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1697
|
+
const fileNoExt = comp.file.replace(/\.(tsx|jsx|ts|js)$/, "");
|
|
1698
|
+
|
|
1699
|
+
// Determine if comp.file is project-root-relative (e.g. "client/src/pages/Foo.tsx")
|
|
1700
|
+
// or components-dir-relative (e.g. "ui/badge.tsx").
|
|
1701
|
+
// Try project-root first; fall back to components-dir.
|
|
1702
|
+
const absoluteFromRoot = path.join(PROJECT_ROOT, comp.file);
|
|
1703
|
+
const absoluteFromComponents = path.join(PROJECT_ROOT, COMPONENTS_REL_DIR, comp.file);
|
|
1704
|
+
const isProjectRelative = fs.existsSync(absoluteFromRoot);
|
|
1705
|
+
const srcPath = isProjectRelative ? absoluteFromRoot : absoluteFromComponents;
|
|
1706
|
+
|
|
1707
|
+
// isPageFile: detect components that live inside a pages/ directory
|
|
1708
|
+
const isPageFile = fileNoExt.includes("/pages/") || fileNoExt.startsWith("pages/");
|
|
1709
|
+
|
|
1710
|
+
// Compute import path relative to src/stories/
|
|
1711
|
+
let importPath;
|
|
1712
|
+
if (isProjectRelative) {
|
|
1713
|
+
// File path is already relative to project root — use directly
|
|
1714
|
+
importPath = path.posix.relative("src/stories", fileNoExt);
|
|
1698
1715
|
} else {
|
|
1716
|
+
// File path is relative to components dir — prefix with components dir
|
|
1699
1717
|
const targetPath = path.posix.join(COMPONENTS_REL_DIR, fileNoExt);
|
|
1700
1718
|
importPath = path.posix.relative("src/stories", targetPath);
|
|
1701
1719
|
}
|
|
@@ -1709,10 +1727,6 @@ function buildStoryFileContent(comp) {
|
|
|
1709
1727
|
// Title: "Module/ComponentName" (category intentionally dropped — folder is the context)
|
|
1710
1728
|
const title = `${group}/${componentName}`;
|
|
1711
1729
|
|
|
1712
|
-
const srcPath = isPageFile
|
|
1713
|
-
? path.join(PROJECT_ROOT, fileNoExt.replace(/^src\//, "src/") + ".tsx")
|
|
1714
|
-
: path.join(PROJECT_ROOT, COMPONENTS_REL_DIR, comp.file);
|
|
1715
|
-
|
|
1716
1730
|
// Read component source once (used for export style, props, CVA parsing)
|
|
1717
1731
|
let source = "";
|
|
1718
1732
|
try {
|
|
@@ -2577,11 +2591,11 @@ function writeFoundationsStories(foundations) {
|
|
|
2577
2591
|
" </p>",
|
|
2578
2592
|
" <p style={{ margin: \"0 0 12px\", fontSize: 12, color: \"#475569\" }}>gap-* values across all components.</p>",
|
|
2579
2593
|
" <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 8 }}>",
|
|
2580
|
-
" {(gapEntries as [string, number][]).map(([val,
|
|
2594
|
+
" {(gapEntries as [string, { count: number; topFiles: string[] }][]).map(([val, data]) => (",
|
|
2581
2595
|
" <span key={val} style={{ display: \"flex\", alignItems: \"center\", gap: 6,",
|
|
2582
2596
|
" background: \"#0a0f1a\", border: \"1px solid #1e293b\", borderRadius: 6, padding: \"5px 10px\", fontSize: 12 }}>",
|
|
2583
2597
|
" <code style={{ color: \"#67e8f9\" }}>gap-{val}</code>",
|
|
2584
|
-
" <span style={{ color: \"#475569\", fontSize: 11 }}>×{count}</span>",
|
|
2598
|
+
" <span style={{ color: \"#475569\", fontSize: 11 }}>×{data.count}</span>",
|
|
2585
2599
|
" </span>",
|
|
2586
2600
|
" ))}",
|
|
2587
2601
|
" </div>",
|
|
@@ -3383,9 +3397,12 @@ function writeCursorRules(components, foundations) {
|
|
|
3383
3397
|
const gridSystem = foundations?.gridSystem;
|
|
3384
3398
|
if (gridSystem) {
|
|
3385
3399
|
lines.push(`## 📐 Spacing & Layout (detected in this project)`);
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3400
|
+
const _gaps = gridSystem.gaps || {};
|
|
3401
|
+
if (Object.keys(_gaps).length > 0) {
|
|
3402
|
+
const gapLine = Object.entries(_gaps)
|
|
3403
|
+
.sort((a,b) => (typeof b[1] === "object" ? b[1].count : b[1]) - (typeof a[1] === "object" ? a[1].count : a[1]))
|
|
3404
|
+
.slice(0,8)
|
|
3405
|
+
.map(([v, d]) => `\`gap-${v}\` ×${typeof d === "object" ? d.count : d}`).join(" · ");
|
|
3389
3406
|
lines.push(`**Common gaps:** ${gapLine}`);
|
|
3390
3407
|
}
|
|
3391
3408
|
if (Object.keys(gridSystem.gridCols || {}).length > 0) {
|
|
@@ -3506,6 +3523,7 @@ function main() {
|
|
|
3506
3523
|
}
|
|
3507
3524
|
}
|
|
3508
3525
|
|
|
3526
|
+
let writtenCount = 0;
|
|
3509
3527
|
for (const comp of components) {
|
|
3510
3528
|
const componentName = toSafeComponentName(comp.name, comp.file);
|
|
3511
3529
|
// Skip unclassified and shadcn/ui primitives (UI group) — they're documented at ui.shadcn.com
|
|
@@ -3515,8 +3533,9 @@ function main() {
|
|
|
3515
3533
|
// Users can override with vds.config.js: includeGroups: ["shadcn"] or includeComponents: ["Button", "Badge"]
|
|
3516
3534
|
const includeGroups = VDS_CONFIG.includeGroups || [];
|
|
3517
3535
|
const includeComponents = VDS_CONFIG.includeComponents || [];
|
|
3518
|
-
|
|
3519
|
-
|
|
3536
|
+
const gLower = g.toLowerCase();
|
|
3537
|
+
if (g === "Uncategorized" || gLower === "ui" || gLower === "shadcn") {
|
|
3538
|
+
const groupIncluded = includeGroups.some((ig) => ig.toLowerCase() === gLower);
|
|
3520
3539
|
const compIncluded = includeComponents.includes(componentName);
|
|
3521
3540
|
if (!groupIncluded && !compIncluded) {
|
|
3522
3541
|
// Clean up leftover story files for components that are now in the skip group
|
|
@@ -3539,7 +3558,10 @@ function main() {
|
|
|
3539
3558
|
const storyPath = path.join(STORIES_DIR, storyFileName);
|
|
3540
3559
|
if (SKIP_LIST.includes(componentName)) continue;
|
|
3541
3560
|
const requiredCount = Array.isArray(comp.props) ? comp.props.filter((p) => p.required === true).length : 0;
|
|
3542
|
-
if (requiredCount > 3)
|
|
3561
|
+
if (requiredCount > 3) {
|
|
3562
|
+
console.log(`[VDS] ${componentName} → skipped (${requiredCount} required props — too complex to auto-generate)`);
|
|
3563
|
+
continue;
|
|
3564
|
+
}
|
|
3543
3565
|
|
|
3544
3566
|
// Never overwrite existing story files — only create new ones
|
|
3545
3567
|
// To regenerate a story: delete the file and re-run VDS
|
|
@@ -3551,6 +3573,22 @@ function main() {
|
|
|
3551
3573
|
if (content == null) continue;
|
|
3552
3574
|
fs.writeFileSync(storyPath, content, "utf-8");
|
|
3553
3575
|
console.log(`[VDS] Wrote ${path.relative(PROJECT_ROOT, storyPath)}`);
|
|
3576
|
+
writtenCount++;
|
|
3577
|
+
}
|
|
3578
|
+
|
|
3579
|
+
// Summary
|
|
3580
|
+
if (writtenCount === 0 && components.length > 0) {
|
|
3581
|
+
const hasShadcnGroup = components.some(c => {
|
|
3582
|
+
const gr = (c.group || "").toLowerCase();
|
|
3583
|
+
return gr === "shadcn" || gr === "ui";
|
|
3584
|
+
});
|
|
3585
|
+
console.log("[VDS] ⚠️ No new component stories were generated.");
|
|
3586
|
+
if (hasShadcnGroup && (VDS_CONFIG.includeGroups || []).length === 0) {
|
|
3587
|
+
console.log("[VDS] Tip: shadcn/ui components detected. Add to vds.config.js:");
|
|
3588
|
+
console.log('[VDS] includeGroups: ["shadcn", "UI"]');
|
|
3589
|
+
}
|
|
3590
|
+
} else if (writtenCount > 0) {
|
|
3591
|
+
console.log(`[VDS] ✓ Generated ${writtenCount} new component stories.`);
|
|
3554
3592
|
}
|
|
3555
3593
|
}
|
|
3556
3594
|
|