vibe-design-system 2.8.3 → 2.8.5
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
|
@@ -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: () => {},",
|
|
@@ -538,6 +538,12 @@ const COMPONENT_EXTRA_ARGS = {
|
|
|
538
538
|
" totalEstimated: 0,",
|
|
539
539
|
" projectTotalEstimated: 0,",
|
|
540
540
|
],
|
|
541
|
+
TimeTable: [
|
|
542
|
+
" logs: [{ id: \"1\", taskId: \"t1\", userId: \"u1\", date: \"2024-01-15\", hours: 8, description: \"Work session\", billable: true, status: \"submitted\" }, { id: \"2\", taskId: \"t1\", userId: \"u1\", date: \"2024-01-16\", hours: 6, description: \"Review session\", billable: false, status: \"draft\" }],",
|
|
543
|
+
" users: [],",
|
|
544
|
+
" tasks: [],",
|
|
545
|
+
" onLogClick: () => {},",
|
|
546
|
+
],
|
|
541
547
|
};
|
|
542
548
|
|
|
543
549
|
/** Render'da args'a uygulanacak fallback (useState(estimate.toString()) gibi kullanımlar için; args/Controls undefined yapsa bile). */
|
|
@@ -548,8 +554,9 @@ const RENDER_ARGS_FALLBACKS = {
|
|
|
548
554
|
/** 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
555
|
const SAFE_WRAPPER_DEFAULTS = {
|
|
550
556
|
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: [] }`,
|
|
557
|
+
TimeFilterPanel: `{ filter: { preset: null, dateRange: {}, userIds: [], tags: [], billable: "all" }, onFilterChange: () => {}, onSaveFilter: () => {}, onDeleteFilter: () => {}, filteredCount: 0, savedFilters: [] }`,
|
|
552
558
|
TimeStats: `{ totalLogged: 0, totalBillable: 0, totalNonBillable: 0, totalBilled: 0, totalEstimated: 0, projectTotalEstimated: 0 }`,
|
|
559
|
+
TimeTable: `{ logs: [{ id: "1", taskId: "t1", userId: "u1", date: "2024-01-15", hours: 8, description: "Work session", billable: true, status: "submitted" }, { id: "2", taskId: "t1", userId: "u1", date: "2024-01-16", hours: 6, description: "Review session", billable: false, status: "draft" }], users: [], tasks: [], onLogClick: () => {} }`,
|
|
553
560
|
};
|
|
554
561
|
|
|
555
562
|
/** Recursive list of .tsx/.jsx file paths under dir (relative to dir). Index.tsx / index.tsx first for deterministic "first usage". */
|
|
@@ -821,15 +828,23 @@ function buildDefaultArgsForRequiredProps(props, usageFromPages = null, componen
|
|
|
821
828
|
}
|
|
822
829
|
}
|
|
823
830
|
}
|
|
824
|
-
// COMPONENT_EXTRA_ARGS: props listesi boş olsa bile (örn. parse edilemeyen component) uygula
|
|
831
|
+
// COMPONENT_EXTRA_ARGS: props listesi boş olsa bile (örn. parse edilemeyen component) uygula.
|
|
832
|
+
// Bu blok her zaman override eder — auto-generated değerleri daha doğru olanlarla değiştirir.
|
|
825
833
|
if (componentName && COMPONENT_EXTRA_ARGS[componentName]) {
|
|
826
834
|
for (const line of COMPONENT_EXTRA_ARGS[componentName]) {
|
|
827
835
|
const keyMatch = line.match(/^\s*(\w+)\s*:/);
|
|
828
836
|
const key = keyMatch ? keyMatch[1] : null;
|
|
829
|
-
if (
|
|
830
|
-
|
|
831
|
-
|
|
837
|
+
if (!key) continue;
|
|
838
|
+
if (added.has(key)) {
|
|
839
|
+
// Remove the previously auto-generated line for this key so we can replace it
|
|
840
|
+
const idx = argLines.findIndex(l => {
|
|
841
|
+
const m = l.match(/^\s*(\w+)\s*:/);
|
|
842
|
+
return m && m[1] === key;
|
|
843
|
+
});
|
|
844
|
+
if (idx !== -1) argLines.splice(idx, 1);
|
|
832
845
|
}
|
|
846
|
+
argLines.push(line);
|
|
847
|
+
added.add(key);
|
|
833
848
|
}
|
|
834
849
|
}
|
|
835
850
|
for (const name of Object.keys(fromPages)) {
|