vibe-design-system 2.5.32 → 2.5.35

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.35",
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,24 @@ 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
+
72
+ ### Test projesinde çıkan hatalar (sorun giderme)
73
+
74
+ | Gördüğünüz mesaj | Ne yapmalı |
75
+ |------------------|------------|
76
+ | **Failed to fetch dynamically imported module: …/X.stories.tsx** | Story dosyası yüklenemiyor. En güncel VDS template’i kullanıp story’leri yeniden üretin: `npm run vds:stories`. Eski template’te statik import vardı; yeni sürümde dinamik import + catch kullanılıyor. |
77
+ | **Cannot read properties of undefined (reading 'dateRange')** (örn. TimeFilterPanel) | `filters` / `dateRange` varsayılanı generator’da var. `npm run vds:stories` tekrar çalıştırın; hâlâ olursa ilgili story’de `args.filters` veya `args.dateRange` manuel ekleyin. |
78
+ | **Cannot read properties of undefined (reading 'toString')** (örn. TaskEstimateInput) | `estimate` / sayısal proplar için varsayılan eklendi. `npm run vds:stories` ile story’leri yenileyin. |
79
+ | **Başlık/component boş** (örn. UnlockModuleModal) | Modal/drawer için `isOpen` veya `open: true` varsayılanı veriliyor. Story’leri yeniden üretin; gerekirse o story’de `args.open = true` veya `args.isOpen = true` kontrol edin. |
80
+
81
+ Genel adım: `vibe-design-system` güncel olsun, sonra proje kökünde **`npm run vds:stories`** çalıştırıp Storybook’u yeniden başlatın.
71
82
 
72
83
  ## Layout
73
84
 
74
85
  - `vds-core/scan.mjs` — Projeyi tarar (src/components, CSS, Tailwind). `vds-output.json` ve `public/vds-output.json` yazar.
75
86
  - `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
87
  - `vds-core/setup-storybook-providers.mjs` — Hook ve react-dnd kullanımını tespit eder, `.storybook/preview` decorator'larına provider ekler.
88
+ - `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
89
  - `vds-core/VdsPreview.tsx` — İsteğe bağlı; `/vds-preview` ile dashboard canlı component önizlemesi yapar.
78
90
  - Dashboard UI `/vds-output.json` okur; Foundations + Component Library gösterir.
@@ -676,13 +676,13 @@ function buildDefaultArgsForRequiredProps(props, usageFromPages = null, componen
676
676
  } else if (/string/.test(type)) {
677
677
  argLines.push(` ${name}: ${stringFallback(name)},`);
678
678
  added.add(name);
679
- } else if (/number/.test(type) || /^(value|amount|total|count|hours|minutes|progress|percent)$/.test(name)) {
679
+ } else if (/number/.test(type) || /^(value|amount|total|count|hours|minutes|progress|percent|estimate)$/.test(name)) {
680
680
  argLines.push(` ${name}: 0,`);
681
681
  added.add(name);
682
682
  }
683
683
  }
684
- // Optional props that often cause "reading X of undefined" in Storybook if missing
685
- const NUMBER_LIKE_OPTIONAL = new Set(["value", "amount", "total", "count", "hours", "minutes", "progress", "percent", "visibility"]);
684
+ // Optional props that often cause "reading X of undefined" or "reading 'toString'" in Storybook if missing
685
+ const NUMBER_LIKE_OPTIONAL = new Set(["value", "amount", "total", "count", "hours", "minutes", "progress", "percent", "visibility", "estimate"]);
686
686
  const DATE_RANGE_DEFAULT = `{ dateRange: { from: new Date().toISOString(), to: new Date().toISOString() } }`;
687
687
  for (const p of props) {
688
688
  const type = String(p.type || "").trim();
@@ -715,6 +715,9 @@ function buildDefaultArgsForRequiredProps(props, usageFromPages = null, componen
715
715
  } else if (name === "defaultProjectId") {
716
716
  argLines.push(` ${name}: "1",`);
717
717
  added.add(name);
718
+ } else if (name === "task" || /Task\b/.test(type)) {
719
+ argLines.push(` ${name}: { id: "1", title: "Example", estimate: 0 },`);
720
+ added.add(name);
718
721
  }
719
722
  }
720
723
  }
@@ -992,32 +995,17 @@ function buildStoryFileContent(comp) {
992
995
 
993
996
  const lines = [];
994
997
  lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
995
- if (useReactNodeChildrenRender || needReact) {
996
- lines.push(`import React from "react";`);
997
- }
998
+ lines.push(`import React from "react";`);
998
999
  if (lucideImports.length > 0) {
999
1000
  lines.push(`import { ${lucideImports.join(", ")} } from "lucide-react";`);
1000
1001
  }
1001
1002
 
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
-
1003
+ // Dynamic import + catch so "Failed to fetch dynamically imported module" shows a fallback instead of breaking Storybook
1004
+ const loadFallback = `() => React.createElement('div', { style: { padding: 16, color: '#666', fontSize: 14 } }, 'Component could not be loaded (import error).')`;
1005
+ const getDefault = `(m) => ({ default: m["${componentName}"] ?? m.default })`;
1006
+ lines.push(`const ComponentRef = React.lazy(() => import(/* @vite-ignore */ "${importPath}").then(${getDefault}).catch(() => ({ default: ${loadFallback} })));`);
1020
1007
  lines.push("");
1008
+
1021
1009
  lines.push(`const meta = {`);
1022
1010
  lines.push(` title: ${JSON.stringify(title)},`);
1023
1011
  lines.push(` component: ComponentRef,`);
@@ -1042,10 +1030,10 @@ function buildStoryFileContent(comp) {
1042
1030
  return lines.join("\n");
1043
1031
  }
1044
1032
 
1045
- // Generic variant-based stories render real component with args (omit children for img/void)
1033
+ // Wrap in Suspense so lazy load errors render fallback instead of crashing
1046
1034
  const renderLine = useReactNodeChildrenRender
1047
- ? ` render: (args) => React.createElement(ComponentRef, { ...args, children: args.children || React.createElement('span', null, 'Example') }),`
1048
- : ` render: (args) => <ComponentRef {...args} />,`;
1035
+ ? ` render: (args) => React.createElement(React.Suspense, { fallback: null }, React.createElement(ComponentRef, { ...args, children: args.children || React.createElement('span', null, 'Example') })),`
1036
+ : ` render: (args) => React.createElement(React.Suspense, { fallback: null }, React.createElement(ComponentRef, args)),`;
1049
1037
  const childrenArgLine = (label) => (!omitChildren && !useReactNodeChildrenRender ? ` children: ${JSON.stringify(label)},` : null);
1050
1038
 
1051
1039
  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);