vibe-design-system 2.8.4 → 2.8.6

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.4",
3
+ "version": "2.8.6",
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
+ }
@@ -271,14 +271,10 @@ function collectProvidersAndWarnings(projectRoot) {
271
271
  providersToAdd.unshift({ name: "MemoryRouter", importPath: routerPackage, props: "{ initialEntries: [\"/\"] }" });
272
272
  console.log("[VDS] React Router tespit edildi → MemoryRouter decorator ekleniyor.");
273
273
  }
274
- if (detectReactDnd(projectRoot) && !providersToAdd.some((p) => p.name === "DndProvider")) {
275
- providersToAdd.unshift({
276
- name: "DndProvider",
277
- importPath: "react-dnd",
278
- props: "{ backend: HTML5Backend }",
279
- extraImport: { name: "HTML5Backend", from: "react-dnd-html5-backend" },
280
- });
281
- }
274
+ // NOTE: DndProvider intentionally NOT injected globally.
275
+ // react-dnd as a global Storybook decorator causes a dual-React-instance crash
276
+ // (Cannot read properties of null (reading 'useEffect')).
277
+ // Components using DnD are handled individually via ErrorBoundary.
282
278
  return { providersToAdd, hooksWithoutProvider, hooksByFile };
283
279
  }
284
280
 
