vibe-design-system 2.8.3 → 2.8.4
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.
|
|
3
|
+
"version": "2.8.4",
|
|
4
4
|
"description": "Auto-generate design systems for vibe coding projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,4 +38,4 @@
|
|
|
38
38
|
"typescript": "^5.8.3",
|
|
39
39
|
"vite": "^5.4.19"
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|
|
@@ -294,6 +294,29 @@ function buildWithProvidersCode(providers) {
|
|
|
294
294
|
return `const withProviders = (Story: any) => ${inner};`;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
+
/** ErrorBoundary class – injected into .storybook/preview to catch story render errors (missing providers, undefined props, etc.) */
|
|
298
|
+
function buildErrorBoundaryCode() {
|
|
299
|
+
return [
|
|
300
|
+
"class VdsErrorBoundary extends React.Component {",
|
|
301
|
+
" constructor(props) { super(props); this.state = { error: null }; }",
|
|
302
|
+
" static getDerivedStateFromError(error) { return { error }; }",
|
|
303
|
+
" componentDidCatch(err) { console.error(\"[VDS Story Error]\", err); }",
|
|
304
|
+
" render() {",
|
|
305
|
+
" const s = this.state; const p = this.props;",
|
|
306
|
+
" if (s && s.error) return React.createElement(\"div\", {",
|
|
307
|
+
" style: { padding: 16, color: \"#ff6b6b\", border: \"1px solid #ff6b6b\", borderRadius: 8, fontFamily: \"monospace\", margin: 8 }",
|
|
308
|
+
" }, React.createElement(\"b\", null, \"⚠️ Story Error: \"), React.createElement(\"code\", { style: { whiteSpace: \"pre-wrap\" } }, String(s.error.message)));",
|
|
309
|
+
" return p.children;",
|
|
310
|
+
" }",
|
|
311
|
+
"}",
|
|
312
|
+
"const withErrorBoundary = (Story) => React.createElement(VdsErrorBoundary, null, React.createElement(Story));",
|
|
313
|
+
].join("\n");
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// VDS markers for idempotent preview injection
|
|
317
|
+
const VDS_BLOCK_START = "// [VDS:providers-start]";
|
|
318
|
+
const VDS_BLOCK_END = "// [VDS:providers-end]";
|
|
319
|
+
|
|
297
320
|
function injectProviderDecorators(projectRoot) {
|
|
298
321
|
const previewPath = getPreviewPath(projectRoot);
|
|
299
322
|
if (!previewPath) {
|
|
@@ -302,44 +325,83 @@ function injectProviderDecorators(projectRoot) {
|
|
|
302
325
|
}
|
|
303
326
|
|
|
304
327
|
const { providersToAdd, hooksWithoutProvider, hooksByFile } = collectProvidersAndWarnings(projectRoot);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
328
|
+
let content = fs.readFileSync(previewPath, "utf-8");
|
|
329
|
+
|
|
330
|
+
// 1. Ensure React import exists (needed for error boundary + providers)
|
|
331
|
+
if (!content.includes("import React") && !content.includes("import React from")) {
|
|
332
|
+
const firstImport = content.match(/^import\s+/m);
|
|
333
|
+
const insertAt = firstImport ? content.indexOf(firstImport[0]) : 0;
|
|
334
|
+
content = content.slice(0, insertAt) + "import React from \"react\";\n" + content.slice(insertAt);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 2. Add provider imports if not already present (use regex to detect existing import)
|
|
338
|
+
const uniqueProviders = [...new Map(providersToAdd.map((p) => [p.name, p])).values()];
|
|
339
|
+
for (const p of uniqueProviders) {
|
|
340
|
+
const alreadyImported = new RegExp(`\\bimport[^;]*\\b${p.name}\\b[^;]*from`).test(content);
|
|
341
|
+
if (!alreadyImported) {
|
|
342
|
+
const importMatches = [...content.matchAll(/^import\s+[^\n]+;/gm)];
|
|
343
|
+
const lastMatch = importMatches[importMatches.length - 1];
|
|
344
|
+
const insertAt = lastMatch ? lastMatch.index + lastMatch[0].length + 1 : content.indexOf("\n") + 1;
|
|
345
|
+
let importLine = `import { ${p.name} } from "${p.importPath}";\n`;
|
|
346
|
+
if (p.extraImport && !new RegExp(`\\b${p.extraImport.name}\\b`).test(content)) {
|
|
347
|
+
importLine += `import { ${p.extraImport.name} } from "${p.extraImport.from}";\n`;
|
|
324
348
|
}
|
|
349
|
+
content = content.slice(0, insertAt) + importLine + content.slice(insertAt);
|
|
325
350
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// 3. Remove previous VDS injections (idempotent re-runs)
|
|
354
|
+
content = content.replace(new RegExp(VDS_BLOCK_START.replace(/[\[\]]/g, "\\$&") + "[\\s\\S]*?" + VDS_BLOCK_END.replace(/[\[\]]/g, "\\$&") + "\\n?"), "");
|
|
355
|
+
// Remove old-style single-line withProviders (pre-marker era)
|
|
356
|
+
content = content.replace(/^const withProviders\s*=\s*\([^)]*\)\s*=>.*;\n?/m, "");
|
|
357
|
+
// Remove VDS decorator names from decorators arrays so we can re-inject cleanly
|
|
358
|
+
content = content.replace(/\bwithErrorBoundary\s*,\s*/g, "").replace(/,\s*\bwithErrorBoundary\b/g, "").replace(/\bwithErrorBoundary\b/g, "");
|
|
359
|
+
content = content.replace(/\bwithProviders\s*,\s*/g, "").replace(/,\s*\bwithProviders\b/g, "").replace(/\bwithProviders\b/g, "");
|
|
360
|
+
// Fix any syntax damage: leading comma, trailing comma, empty decorators
|
|
361
|
+
content = content.replace(/\[\s*,\s*/g, "[").replace(/,\s*\]/g, "]");
|
|
362
|
+
content = content.replace(/\s*decorators:\s*\[\s*\]\s*,?\n?/g, "");
|
|
363
|
+
content = content.replace(/\n{3,}/g, "\n\n");
|
|
364
|
+
|
|
365
|
+
// 4. Build new VDS block (error boundary + optional provider wrapper)
|
|
366
|
+
const errorBoundaryCode = buildErrorBoundaryCode();
|
|
367
|
+
const withProvidersCode = uniqueProviders.length > 0 ? buildWithProvidersCode(providersToAdd) : null;
|
|
368
|
+
const vdsCode = [errorBoundaryCode, withProvidersCode].filter(Boolean).join("\n\n");
|
|
369
|
+
const vdsBlock = VDS_BLOCK_START + "\n" + vdsCode + "\n" + VDS_BLOCK_END;
|
|
370
|
+
|
|
371
|
+
// 5. Find insertion point: before "const preview" or "export default {"
|
|
372
|
+
let insertBefore = content.indexOf("const preview");
|
|
373
|
+
if (insertBefore === -1) {
|
|
374
|
+
const edMatch = content.match(/export\s+default\s*[\{(]/);
|
|
375
|
+
if (edMatch) insertBefore = content.indexOf(edMatch[0]);
|
|
376
|
+
}
|
|
377
|
+
if (insertBefore === -1) insertBefore = content.length;
|
|
378
|
+
content = content.slice(0, insertBefore) + vdsBlock + "\n\n" + content.slice(insertBefore);
|
|
379
|
+
|
|
380
|
+
// 6. Inject decorators into preview object
|
|
381
|
+
const decoratorItems = ["withErrorBoundary", ...(withProvidersCode ? ["withProviders"] : [])];
|
|
382
|
+
const decoratorsStr = decoratorItems.join(", ");
|
|
383
|
+
if (content.includes("decorators:")) {
|
|
384
|
+
// Prepend VDS decorators to existing decorators array
|
|
385
|
+
content = content.replace(/\bdecorators:\s*\[/, `decorators: [${decoratorsStr}, `);
|
|
386
|
+
content = content.replace(/,\s*\]/g, "]");
|
|
387
|
+
} else {
|
|
388
|
+
// Add new decorators key to preview object
|
|
389
|
+
const constPreviewMatch = content.match(/(const\s+preview\s*[^=\n]*=\s*\{)/);
|
|
390
|
+
if (constPreviewMatch) {
|
|
391
|
+
content = content.replace(constPreviewMatch[0], constPreviewMatch[0] + `\n decorators: [${decoratorsStr}],`);
|
|
392
|
+
} else {
|
|
393
|
+
const exportDefaultMatch = content.match(/(export\s+default\s*\{)/);
|
|
394
|
+
if (exportDefaultMatch) {
|
|
395
|
+
content = content.replace(exportDefaultMatch[0], exportDefaultMatch[0] + `\n decorators: [${decoratorsStr}],`);
|
|
337
396
|
}
|
|
338
397
|
}
|
|
339
|
-
fs.writeFileSync(previewPath, content, "utf-8");
|
|
340
|
-
console.log("[VDS] Storybook preview: " + uniqueProviders.map((p) => p.name).join(", "));
|
|
341
398
|
}
|
|
342
399
|
|
|
400
|
+
content = content.replace(/\n{3,}/g, "\n\n");
|
|
401
|
+
fs.writeFileSync(previewPath, content, "utf-8");
|
|
402
|
+
console.log("[VDS] Storybook preview: ErrorBoundary" + (uniqueProviders.length ? " + " + uniqueProviders.map((p) => p.name).join(", ") : ""));
|
|
403
|
+
|
|
404
|
+
// 7. Handle hooks without provider: add warning comment to affected story files
|
|
343
405
|
if (hooksWithoutProvider.size > 0) {
|
|
344
406
|
const componentNameFromPath = (rel) => path.basename(rel, path.extname(rel));
|
|
345
407
|
const storiesDir = path.join(projectRoot, "src", "stories");
|
|
@@ -523,7 +523,7 @@ const COMPONENT_EXTRA_ARGS = {
|
|
|
523
523
|
" taskId: \"1\",",
|
|
524
524
|
],
|
|
525
525
|
TimeFilterPanel: [
|
|
526
|
-
" filter: { dateRange: {}, userIds: [], tags: [], billable: \"all\" },",
|
|
526
|
+
" filter: { preset: null, dateRange: {}, userIds: [], tags: [], billable: \"all\" },",
|
|
527
527
|
" onFilterChange: () => {},",
|
|
528
528
|
" onSaveFilter: () => {},",
|
|
529
529
|
" onDeleteFilter: () => {},",
|
|
@@ -548,7 +548,7 @@ const RENDER_ARGS_FALLBACKS = {
|
|
|
548
548
|
/** Kalıcı çözüm: Storybook Docs/Controls args'ı geçmezse bile component'a güvenli props veren wrapper. Önce safeDefaults uygulanır, sonra gelen props. */
|
|
549
549
|
const SAFE_WRAPPER_DEFAULTS = {
|
|
550
550
|
TaskEstimateInput: `{ estimate: 0, onUpdate: () => {}, value: 0, task: { id: "1", title: "Example", estimate: 0 }, compact: false }`,
|
|
551
|
-
TimeFilterPanel: `{ filter: { dateRange: {}, userIds: [], tags: [], billable: "all" }, onFilterChange: () => {}, onSaveFilter: () => {}, onDeleteFilter: () => {}, filteredCount: 0, savedFilters: [] }`,
|
|
551
|
+
TimeFilterPanel: `{ filter: { preset: null, dateRange: {}, userIds: [], tags: [], billable: "all" }, onFilterChange: () => {}, onSaveFilter: () => {}, onDeleteFilter: () => {}, filteredCount: 0, savedFilters: [] }`,
|
|
552
552
|
TimeStats: `{ totalLogged: 0, totalBillable: 0, totalNonBillable: 0, totalBilled: 0, totalEstimated: 0, projectTotalEstimated: 0 }`,
|
|
553
553
|
};
|
|
554
554
|
|