vibe-design-system 2.5.32 → 2.5.34

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 CHANGED
@@ -253,7 +253,7 @@ function addScripts(projectRoot) {
253
253
  changed = true;
254
254
  }
255
255
  if (!scripts["vds:stories"]) {
256
- scripts["vds:stories"] = "node vds-core/scan.mjs && node vds-core/story-generator.mjs && node vds-core/setup-storybook-providers.mjs";
256
+ scripts["vds:stories"] = "node vds-core/scan.mjs && node vds-core/story-generator.mjs && node vds-core/setup-storybook-providers.mjs && node vds-core/storybook-adapt.mjs";
257
257
  changed = true;
258
258
  }
259
259
  if (!scripts["vds:watch"]) {
@@ -340,6 +340,18 @@ function runSetupStorybookProviders(projectRoot) {
340
340
  if (r.status !== 0) process.exitCode = r.status ?? 1;
341
341
  }
342
342
 
343
+ // ADIM 7c — Storybook adapt: mock problematic imports (server-only, next/*) so components load
344
+ function runStorybookAdapt(projectRoot) {
345
+ const adaptPath = path.join(projectRoot, "vds-core", "storybook-adapt.mjs");
346
+ if (!fs.existsSync(adaptPath)) return;
347
+ const r = spawnSync("node", [adaptPath], {
348
+ cwd: projectRoot,
349
+ stdio: "inherit",
350
+ shell: false,
351
+ });
352
+ if (r.status !== 0) process.exitCode = r.status ?? 1;
353
+ }
354
+
343
355
  // ADIM 9 — Storybook örnek dosyalarını sil
344
356
  function removeStorybookExamples(projectRoot) {
345
357
  const storiesDir = path.join(projectRoot, "src", "stories");
@@ -394,6 +406,7 @@ removeStorybookExamples(projectRoot);
394
406
  runScan(projectRoot);
395
407
  runStoryGenerator(projectRoot);
396
408
  runSetupStorybookProviders(projectRoot);
409
+ runStorybookAdapt(projectRoot);
397
410
 
398
411
  // ADIM 8
399
412
  console.log("\n✅ VDS kuruldu!");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-design-system",
3
- "version": "2.5.32",
3
+ "version": "2.5.34",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,7 +51,7 @@ To see **live renders** of components in the dashboard (isolated, no app chrome)
51
51
  ```bash
52
52
  npm run vds:stories
53
53
  ```
54
- Script (`package.json`): `node vds-core/scan.mjs && node vds-core/story-generator.mjs && node vds-core/setup-storybook-providers.mjs`
54
+ Script: `scan.mjs` `story-generator.mjs` `setup-storybook-providers.mjs` → **`storybook-adapt.mjs`** (dönüştürücü: sorunlu import'ları mock'lar, çözülemeyenleri uyarır).
55
55
 
56
56
  - **Provider'lar:** `vds:stories` içinde zaten çalışır; ayrıca `node vds-core/setup-storybook-providers.mjs` çalıştırmanıza gerek yok. Hooks (useTimer, useSidebar, useCircles, useAuth, useSearch) and inject the matching providers into `.storybook/preview.ts`. Kalan "undefined (reading 'x')" hatalarında ilgili story'de args veya mock state ekleyin.
57
57
 
@@ -67,12 +67,13 @@ VDS, **tek komutla** projenizin design system'ını Storybook'ta stilleriyle eş
67
67
 
68
68
  Kullanıcının her projede ayrı ayrı provider eklemesi, manuel story düzeltmesi veya birden fazla komut çalıştırması gerekmez. Nadir kalan hatalar (belirli bir component'ın özel context'i) story dosyasında args/mock ile giderilir.
69
69
 
70
- **"Failed to fetch dynamically imported module"** genelde o story veya component dosyasındaki hatalı/eksik import'tan kaynaklanır; ilgili .stories.tsx veya component'ı kontrol edin veya o component'ı VDS skip listesine ekleyin.
70
+ **"Failed to fetch dynamically imported module"** artık manuel adım gerektirmez: story'ler dinamik import ile üretilir; component yüklenemezse canvas'ta "Component could not be loaded (import error)." mesajı gösterilir, Storybook çökmez.
71
71
 
72
72
  ## Layout
73
73
 
74
74
  - `vds-core/scan.mjs` — Projeyi tarar (src/components, CSS, Tailwind). `vds-output.json` ve `public/vds-output.json` yazar.
75
75
  - `vds-core/story-generator.mjs` — `vds-output.json`'dan story'leri üretir; varsayılan args: filters/dateRange, sayı, tarih, modal/drawer için isOpen/open: true, onClose/onSave vb. no-op, circle/user/nav/allocation mock objeleri (visibility, path hatalarını önler).
76
76
  - `vds-core/setup-storybook-providers.mjs` — Hook ve react-dnd kullanımını tespit eder, `.storybook/preview` decorator'larına provider ekler.
77
+ - `vds-core/storybook-adapt.mjs` — **Dönüştürücü:** src/ içindeki import'ları tarar; Storybook'ta yüklenmeyen paketleri (server-only, next/headers, next/navigation vb.) mock'lar, `.storybook/mocks/` yazar ve Vite alias'larını ekler. Göreli import'ları kontrol eder, çözülemeyenleri uyarır.
77
78
  - `vds-core/VdsPreview.tsx` — İsteğe bağlı; `/vds-preview` ile dashboard canlı component önizlemesi yapar.
78
79
  - Dashboard UI `/vds-output.json` okur; Foundations + Component Library gösterir.
@@ -992,32 +992,17 @@ function buildStoryFileContent(comp) {
992
992
 
993
993
  const lines = [];
994
994
  lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
995
- if (useReactNodeChildrenRender || needReact) {
996
- lines.push(`import React from "react";`);
997
- }
995
+ lines.push(`import React from "react";`);
998
996
  if (lucideImports.length > 0) {
999
997
  lines.push(`import { ${lucideImports.join(", ")} } from "lucide-react";`);
1000
998
  }
1001
999
 
1002
- if (isPage && exportStyle !== "default") {
1003
- lines.push(`import * as Named from "${importPath}";`);
1004
- lines.push(`const ComponentRef = Named["${componentName}"] ?? Named.default;`);
1005
- } else if (exportStyle === "default") {
1006
- lines.push(`import ${componentName} from "${importPath}";`);
1007
- lines.push(`const ComponentRef = ${componentName};`);
1008
- } else if (exportStyle === "named" || exportStyle === "unknown") {
1009
- lines.push(`import { ${componentName} } from "${importPath}";`);
1010
- lines.push(`const ComponentRef = ${componentName};`);
1011
- } else {
1012
- const defaultAlias = `${componentName}Default`;
1013
- const namedAlias = `${componentName}Named`;
1014
- lines.push(
1015
- `import ${defaultAlias}, { ${componentName} as ${namedAlias} } from "${importPath}";`,
1016
- );
1017
- lines.push(`const ComponentRef = ${namedAlias} ?? ${defaultAlias};`);
1018
- }
1019
-
1000
+ // Dynamic import + catch so "Failed to fetch dynamically imported module" shows a fallback instead of breaking Storybook
1001
+ const loadFallback = `() => React.createElement('div', { style: { padding: 16, color: '#666', fontSize: 14 } }, 'Component could not be loaded (import error).')`;
1002
+ const getDefault = `(m) => ({ default: m["${componentName}"] ?? m.default })`;
1003
+ lines.push(`const ComponentRef = React.lazy(() => import(/* @vite-ignore */ "${importPath}").then(${getDefault}).catch(() => ({ default: ${loadFallback} })));`);
1020
1004
  lines.push("");
1005
+
1021
1006
  lines.push(`const meta = {`);
1022
1007
  lines.push(` title: ${JSON.stringify(title)},`);
1023
1008
  lines.push(` component: ComponentRef,`);
@@ -1042,10 +1027,10 @@ function buildStoryFileContent(comp) {
1042
1027
  return lines.join("\n");
1043
1028
  }
1044
1029
 
1045
- // Generic variant-based stories render real component with args (omit children for img/void)
1030
+ // Wrap in Suspense so lazy load errors render fallback instead of crashing
1046
1031
  const renderLine = useReactNodeChildrenRender
1047
- ? ` render: (args) => React.createElement(ComponentRef, { ...args, children: args.children || React.createElement('span', null, 'Example') }),`
1048
- : ` render: (args) => <ComponentRef {...args} />,`;
1032
+ ? ` render: (args) => React.createElement(React.Suspense, { fallback: null }, React.createElement(ComponentRef, { ...args, children: args.children || React.createElement('span', null, 'Example') })),`
1033
+ : ` render: (args) => React.createElement(React.Suspense, { fallback: null }, React.createElement(ComponentRef, args)),`;
1049
1034
  const childrenArgLine = (label) => (!omitChildren && !useReactNodeChildrenRender ? ` children: ${JSON.stringify(label)},` : null);
1050
1035
 
1051
1036
  if (!variants.length) {
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * VDS — Storybook adapter: makes components load in Storybook by mocking
4
+ * problematic imports (server-only, next/*, etc.) and wiring Vite aliases.
5
+ *
6
+ * Run from project root: node vds-core/storybook-adapt.mjs
7
+ * Runs automatically as part of npm run vds:stories.
8
+ */
9
+ import fs from "fs";
10
+ import path from "path";
11
+ import { fileURLToPath } from "url";
12
+
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+ const PROJECT_ROOT = path.join(__dirname, "..");
15
+ const SRC_DIR = path.join(PROJECT_ROOT, "src");
16
+ const STORYBOOK_DIR = path.join(PROJECT_ROOT, ".storybook");
17
+ const MOCKS_DIR = path.join(STORYBOOK_DIR, "mocks");
18
+
19
+ const IGNORE_DIRS = new Set(["node_modules", "dist", ".next", "build", ".storybook", "stories"]);
20
+
21
+ // Packages that often break in Storybook (browser); we mock them so the component can load.
22
+ const KNOWN_PROBLEMATIC = new Set([
23
+ "server-only",
24
+ "next/headers",
25
+ "next/navigation",
26
+ "next/server",
27
+ "next/cache",
28
+ "next/dist/...",
29
+ ]);
30
+
31
+ function getAllSourceFiles(dir, baseDir = dir) {
32
+ if (!fs.existsSync(dir)) return [];
33
+ const out = [];
34
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
35
+ for (const e of entries) {
36
+ const full = path.join(dir, e.name);
37
+ const rel = path.relative(baseDir, full).replace(/\\/g, "/");
38
+ if (e.isDirectory()) {
39
+ if (IGNORE_DIRS.has(e.name)) continue;
40
+ out.push(...getAllSourceFiles(full, baseDir));
41
+ } else if (/\.(tsx?|jsx?)$/i.test(e.name)) {
42
+ out.push(rel);
43
+ }
44
+ }
45
+ return out;
46
+ }
47
+
48
+ /** Extract import specifiers (package or path) from file content. */
49
+ function extractImports(content) {
50
+ const specifiers = new Set();
51
+ const re = /from\s+["']([^"']+)["']/g;
52
+ let m;
53
+ while ((m = re.exec(content)) !== null) {
54
+ specifiers.add(m[1]);
55
+ }
56
+ const re2 = /import\s+["']([^"']+)["']\s*;/g;
57
+ while ((m = re2.exec(content)) !== null) {
58
+ specifiers.add(m[1]);
59
+ }
60
+ return specifiers;
61
+ }
62
+
63
+ /** Check if this import is known to break in Storybook. */
64
+ function isProblematic(spec) {
65
+ if (spec.startsWith(".") || spec.startsWith("@/")) return false;
66
+ if (KNOWN_PROBLEMATIC.has(spec)) return true;
67
+ if (spec.startsWith("next/")) return true;
68
+ if (spec === "server-only") return true;
69
+ return false;
70
+ }
71
+
72
+ function collectProblematicImports(projectRoot) {
73
+ const srcDir = path.join(projectRoot, "src");
74
+ if (!fs.existsSync(srcDir)) return new Set();
75
+ const files = getAllSourceFiles(srcDir, srcDir).map((r) => path.join(projectRoot, "src", r));
76
+ const found = new Set();
77
+ for (const file of files) {
78
+ try {
79
+ const content = fs.readFileSync(file, "utf-8");
80
+ for (const spec of extractImports(content)) {
81
+ if (isProblematic(spec)) found.add(spec);
82
+ }
83
+ } catch (_) {}
84
+ }
85
+ return found;
86
+ }
87
+
88
+ /** Check relative imports resolve to a file; report unresolved. */
89
+ function reportUnresolvedImports(projectRoot) {
90
+ const srcDir = path.join(projectRoot, "src");
91
+ if (!fs.existsSync(srcDir)) return;
92
+ const files = getAllSourceFiles(srcDir, srcDir).map((r) => path.join(projectRoot, "src", r));
93
+ for (const file of files) {
94
+ try {
95
+ const content = fs.readFileSync(file, "utf-8");
96
+ const dir = path.dirname(file);
97
+ for (const spec of extractImports(content)) {
98
+ if (!spec.startsWith(".")) continue;
99
+ const resolved = path.resolve(dir, spec);
100
+ const exists =
101
+ fs.existsSync(resolved) ||
102
+ [".tsx", ".ts", ".jsx", ".js"].some((ext) => fs.existsSync(resolved + ext)) ||
103
+ ["/index.tsx", "/index.ts", "/index.js"].some((ext) => fs.existsSync(resolved + ext));
104
+ if (!exists) {
105
+ const rel = path.relative(projectRoot, file);
106
+ console.warn("[VDS] Unresolved import in " + rel + ": " + spec);
107
+ }
108
+ }
109
+ } catch (_) {}
110
+ }
111
+ }
112
+
113
+ /** Filename-safe alias for a specifier (e.g. next/headers -> next-headers). */
114
+ function mockFileName(spec) {
115
+ return spec.replace(/[@/\\]/g, "-") + ".js";
116
+ }
117
+
118
+ /** Generate mock module content for a given specifier. */
119
+ function getMockContent(spec) {
120
+ if (spec === "server-only") {
121
+ return "// Mock for Storybook: server-only has no runtime export.\nexport {};\n";
122
+ }
123
+ if (spec.startsWith("next/headers") || spec === "next/headers") {
124
+ return `// Mock for Storybook: next/headers
125
+ export function headers() { return new Headers(); }
126
+ export function cookies() { return { get: () => ({ value: '' }), getAll: () => [] }; }
127
+ export function draftMode() { return { isEnabled: false }; }
128
+ `;
129
+ }
130
+ if (spec.startsWith("next/navigation") || spec === "next/navigation") {
131
+ return `// Mock for Storybook: next/navigation
132
+ export function useRouter() {
133
+ return { push: () => {}, replace: () => {}, back: () => {}, forward: () => {}, refresh: () => {},
134
+ prefetch: () => {}, pathname: '/', query: {}, asPath: '/' };
135
+ }
136
+ export function usePathname() { return '/'; }
137
+ export function useSearchParams() { return new URLSearchParams(); }
138
+ export function useParams() { return {}; }
139
+ export function redirect() {}
140
+ export function notFound() {}
141
+ export const permanentRedirect = redirect;
142
+ `;
143
+ }
144
+ if (spec.startsWith("next/server") || spec === "next/server") {
145
+ return `// Mock for Storybook: next/server
146
+ export function NextResponse() {}
147
+ NextResponse.json = (v) => ({ body: JSON.stringify(v), headers: {} });
148
+ NextResponse.redirect = () => ({});
149
+ export function NextRequest() {}
150
+ `;
151
+ }
152
+ if (spec.startsWith("next/cache") || spec === "next/cache") {
153
+ return `// Mock for Storybook: next/cache
154
+ export function unstable_cache(fn) { return fn; }
155
+ export function revalidateTag() {}
156
+ export function revalidatePath() {}
157
+ `;
158
+ }
159
+ return "// Mock for Storybook\nexport {};\nexport default {};\n";
160
+ }
161
+
162
+ function ensureMocksDir(projectRoot) {
163
+ const dir = path.join(projectRoot, ".storybook", "mocks");
164
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
165
+ return dir;
166
+ }
167
+
168
+ function writeMocks(projectRoot, specifiers) {
169
+ const dir = ensureMocksDir(projectRoot);
170
+ for (const spec of specifiers) {
171
+ const name = mockFileName(spec);
172
+ const filePath = path.join(dir, name);
173
+ fs.writeFileSync(filePath, getMockContent(spec), "utf-8");
174
+ }
175
+ }
176
+
177
+ function getMainPath(projectRoot) {
178
+ const sb = path.join(projectRoot, ".storybook");
179
+ for (const name of ["main.ts", "main.tsx", "main.js", "main.jsx"]) {
180
+ const p = path.join(sb, name);
181
+ if (fs.existsSync(p)) return p;
182
+ }
183
+ return null;
184
+ }
185
+
186
+ /** Inject alias entries into .storybook/main.* viteFinal. */
187
+ function injectAliases(projectRoot, specifiers) {
188
+ const mainPath = getMainPath(projectRoot);
189
+ if (!mainPath) return;
190
+ let content = fs.readFileSync(mainPath, "utf-8");
191
+ const firstMock = mockFileName([...specifiers][0]);
192
+ if (content.includes(".storybook/mocks") && content.includes(firstMock)) return;
193
+
194
+ const aliasLines = [];
195
+ for (const spec of specifiers) {
196
+ const mockRel = `.storybook/mocks/${mockFileName(spec)}`;
197
+ aliasLines.push(`"${spec.replace(/"/g, '\\"')}": path.resolve(process.cwd(), "${mockRel}")`);
198
+ }
199
+ const newAliases = aliasLines.join(",\n ");
200
+ const pattern = /("@":\s*path\.resolve\(process\.cwd\(\),\s*"src"\))(\s*)(\})/;
201
+ if (pattern.test(content)) {
202
+ content = content.replace(pattern, `$1,\n ${newAliases}$2$3`);
203
+ fs.writeFileSync(mainPath, content, "utf-8");
204
+ }
205
+ }
206
+
207
+ function main() {
208
+ const projectRoot = PROJECT_ROOT;
209
+ if (!fs.existsSync(path.join(projectRoot, ".storybook"))) {
210
+ console.log("[VDS] .storybook not found; skip storybook-adapt.");
211
+ return;
212
+ }
213
+ reportUnresolvedImports(projectRoot);
214
+ const problematic = collectProblematicImports(projectRoot);
215
+ if (problematic.size === 0) return;
216
+ writeMocks(projectRoot, problematic);
217
+ injectAliases(projectRoot, problematic);
218
+ console.log("[VDS] Storybook adapt: mocked", [...problematic].join(", "));
219
+ }
220
+
221
+ main();
@@ -14,6 +14,7 @@ function run() {
14
14
  execSync('node vds-core/scan.mjs', { stdio: 'inherit', cwd: ROOT });
15
15
  execSync('node vds-core/story-generator.mjs', { stdio: 'inherit', cwd: ROOT });
16
16
  execSync('node vds-core/setup-storybook-providers.mjs', { stdio: 'inherit', cwd: ROOT });
17
+ execSync('node vds-core/storybook-adapt.mjs', { stdio: 'inherit', cwd: ROOT });
17
18
  console.log(`[VDS ${ts}] ✅ Design system güncellendi.`);
18
19
  } catch (e) {
19
20
  console.error(`[VDS ${ts}] ❌ Hata:`, e.message);