@@ -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). */
@@ -550,6 +556,7 @@ const SAFE_WRAPPER_DEFAULTS = {
550
556
  TaskEstimateInput: `{ estimate: 0, onUpdate: () => {}, value: 0, task: { id: "1", title: "Example", estimate: 0 }, compact: false }`,
551
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 (key && !added.has(key)) {
830
- argLines.push(line);
831
- added.add(key);
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)) {
@@ -1439,6 +1454,7 @@ function writeComponentSuggestionsStory(componentSuggestions) {
1439
1454
  const content =
1440
1455
  [
1441
1456
  "import type { Meta, StoryObj } from \"@storybook/react\";",
1457
+ "import { useState } from \"react\";",
1442
1458
  "",
1443
1459
  "const meta = { title: \"Foundations/Component Suggestions\" } satisfies Meta;",
1444
1460
  "export default meta;",
@@ -1446,19 +1462,60 @@ function writeComponentSuggestionsStory(componentSuggestions) {
1446
1462
  "",
1447
1463
  `const suggestions = ${JSON.stringify(suggestions)};`,
1448
1464
  "",
1465
+ "function buildPrompt(s: any) {",
1466
+ " const files = s.foundIn.join(', ');",
1467
+ " return [",
1468
+ " `Extract the repeated JSX pattern below into a new reusable React component named \\`${s.suggestedName}\\`.`,",
1469
+ " ``,",
1470
+ " `This pattern appears ${s.occurrences} time(s) across: ${files}`,",
1471
+ " ``,",
1472
+ " `Pattern:`,",
1473
+ " s.snippet,",
1474
+ " ``,",
1475
+ " `Instructions:`,",
1476
+ " `- Create a new file for ${s.suggestedName} with proper TypeScript props`,",
1477
+ " `- Replace all occurrences in the files above with the new component`,",
1478
+ " `- Keep existing styling and behavior exactly the same`,",
1479
+ " ].join('\\n');",
1480
+ "}",
1481
+ "",
1482
+ "function SuggestionCard({ s }: { s: any }) {",
1483
+ " const [copied, setCopied] = useState(false);",
1484
+ " const copy = () => {",
1485
+ " navigator.clipboard.writeText(buildPrompt(s)).then(() => {",
1486
+ " setCopied(true);",
1487
+ " setTimeout(() => setCopied(false), 2000);",
1488
+ " });",
1489
+ " };",
1490
+ " return (",
1491
+ " <div style={{ border: '1px solid #e2e8f0', borderRadius: 12, padding: 20, background: '#fff', boxShadow: '0 1px 3px rgba(0,0,0,0.06)' }}>",
1492
+ " <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 12 }}>",
1493
+ " <div>",
1494
+ " <div style={{ fontWeight: 700, fontSize: 16, color: '#1a202c', marginBottom: 4 }}>{s.suggestedName}</div>",
1495
+ " <div style={{ fontSize: 12, color: '#718096' }}>{s.reason}</div>",
1496
+ " </div>",
1497
+ " <button onClick={copy} style={{ flexShrink: 0, marginLeft: 16, padding: '8px 16px', borderRadius: 8, border: 'none', cursor: 'pointer', fontWeight: 600, fontSize: 13, background: copied ? '#48bb78' : '#6366f1', color: '#fff', transition: 'background 0.2s' }}>",
1498
+ " {copied ? '✅ Copied!' : '📋 Copy Prompt'}",
1499
+ " </button>",
1500
+ " </div>",
1501
+ " <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 12 }}>",
1502
+ " {s.foundIn.map((f: string, i: number) => (",
1503
+ " <span key={i} style={{ fontSize: 11, background: '#edf2f7', color: '#4a5568', padding: '2px 8px', borderRadius: 4, fontFamily: 'monospace' }}>{f}</span>",
1504
+ " ))}",
1505
+ " </div>",
1506
+ " <pre style={{ margin: 0, padding: 12, background: '#1a202c', borderRadius: 8, overflow: 'auto', fontSize: 12, color: '#e2e8f0', lineHeight: 1.6 }}><code>{s.snippet}</code></pre>",
1507
+ " <div style={{ marginTop: 10, fontSize: 12, color: '#a0aec0' }}>💡 Copy Prompt'a tıkla → Cursor / Superflex'e yapıştır → component otomatik oluşturulur.</div>",
1508
+ " </div>",
1509
+ " );",
1510
+ "}",
1511
+ "",
1449
1512
  "export const Default: Story = {",
1450
1513
  " render: () => (",
1451
- " <div style={{ padding: 24, fontFamily: \"system-ui, sans-serif\" }}>",
1452
- " <h2 style={{ marginBottom: 16 }}>Visual section candidates (component suggestions)</h2>",
1453
- " <p style={{ color: \"#888\", marginBottom: 24 }}>From src/pages, src/app ve src/components: kendi className kümeleri, 2+ child element, 2+ tekrar. Aynı yapı birden fazla dosyada geçiyorsa ayrı component olarak düşünün.</p>",
1454
- " <div style={{ display: \"flex\", flexDirection: \"column\", gap: 24 }}>",
1455
- " {suggestions.map((s, i) => (",
1456
- " <div key={i} style={{ border: \"1px solid #333\", borderRadius: 8, padding: 16, background: \"#111\" }}>",
1457
- " <div style={{ fontWeight: 600, marginBottom: 8 }}>{s.suggestedName}</div>",
1458
- " <div style={{ fontSize: 12, color: \"#888\", marginBottom: 8 }}>{s.reason} · {s.foundIn.join(\", \")}</div>",
1459
- " <pre style={{ margin: 0, padding: 12, background: \"#000\", borderRadius: 4, overflow: \"auto\", fontSize: 12 }}><code>{s.snippet}</code></pre>",
1460
- " </div>",
1461
- " ))}",
1514
+ " <div style={{ padding: 32, fontFamily: 'system-ui, sans-serif', background: '#f7fafc', minHeight: '100vh' }}>",
1515
+ " <h2 style={{ marginBottom: 8, fontSize: 24, fontWeight: 700, color: '#1a202c' }}>Component Suggestions</h2>",
1516
+ " <p style={{ color: '#718096', marginBottom: 32, fontSize: 14 }}>Bu pattern'ler birden fazla dosyada tekrar ediyor. Her biri ayrı bir component olabilir. <strong>Copy Prompt</strong> butonuna tıklayıp Cursor veya Superflex'e yapıştır.</p>",
1517
+ " <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>",
1518
+ " {suggestions.map((s: any, i: number) => <SuggestionCard key={i} s={s} />)}",
1462
1519
  " </div>",
1463
1520
  " </div>",
1464
1521
  " ),",
@@ -1533,22 +1590,25 @@ function main() {
1533
1590
  // ignore
1534
1591
  }
1535
1592
 
1536
- // Clear existing .stories.* files (except foundations/*.mdx) so only VDS-generated stories remain
1537
- try {
1538
- const existing = fs.readdirSync(STORIES_DIR);
1539
- for (const name of existing) {
1540
- if (name === "foundations") continue;
1541
- if (
1542
- name.endsWith(".stories.tsx") ||
1543
- name.endsWith(".stories.ts") ||
1544
- name.endsWith(".stories.jsx") ||
1545
- name.endsWith(".stories.js")
1546
- ) {
1547
- fs.unlinkSync(path.join(STORIES_DIR, name));
1593
+ // Clear existing .stories.* files only on full regeneration (no filter arg),
1594
+ // so that "node story-generator.mjs SomeName" doesn't wipe other stories.
1595
+ if (!onlyName) {
1596
+ try {
1597
+ const existing = fs.readdirSync(STORIES_DIR);
1598
+ for (const name of existing) {
1599
+ if (name === "foundations") continue;
1600
+ if (
1601
+ name.endsWith(".stories.tsx") ||
1602
+ name.endsWith(".stories.ts") ||
1603
+ name.endsWith(".stories.jsx") ||
1604
+ name.endsWith(".stories.js")
1605
+ ) {
1606
+ fs.unlinkSync(path.join(STORIES_DIR, name));
1607
+ }
1548
1608
  }
1609
+ } catch {
1610
+ // ignore
1549
1611
  }
1550
- } catch {
1551
- // ignore
1552
1612
  }
1553
1613
 
1554
1614
  for (const comp of components) {