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
|
@@ -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
|
|
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"**
|
|
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
|
-
|
|
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
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
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
|
-
//
|
|
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) =>
|
|
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);
|