vibe-design-system 1.9.3 → 1.9.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-design-system",
3
- "version": "1.9.3",
3
+ "version": "1.9.5",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,11 +20,7 @@ const VDS_OUTPUT = path.join(PROJECT_ROOT, "vds-output.json");
20
20
  const SRC_DIR = path.join(PROJECT_ROOT, "src");
21
21
  const STORIES_DIR = path.join(SRC_DIR, "stories");
22
22
 
23
- // Top of every story file for CSS variables
24
- const STORY_CSS_HEADER = `// @ts-ignore
25
- import '../../index.css'
26
-
27
- `;
23
+ // CSS is loaded from .storybook/preview.tsx never add CSS import to story files.
28
24
 
29
25
  // Components we don't want to auto-generate stories for (project-specific dashboards, heavy UIs, etc.)
30
26
  const SKIP_LIST = [
@@ -42,8 +38,270 @@ const SKIP_LIST = [
42
38
  "ToggleGroup",
43
39
  "Sidebar",
44
40
  "TestComponent",
41
+ "Chart",
42
+ "InputOtp",
43
+ "Resizable",
44
+ "Sonner",
45
45
  ];
46
46
 
47
+ /** shadcn/ui composite component recipes: component name → imports + render. */
48
+ const RECIPES = {
49
+ Accordion: {
50
+ imports: ["AccordionItem", "AccordionTrigger", "AccordionContent"],
51
+ render: `(args) => (
52
+ <ComponentRef type="single" collapsible {...args}>
53
+ <AccordionItem value="item-1">
54
+ <AccordionTrigger>Is it accessible?</AccordionTrigger>
55
+ <AccordionContent>Yes. It adheres to the WAI-ARIA design pattern.</AccordionContent>
56
+ </AccordionItem>
57
+ <AccordionItem value="item-2">
58
+ <AccordionTrigger>Is it styled?</AccordionTrigger>
59
+ <AccordionContent>Yes. It comes with default styles.</AccordionContent>
60
+ </AccordionItem>
61
+ </ComponentRef>
62
+ )`,
63
+ },
64
+ Dialog: {
65
+ imports: ["DialogTrigger", "DialogContent", "DialogHeader", "DialogTitle", "DialogDescription"],
66
+ render: `(args) => (
67
+ <ComponentRef {...args}>
68
+ <DialogTrigger asChild><button>Open Dialog</button></DialogTrigger>
69
+ <DialogContent>
70
+ <DialogHeader>
71
+ <DialogTitle>Dialog Title</DialogTitle>
72
+ <DialogDescription>This is a dialog description.</DialogDescription>
73
+ </DialogHeader>
74
+ </DialogContent>
75
+ </ComponentRef>
76
+ )`,
77
+ },
78
+ AlertDialog: {
79
+ imports: ["AlertDialogTrigger", "AlertDialogContent", "AlertDialogHeader", "AlertDialogTitle", "AlertDialogDescription", "AlertDialogFooter", "AlertDialogCancel", "AlertDialogAction"],
80
+ render: `(args) => (
81
+ <ComponentRef {...args}>
82
+ <AlertDialogTrigger asChild><button>Open</button></AlertDialogTrigger>
83
+ <AlertDialogContent>
84
+ <AlertDialogHeader>
85
+ <AlertDialogTitle>Are you sure?</AlertDialogTitle>
86
+ <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
87
+ </AlertDialogHeader>
88
+ <AlertDialogFooter>
89
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
90
+ <AlertDialogAction>Continue</AlertDialogAction>
91
+ </AlertDialogFooter>
92
+ </AlertDialogContent>
93
+ </ComponentRef>
94
+ )`,
95
+ },
96
+ Alert: {
97
+ imports: ["AlertTitle", "AlertDescription"],
98
+ render: `(args) => (
99
+ <ComponentRef {...args}>
100
+ <AlertTitle>Heads up!</AlertTitle>
101
+ <AlertDescription>You can add components to your app using the CLI.</AlertDescription>
102
+ </ComponentRef>
103
+ )`,
104
+ },
105
+ Tooltip: {
106
+ imports: ["TooltipProvider", "TooltipTrigger", "TooltipContent"],
107
+ render: `(args) => (
108
+ <TooltipProvider>
109
+ <ComponentRef {...args}>
110
+ <TooltipTrigger asChild><button>Hover me</button></TooltipTrigger>
111
+ <TooltipContent><p>Tooltip content</p></TooltipContent>
112
+ </ComponentRef>
113
+ </TooltipProvider>
114
+ )`,
115
+ },
116
+ Popover: {
117
+ imports: ["PopoverTrigger", "PopoverContent"],
118
+ render: `(args) => (
119
+ <ComponentRef {...args}>
120
+ <PopoverTrigger asChild><button>Open Popover</button></PopoverTrigger>
121
+ <PopoverContent>Place content here.</PopoverContent>
122
+ </ComponentRef>
123
+ )`,
124
+ },
125
+ HoverCard: {
126
+ imports: ["HoverCardTrigger", "HoverCardContent"],
127
+ render: `(args) => (
128
+ <ComponentRef {...args}>
129
+ <HoverCardTrigger asChild><button>Hover</button></HoverCardTrigger>
130
+ <HoverCardContent>Card content on hover.</HoverCardContent>
131
+ </ComponentRef>
132
+ )`,
133
+ },
134
+ Tabs: {
135
+ imports: ["TabsList", "TabsTrigger", "TabsContent"],
136
+ render: `(args) => (
137
+ <ComponentRef defaultValue="tab1" {...args}>
138
+ <TabsList>
139
+ <TabsTrigger value="tab1">Tab 1</TabsTrigger>
140
+ <TabsTrigger value="tab2">Tab 2</TabsTrigger>
141
+ </TabsList>
142
+ <TabsContent value="tab1">Content for tab 1</TabsContent>
143
+ <TabsContent value="tab2">Content for tab 2</TabsContent>
144
+ </ComponentRef>
145
+ )`,
146
+ },
147
+ Table: {
148
+ imports: ["TableHeader", "TableBody", "TableRow", "TableHead", "TableCell"],
149
+ render: `(args) => (
150
+ <ComponentRef {...args}>
151
+ <TableHeader><TableRow><TableHead>Name</TableHead><TableHead>Status</TableHead></TableRow></TableHeader>
152
+ <TableBody><TableRow><TableCell>Item 1</TableCell><TableCell>Active</TableCell></TableRow></TableBody>
153
+ </ComponentRef>
154
+ )`,
155
+ },
156
+ DropdownMenu: {
157
+ imports: ["DropdownMenuTrigger", "DropdownMenuContent", "DropdownMenuItem"],
158
+ render: `(args) => (
159
+ <ComponentRef {...args}>
160
+ <DropdownMenuTrigger asChild><button>Open Menu</button></DropdownMenuTrigger>
161
+ <DropdownMenuContent>
162
+ <DropdownMenuItem>Profile</DropdownMenuItem>
163
+ <DropdownMenuItem>Settings</DropdownMenuItem>
164
+ <DropdownMenuItem>Logout</DropdownMenuItem>
165
+ </DropdownMenuContent>
166
+ </ComponentRef>
167
+ )`,
168
+ },
169
+ ContextMenu: {
170
+ imports: ["ContextMenuTrigger", "ContextMenuContent", "ContextMenuItem"],
171
+ render: `(args) => (
172
+ <ComponentRef {...args}>
173
+ <ContextMenuTrigger><div style={{padding: 40, border: '1px dashed #ccc'}}>Right click here</div></ContextMenuTrigger>
174
+ <ContextMenuContent>
175
+ <ContextMenuItem>Back</ContextMenuItem>
176
+ <ContextMenuItem>Forward</ContextMenuItem>
177
+ <ContextMenuItem>Reload</ContextMenuItem>
178
+ </ContextMenuContent>
179
+ </ComponentRef>
180
+ )`,
181
+ },
182
+ Select: {
183
+ imports: ["SelectTrigger", "SelectValue", "SelectContent", "SelectItem"],
184
+ render: `(args) => (
185
+ <ComponentRef {...args}>
186
+ <SelectTrigger className="w-[180px]"><SelectValue placeholder="Select a fruit" /></SelectTrigger>
187
+ <SelectContent>
188
+ <SelectItem value="apple">Apple</SelectItem>
189
+ <SelectItem value="banana">Banana</SelectItem>
190
+ <SelectItem value="orange">Orange</SelectItem>
191
+ </SelectContent>
192
+ </ComponentRef>
193
+ )`,
194
+ },
195
+ Card: {
196
+ imports: ["CardHeader", "CardTitle", "CardDescription", "CardContent", "CardFooter"],
197
+ render: `(args) => (
198
+ <ComponentRef className="w-[340px]" {...args}>
199
+ <CardHeader>
200
+ <CardTitle>Card title</CardTitle>
201
+ <CardDescription>Short description.</CardDescription>
202
+ </CardHeader>
203
+ <CardContent><p>Card body content here.</p></CardContent>
204
+ <CardFooter>Footer</CardFooter>
205
+ </ComponentRef>
206
+ )`,
207
+ },
208
+ Avatar: {
209
+ imports: ["AvatarImage", "AvatarFallback"],
210
+ render: `(args) => (
211
+ <ComponentRef {...args}>
212
+ <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
213
+ <AvatarFallback>JD</AvatarFallback>
214
+ </ComponentRef>
215
+ )`,
216
+ },
217
+ Checkbox: {
218
+ extraImports: [{ from: "@/components/ui/label", names: ["Label"] }],
219
+ render: `(args) => (
220
+ <div className="flex items-center space-x-2">
221
+ <ComponentRef id="terms" {...args} />
222
+ <Label htmlFor="terms">Accept terms</Label>
223
+ </div>
224
+ )`,
225
+ },
226
+ Switch: {
227
+ extraImports: [{ from: "@/components/ui/label", names: ["Label"] }],
228
+ render: `(args) => (
229
+ <div className="flex items-center space-x-2">
230
+ <ComponentRef id="switch" {...args} />
231
+ <Label htmlFor="switch">Enable notifications</Label>
232
+ </div>
233
+ )`,
234
+ },
235
+ RadioGroup: {
236
+ imports: ["RadioGroupItem"],
237
+ extraImports: [{ from: "@/components/ui/label", names: ["Label"] }],
238
+ render: `(args) => (
239
+ <ComponentRef className="flex flex-col space-y-2" {...args}>
240
+ <div className="flex items-center space-x-2">
241
+ <RadioGroupItem value="comfortable" id="comfortable" />
242
+ <Label htmlFor="comfortable">Comfortable</Label>
243
+ </div>
244
+ <div className="flex items-center space-x-2">
245
+ <RadioGroupItem value="compact" id="compact" />
246
+ <Label htmlFor="compact">Compact</Label>
247
+ </div>
248
+ </ComponentRef>
249
+ )`,
250
+ },
251
+ Sheet: {
252
+ imports: ["SheetTrigger", "SheetContent", "SheetHeader", "SheetTitle", "SheetDescription"],
253
+ render: `(args) => (
254
+ <ComponentRef {...args}>
255
+ <SheetTrigger asChild><button>Open Sheet</button></SheetTrigger>
256
+ <SheetContent>
257
+ <SheetHeader>
258
+ <SheetTitle>Sheet Title</SheetTitle>
259
+ <SheetDescription>Sheet description here.</SheetDescription>
260
+ </SheetHeader>
261
+ </SheetContent>
262
+ </ComponentRef>
263
+ )`,
264
+ },
265
+ Drawer: {
266
+ imports: ["DrawerTrigger", "DrawerContent", "DrawerHeader", "DrawerTitle", "DrawerDescription"],
267
+ render: `(args) => (
268
+ <ComponentRef {...args}>
269
+ <DrawerTrigger asChild><button>Open Drawer</button></DrawerTrigger>
270
+ <DrawerContent>
271
+ <DrawerHeader>
272
+ <DrawerTitle>Drawer Title</DrawerTitle>
273
+ <DrawerDescription>Drawer description here.</DrawerDescription>
274
+ </DrawerHeader>
275
+ </DrawerContent>
276
+ </ComponentRef>
277
+ )`,
278
+ },
279
+ Collapsible: {
280
+ imports: ["CollapsibleTrigger", "CollapsibleContent"],
281
+ render: `(args) => (
282
+ <ComponentRef {...args}>
283
+ <CollapsibleTrigger asChild><button>Toggle</button></CollapsibleTrigger>
284
+ <CollapsibleContent>Collapsible content here.</CollapsibleContent>
285
+ </ComponentRef>
286
+ )`,
287
+ },
288
+ Menubar: {
289
+ imports: ["MenubarMenu", "MenubarTrigger", "MenubarContent", "MenubarItem"],
290
+ render: `(args) => (
291
+ <ComponentRef {...args}>
292
+ <MenubarMenu>
293
+ <MenubarTrigger>File</MenubarTrigger>
294
+ <MenubarContent>
295
+ <MenubarItem>New</MenubarItem>
296
+ <MenubarItem>Open</MenubarItem>
297
+ <MenubarItem>Save</MenubarItem>
298
+ </MenubarContent>
299
+ </MenubarMenu>
300
+ </ComponentRef>
301
+ )`,
302
+ },
303
+ };
304
+
47
305
  function ensureDir(dir) {
48
306
  if (!fs.existsSync(dir)) {
49
307
  fs.mkdirSync(dir, { recursive: true });
@@ -58,27 +316,22 @@ function needsRouter(source) {
58
316
  return false;
59
317
  }
60
318
 
61
- /** If component has <img and accepts children prop, we should omit children from story args (void element). */
62
- function componentHasImgAndChildren(source) {
319
+ /** Void HTML elements: img, input, hr, br — must not receive children. If component wraps one and has children in props, omit children in story args. */
320
+ function componentWrapsVoidElement(source) {
63
321
  if (!source || typeof source !== "string") return false;
64
- const hasImg = /return\s+<img|<\s*img\s+/.test(source);
65
- if (!hasImg) return false;
322
+ const hasVoid = /return\s+<(?:img|input|hr|br)\b|<\s*(?:img|input|hr|br)\s+/.test(source);
323
+ if (!hasVoid) return false;
66
324
  return /\bchildren\b/.test(source);
67
325
  }
68
326
 
69
327
  function toSafeComponentName(name, file) {
70
- if (!name || typeof name !== "string") {
71
- const base = (file || "").replace(/\.[^.]+$/, "");
72
- const parts = base.split(/[\\/]/g);
73
- const last = parts[parts.length - 1] || "Component";
74
- return last.charAt(0).toUpperCase() + last.slice(1);
328
+ if (name && typeof name === "string") {
329
+ return name.replace(/[^A-Za-z0-9]+/g, " ").trim().replace(/\s+([a-z])/g, (_, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toUpperCase()).replace(/\s+/g, "");
75
330
  }
76
- return name
77
- .replace(/[^A-Za-z0-9]+/g, " ")
78
- .trim()
79
- .replace(/\s+([a-z])/g, (_, c) => c.toUpperCase())
80
- .replace(/^\w/, (c) => c.toUpperCase())
81
- .replace(/\s+/g, "");
331
+ const base = (file || "").replace(/\.[^.]+$/, "");
332
+ const parts = base.split(/[\\/]/g);
333
+ const last = parts[parts.length - 1] || "Component";
334
+ return last.charAt(0).toUpperCase() + last.slice(1);
82
335
  }
83
336
 
84
337
  function parseUnionLiterals(type) {
@@ -170,67 +423,6 @@ function buildSpecialStories(componentName, variants) {
170
423
  return lines.join("\n");
171
424
  }
172
425
 
173
- if (componentName === "Checkbox") {
174
- lines.push(`export const Default: Story = {`);
175
- lines.push(` render: (args) => (`);
176
- lines.push(` <div className="flex items-center space-x-2">`);
177
- lines.push(` <ComponentRef id="terms" {...args} />`);
178
- lines.push(` <Label htmlFor="terms">Accept terms</Label>`);
179
- lines.push(` </div>`);
180
- lines.push(` ),`);
181
- lines.push(`};`);
182
- return lines.join("\n");
183
- }
184
-
185
- if (componentName === "Switch") {
186
- lines.push(`export const Default: Story = {`);
187
- lines.push(` render: (args) => (`);
188
- lines.push(` <div className="flex items-center space-x-2">`);
189
- lines.push(` <ComponentRef id="notifications" {...args} />`);
190
- lines.push(` <Label htmlFor="notifications">Enable notifications</Label>`);
191
- lines.push(` </div>`);
192
- lines.push(` ),`);
193
- lines.push(`};`);
194
- return lines.join("\n");
195
- }
196
-
197
- if (componentName === "RadioGroup") {
198
- lines.push(`export const Default: Story = {`);
199
- lines.push(` render: (args) => (`);
200
- lines.push(` <ComponentRef className="flex flex-col space-y-2" {...args}>`);
201
- lines.push(` <div className="flex items-center space-x-2">`);
202
- lines.push(` <RadioGroupItem value="comfortable" id="comfortable" />`);
203
- lines.push(` <Label htmlFor="comfortable">Comfortable</Label>`);
204
- lines.push(` </div>`);
205
- lines.push(` <div className="flex items-center space-x-2">`);
206
- lines.push(` <RadioGroupItem value="compact" id="compact" />`);
207
- lines.push(` <Label htmlFor="compact">Compact</Label>`);
208
- lines.push(` </div>`);
209
- lines.push(` </ComponentRef>`);
210
- lines.push(` ),`);
211
- lines.push(`};`);
212
- return lines.join("\n");
213
- }
214
-
215
- if (componentName === "Select") {
216
- lines.push(`export const Default: Story = {`);
217
- lines.push(` args: { defaultValue: "apple" },`);
218
- lines.push(` render: (args) => (`);
219
- lines.push(` <ComponentRef {...args}>`);
220
- lines.push(` <SelectTrigger className="w-[180px]">`);
221
- lines.push(` <SelectValue placeholder="Select a fruit" />`);
222
- lines.push(` </SelectTrigger>`);
223
- lines.push(` <SelectContent>`);
224
- lines.push(` <SelectItem value="apple">Apple</SelectItem>`);
225
- lines.push(` <SelectItem value="banana">Banana</SelectItem>`);
226
- lines.push(` <SelectItem value="orange">Orange</SelectItem>`);
227
- lines.push(` </SelectContent>`);
228
- lines.push(` </ComponentRef>`);
229
- lines.push(` ),`);
230
- lines.push(`};`);
231
- return lines.join("\n");
232
- }
233
-
234
426
  if (componentName === "Badge") {
235
427
  const vs = variants && variants.length ? variants : ["default", "secondary", "destructive", "outline"];
236
428
  vs.forEach((v, idx) => {
@@ -246,38 +438,56 @@ function buildSpecialStories(componentName, variants) {
246
438
  return lines.join("\n");
247
439
  }
248
440
 
249
- if (componentName === "Card") {
250
- lines.push(`export const Default: Story = {`);
251
- lines.push(` render: (args) => (`);
252
- lines.push(` <ComponentRef className="w-[340px]" {...args}>`);
253
- lines.push(` <CardHeader>`);
254
- lines.push(` <CardTitle>Card title</CardTitle>`);
255
- lines.push(` <CardDescription>Short description about this card.</CardDescription>`);
256
- lines.push(` </CardHeader>`);
257
- lines.push(` <CardContent>`);
258
- lines.push(` <p>Here is some representative content inside the card body.</p>`);
259
- lines.push(` </CardContent>`);
260
- lines.push(` <CardFooter>Footer content</CardFooter>`);
261
- lines.push(` </ComponentRef>`);
262
- lines.push(` ),`);
263
- lines.push(`};`);
264
- return lines.join("\n");
265
- }
441
+ // Fallback: let the generic variant-based logic or RECIPES handle it
442
+ return "";
443
+ }
266
444
 
267
- if (componentName === "Avatar") {
268
- lines.push(`export const Default: Story = {`);
269
- lines.push(` render: (args) => (`);
270
- lines.push(` <ComponentRef {...args}>`);
271
- lines.push(` <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />`);
272
- lines.push(` <AvatarFallback>JD</AvatarFallback>`);
273
- lines.push(` </ComponentRef>`);
274
- lines.push(` ),`);
275
- lines.push(`};`);
276
- return lines.join("\n");
445
+ function buildRecipeStoryContent(comp, componentName, importPath, title, source, exportStyle, recipe) {
446
+ const lines = [];
447
+ lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
448
+ const useRouterDecorator = needsRouter(source);
449
+ if (exportStyle === "default") {
450
+ lines.push(`import ${componentName} from "${importPath}";`);
451
+ if (recipe.imports?.length) {
452
+ lines.push(`import { ${recipe.imports.join(", ")} } from "${importPath}";`);
453
+ }
454
+ lines.push(`const ComponentRef = ${componentName};`);
455
+ } else if (exportStyle === "named") {
456
+ const names = recipe.imports?.length ? [componentName, ...recipe.imports] : [componentName];
457
+ lines.push(`import { ${names.join(", ")} } from "${importPath}";`);
458
+ lines.push(`const ComponentRef = ${componentName};`);
459
+ } else {
460
+ const defaultAlias = `${componentName}Default`;
461
+ const namedAlias = `${componentName}Named`;
462
+ const extra = recipe.imports?.length ? ", " + recipe.imports.join(", ") : "";
463
+ lines.push(`import ${defaultAlias}, { ${componentName} as ${namedAlias}${extra} } from "${importPath}";`);
464
+ lines.push(`const ComponentRef = ${namedAlias} ?? ${defaultAlias};`);
277
465
  }
278
-
279
- // Fallback: let the generic variant-based logic handle it
280
- return "";
466
+ for (const ext of recipe.extraImports || []) {
467
+ lines.push(`import { ${ext.names.join(", ")} } from "${ext.from}";`);
468
+ }
469
+ if (useRouterDecorator) lines.push(`import { MemoryRouter } from "react-router-dom";`);
470
+ lines.push("");
471
+ lines.push(`const meta = {`);
472
+ lines.push(` title: ${JSON.stringify(title)},`);
473
+ lines.push(` component: ComponentRef,`);
474
+ lines.push(` tags: ["autodocs"],`);
475
+ if (useRouterDecorator) {
476
+ lines.push(` decorators: [(Story) => (`);
477
+ lines.push(` <MemoryRouter>`);
478
+ lines.push(` <Story />`);
479
+ lines.push(` </MemoryRouter>`);
480
+ lines.push(` )],`);
481
+ }
482
+ lines.push(`} satisfies Meta<typeof ComponentRef>;`);
483
+ lines.push("");
484
+ lines.push(`export default meta;`);
485
+ lines.push(`type Story = StoryObj<typeof meta>;`);
486
+ lines.push("");
487
+ lines.push(`export const Default: Story = {`);
488
+ lines.push(` render: ${recipe.render},`);
489
+ lines.push(`};`);
490
+ return lines.join("\n");
281
491
  }
282
492
 
283
493
  function buildStoryFileContent(comp) {
@@ -328,7 +538,11 @@ function buildStoryFileContent(comp) {
328
538
  // ignore
329
539
  }
330
540
  const exportStyle = detectExportStyle(source, componentName);
331
- const omitChildren = componentHasImgAndChildren(source);
541
+ const omitChildren = componentWrapsVoidElement(source);
542
+
543
+ if (RECIPES[componentName]) {
544
+ return buildRecipeStoryContent(comp, componentName, importPath, title, source, exportStyle, RECIPES[componentName]);
545
+ }
332
546
 
333
547
  const lines = [];
334
548
  lines.push(`import type { Meta, StoryObj } from "@storybook/react";`);
@@ -348,26 +562,6 @@ function buildStoryFileContent(comp) {
348
562
  lines.push(`const ComponentRef = ${namedAlias} ?? ${defaultAlias};`);
349
563
  }
350
564
 
351
- // Extra imports for composite components
352
- if (componentName === "Checkbox" || componentName === "Switch" || componentName === "RadioGroup") {
353
- lines.push(`import { Label } from "@/components/ui/label";`);
354
- }
355
- if (componentName === "RadioGroup") {
356
- lines.push(`import { RadioGroupItem } from "@/components/ui/radio-group";`);
357
- }
358
- if (componentName === "Select") {
359
- lines.push(
360
- `import { SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select";`,
361
- );
362
- }
363
- if (componentName === "Avatar") {
364
- lines.push(`import { AvatarImage, AvatarFallback } from "@/components/ui/avatar";`);
365
- }
366
- if (componentName === "Card") {
367
- lines.push(
368
- `import { CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card";`,
369
- );
370
- }
371
565
  const useRouterDecorator = needsRouter(source);
372
566
  if (useRouterDecorator) {
373
567
  lines.push(`import { MemoryRouter } from "react-router-dom";`);
@@ -395,7 +589,7 @@ function buildStoryFileContent(comp) {
395
589
  const specialStories = buildSpecialStories(componentName, variants);
396
590
  if (specialStories) {
397
591
  lines.push(specialStories);
398
- return STORY_CSS_HEADER + lines.join("\n");
592
+ return lines.join("\n");
399
593
  }
400
594
 
401
595
  // Generic variant-based stories (omit children for img/void components)
@@ -426,7 +620,7 @@ function buildStoryFileContent(comp) {
426
620
  }
427
621
  }
428
622
 
429
- return STORY_CSS_HEADER + lines.join("\n");
623
+ return lines.join("\n");
430
624
  }
431
625
 
432
626
  /** Build color entries from foundations.colors (skip _dark; flatten to { name, hex }). */
@@ -449,7 +643,6 @@ function writeFoundationsStories(foundations) {
449
643
 
450
644
  const colorEntries = getColorEntries(foundations?.colors);
451
645
  const colorsContent =
452
- STORY_CSS_HEADER +
453
646
  [
454
647
  "import type { Meta, StoryObj } from \"@storybook/react\";",
455
648
  "",
@@ -483,7 +676,6 @@ function writeFoundationsStories(foundations) {
483
676
  value: Array.isArray(v) ? v.join(", ") : String(v),
484
677
  }));
485
678
  const typoContent =
486
- STORY_CSS_HEADER +
487
679
  [
488
680
  "import type { Meta, StoryObj } from \"@storybook/react\";",
489
681
  "",
@@ -516,7 +708,6 @@ function writeFoundationsStories(foundations) {
516
708
  const brandAssets = foundations?.brand?.assets;
517
709
  const assets = Array.isArray(brandAssets) ? brandAssets : [];
518
710
  const brandContent =
519
- STORY_CSS_HEADER +
520
711
  [
521
712
  "import type { Meta, StoryObj } from \"@storybook/react\";",
522
713
  "",
@@ -593,6 +784,8 @@ function main() {
593
784
  const componentName = toSafeComponentName(comp.name, comp.file);
594
785
  if (onlyName && componentName !== onlyName) continue;
595
786
  if (SKIP_LIST.includes(componentName)) continue;
787
+ const requiredCount = Array.isArray(comp.props) ? comp.props.filter((p) => p.required === true).length : 0;
788
+ if (requiredCount > 3) continue;
596
789
 
597
790
  const storyFileName = `${componentName}.stories.tsx`;
598
791
  const storyPath = path.join(STORIES_DIR, storyFileName);
@@ -603,3 +796,4 @@ function main() {
603
796
  }
604
797
 
605
798
  main();
799
+