@thesage/mcp 0.2.1 → 0.5.0

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.
Files changed (3) hide show
  1. package/dist/index.js +1559 -70
  2. package/dist/index.mjs +1559 -70
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11,37 +11,57 @@ var COMPONENT_CATEGORIES = {
11
11
  actions: {
12
12
  label: "Actions",
13
13
  description: "Interactive elements that trigger behaviors",
14
- count: 3
14
+ count: 5
15
15
  },
16
16
  forms: {
17
17
  label: "Forms",
18
18
  description: "Input controls for data collection",
19
- count: 11
19
+ count: 18
20
20
  },
21
21
  navigation: {
22
22
  label: "Navigation",
23
23
  description: "Moving through content and hierarchy",
24
- count: 6
24
+ count: 10
25
25
  },
26
26
  overlays: {
27
27
  label: "Overlays",
28
28
  description: "Contextual content that appears above the main UI",
29
- count: 9
29
+ count: 11
30
30
  },
31
31
  feedback: {
32
32
  label: "Feedback",
33
33
  description: "Communicating system state and user action results",
34
- count: 5
34
+ count: 7
35
35
  },
36
36
  "data-display": {
37
37
  label: "Data Display",
38
38
  description: "Presenting information in structured formats",
39
- count: 6
39
+ count: 16
40
40
  },
41
41
  layout: {
42
42
  label: "Layout",
43
43
  description: "Spatial organization and structural elements",
44
- count: 8
44
+ count: 17
45
+ },
46
+ backgrounds: {
47
+ label: "Backgrounds",
48
+ description: "Animated background effects and decorative elements",
49
+ count: 3
50
+ },
51
+ cursor: {
52
+ label: "Cursor",
53
+ description: "Custom cursor effects and interactions",
54
+ count: 2
55
+ },
56
+ motion: {
57
+ label: "Motion",
58
+ description: "Animation components and motion effects",
59
+ count: 1
60
+ },
61
+ blocks: {
62
+ label: "Blocks",
63
+ description: "Composed page sections and layouts",
64
+ count: 2
45
65
  }
46
66
  };
47
67
  var COMPONENT_REGISTRY = {
@@ -60,7 +80,14 @@ var COMPONENT_REGISTRY = {
60
80
  "Call-to-action elements"
61
81
  ],
62
82
  dependencies: ["@radix-ui/react-slot"],
63
- radixPrimitive: "@radix-ui/react-slot"
83
+ radixPrimitive: "@radix-ui/react-slot",
84
+ props: {
85
+ variant: { type: "'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'", default: "'default'", description: "Visual style variant" },
86
+ size: { type: "'sm' | 'default' | 'lg' | 'icon'", default: "'default'", description: "Size variant" },
87
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" },
88
+ asChild: { type: "boolean", default: "false", description: "Render as child element via Radix Slot" }
89
+ },
90
+ example: `<Button variant="outline" size="sm" onClick={handleClick}>Click Me</Button>`
64
91
  },
65
92
  toggle: {
66
93
  name: "Toggle",
@@ -74,7 +101,15 @@ var COMPONENT_REGISTRY = {
74
101
  "Filter activation"
75
102
  ],
76
103
  dependencies: ["@radix-ui/react-toggle"],
77
- radixPrimitive: "@radix-ui/react-toggle"
104
+ radixPrimitive: "@radix-ui/react-toggle",
105
+ props: {
106
+ pressed: { type: "boolean", description: "Controlled pressed state" },
107
+ onPressedChange: { type: "(pressed: boolean) => void", description: "Callback on press change" },
108
+ variant: { type: "'default' | 'outline'", default: "'default'", description: "Visual variant" },
109
+ size: { type: "'sm' | 'default' | 'lg'", default: "'default'", description: "Size variant" },
110
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" }
111
+ },
112
+ example: `<Toggle pressed={isBold} onPressedChange={setIsBold}><Bold className="h-4 w-4" /></Toggle>`
78
113
  },
79
114
  "toggle-group": {
80
115
  name: "ToggleGroup",
@@ -88,7 +123,19 @@ var COMPONENT_REGISTRY = {
88
123
  "Option selection"
89
124
  ],
90
125
  dependencies: ["@radix-ui/react-toggle-group"],
91
- radixPrimitive: "@radix-ui/react-toggle-group"
126
+ radixPrimitive: "@radix-ui/react-toggle-group",
127
+ props: {
128
+ type: { type: "'single' | 'multiple'", description: "Selection mode", required: true },
129
+ value: { type: "string | string[]", description: "Selected value(s)" },
130
+ onValueChange: { type: "(value) => void", description: "Callback on value change" },
131
+ variant: { type: "'default' | 'outline'", default: "'default'", description: "Visual variant" },
132
+ size: { type: "'sm' | 'default' | 'lg'", default: "'default'", description: "Size variant" }
133
+ },
134
+ subComponents: ["ToggleGroupItem"],
135
+ example: `<ToggleGroup type="single" value={align} onValueChange={setAlign}>
136
+ <ToggleGroupItem value="left">Left</ToggleGroupItem>
137
+ <ToggleGroupItem value="center">Center</ToggleGroupItem>
138
+ </ToggleGroup>`
92
139
  },
93
140
  // ============================================================================
94
141
  // FORMS (11)
@@ -105,7 +152,16 @@ var COMPONENT_REGISTRY = {
105
152
  "Bulk actions"
106
153
  ],
107
154
  dependencies: ["@radix-ui/react-checkbox"],
108
- radixPrimitive: "@radix-ui/react-checkbox"
155
+ radixPrimitive: "@radix-ui/react-checkbox",
156
+ props: {
157
+ checked: { type: "boolean | 'indeterminate'", description: "Checked state" },
158
+ onCheckedChange: { type: "(checked: boolean) => void", description: "Callback on check change" },
159
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" }
160
+ },
161
+ example: `<div className="flex items-center gap-2">
162
+ <Checkbox id="terms" checked={accepted} onCheckedChange={setAccepted} />
163
+ <Label htmlFor="terms">Accept terms</Label>
164
+ </div>`
109
165
  },
110
166
  combobox: {
111
167
  name: "Combobox",
@@ -119,7 +175,21 @@ var COMPONENT_REGISTRY = {
119
175
  "Large option lists"
120
176
  ],
121
177
  dependencies: ["cmdk", "@radix-ui/react-popover"],
122
- radixPrimitive: "@radix-ui/react-popover"
178
+ radixPrimitive: "@radix-ui/react-popover",
179
+ props: {
180
+ options: { type: "{ value: string; label: string }[]", description: "List of options", required: true },
181
+ value: { type: "string", description: "Selected value" },
182
+ onValueChange: { type: "(value: string) => void", description: "Callback on selection" },
183
+ placeholder: { type: "string", description: "Trigger placeholder text" },
184
+ searchPlaceholder: { type: "string", description: "Search input placeholder" },
185
+ emptyText: { type: "string", description: "Text when no results found" }
186
+ },
187
+ example: `<Combobox
188
+ options={[{ value: 'react', label: 'React' }, { value: 'vue', label: 'Vue' }]}
189
+ value={framework}
190
+ onValueChange={setFramework}
191
+ placeholder="Select framework"
192
+ />`
123
193
  },
124
194
  form: {
125
195
  name: "Form",
@@ -132,7 +202,23 @@ var COMPONENT_REGISTRY = {
132
202
  "Data entry",
133
203
  "Multi-step forms"
134
204
  ],
135
- dependencies: ["react-hook-form", "@hookform/resolvers", "zod"]
205
+ dependencies: ["react-hook-form", "@hookform/resolvers", "zod"],
206
+ props: {
207
+ "...form": { type: "UseFormReturn", description: "Spread react-hook-form useForm() return value", required: true }
208
+ },
209
+ subComponents: ["FormControl", "FormDescription", "FormField", "FormItem", "FormLabel", "FormMessage"],
210
+ example: `<Form {...form}>
211
+ <form onSubmit={form.handleSubmit(onSubmit)}>
212
+ <FormField control={form.control} name="email" render={({ field }) => (
213
+ <FormItem>
214
+ <FormLabel>Email</FormLabel>
215
+ <FormControl><Input {...field} /></FormControl>
216
+ <FormMessage />
217
+ </FormItem>
218
+ )} />
219
+ <Button type="submit">Submit</Button>
220
+ </form>
221
+ </Form>`
136
222
  },
137
223
  input: {
138
224
  name: "Input",
@@ -145,7 +231,13 @@ var COMPONENT_REGISTRY = {
145
231
  "Passwords",
146
232
  "Numeric input"
147
233
  ],
148
- dependencies: []
234
+ dependencies: [],
235
+ props: {
236
+ type: { type: "string", default: "'text'", description: "HTML input type" },
237
+ placeholder: { type: "string", description: "Placeholder text" },
238
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" }
239
+ },
240
+ example: `<Input type="email" placeholder="Enter email" />`
149
241
  },
150
242
  "input-otp": {
151
243
  name: "InputOTP",
@@ -158,7 +250,26 @@ var COMPONENT_REGISTRY = {
158
250
  "Phone verification",
159
251
  "Security codes"
160
252
  ],
161
- dependencies: ["input-otp"]
253
+ dependencies: ["input-otp"],
254
+ props: {
255
+ maxLength: { type: "number", default: "6", description: "Maximum number of characters" },
256
+ value: { type: "string", description: "Controlled input value" },
257
+ onChange: { type: "(value: string) => void", description: "Callback on value change" }
258
+ },
259
+ subComponents: ["InputOTPGroup", "InputOTPSlot", "InputOTPSeparator"],
260
+ example: `<InputOTP maxLength={6}>
261
+ <InputOTPGroup>
262
+ <InputOTPSlot index={0} />
263
+ <InputOTPSlot index={1} />
264
+ <InputOTPSlot index={2} />
265
+ </InputOTPGroup>
266
+ <InputOTPSeparator />
267
+ <InputOTPGroup>
268
+ <InputOTPSlot index={3} />
269
+ <InputOTPSlot index={4} />
270
+ <InputOTPSlot index={5} />
271
+ </InputOTPGroup>
272
+ </InputOTP>`
162
273
  },
163
274
  label: {
164
275
  name: "Label",
@@ -171,7 +282,12 @@ var COMPONENT_REGISTRY = {
171
282
  "Accessible forms"
172
283
  ],
173
284
  dependencies: ["@radix-ui/react-label"],
174
- radixPrimitive: "@radix-ui/react-label"
285
+ radixPrimitive: "@radix-ui/react-label",
286
+ props: {
287
+ htmlFor: { type: "string", description: "ID of the associated form control" }
288
+ },
289
+ example: `<Label htmlFor="email">Email Address</Label>
290
+ <Input id="email" type="email" />`
175
291
  },
176
292
  "radio-group": {
177
293
  name: "RadioGroup",
@@ -185,7 +301,19 @@ var COMPONENT_REGISTRY = {
185
301
  "Shipping options"
186
302
  ],
187
303
  dependencies: ["@radix-ui/react-radio-group"],
188
- radixPrimitive: "@radix-ui/react-radio-group"
304
+ radixPrimitive: "@radix-ui/react-radio-group",
305
+ props: {
306
+ value: { type: "string", description: "Controlled selected value" },
307
+ onValueChange: { type: "(value: string) => void", description: "Callback on selection" },
308
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" }
309
+ },
310
+ subComponents: ["RadioGroupItem"],
311
+ example: `<RadioGroup value={plan} onValueChange={setPlan}>
312
+ <div className="flex items-center gap-2">
313
+ <RadioGroupItem value="free" id="free" />
314
+ <Label htmlFor="free">Free</Label>
315
+ </div>
316
+ </RadioGroup>`
189
317
  },
190
318
  select: {
191
319
  name: "Select",
@@ -199,7 +327,22 @@ var COMPONENT_REGISTRY = {
199
327
  "Data sorting"
200
328
  ],
201
329
  dependencies: ["@radix-ui/react-select"],
202
- radixPrimitive: "@radix-ui/react-select"
330
+ radixPrimitive: "@radix-ui/react-select",
331
+ props: {
332
+ value: { type: "string", description: "Controlled selected value" },
333
+ onValueChange: { type: "(value: string) => void", description: "Callback on selection" },
334
+ defaultValue: { type: "string", description: "Default selected value" }
335
+ },
336
+ subComponents: ["SelectTrigger", "SelectValue", "SelectContent", "SelectItem", "SelectGroup", "SelectLabel", "SelectSeparator"],
337
+ example: `<Select value={theme} onValueChange={setTheme}>
338
+ <SelectTrigger className="w-[180px]">
339
+ <SelectValue placeholder="Select theme" />
340
+ </SelectTrigger>
341
+ <SelectContent>
342
+ <SelectItem value="light">Light</SelectItem>
343
+ <SelectItem value="dark">Dark</SelectItem>
344
+ </SelectContent>
345
+ </Select>`
203
346
  },
204
347
  slider: {
205
348
  name: "Slider",
@@ -213,7 +356,16 @@ var COMPONENT_REGISTRY = {
213
356
  "Zoom level"
214
357
  ],
215
358
  dependencies: ["@radix-ui/react-slider"],
216
- radixPrimitive: "@radix-ui/react-slider"
359
+ radixPrimitive: "@radix-ui/react-slider",
360
+ props: {
361
+ value: { type: "number[]", description: "Current value(s)" },
362
+ onValueChange: { type: "(value: number[]) => void", description: "Callback on value change" },
363
+ min: { type: "number", default: "0", description: "Minimum value" },
364
+ max: { type: "number", default: "100", description: "Maximum value" },
365
+ step: { type: "number", default: "1", description: "Step increment" },
366
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" }
367
+ },
368
+ example: `<Slider value={[volume]} onValueChange={(v) => setVolume(v[0])} max={100} step={1} />`
217
369
  },
218
370
  switch: {
219
371
  name: "Switch",
@@ -227,7 +379,15 @@ var COMPONENT_REGISTRY = {
227
379
  "Mode switches"
228
380
  ],
229
381
  dependencies: ["@radix-ui/react-switch"],
230
- radixPrimitive: "@radix-ui/react-switch"
382
+ radixPrimitive: "@radix-ui/react-switch",
383
+ props: {
384
+ checked: { type: "boolean", description: "Controlled checked state" },
385
+ onCheckedChange: { type: "(checked: boolean) => void", description: "Callback on toggle" },
386
+ size: { type: "'sm' | 'md' | 'lg'", default: "'md'", description: "Size variant" },
387
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" },
388
+ label: { type: "string", description: "Optional label text" }
389
+ },
390
+ example: `<Switch checked={enabled} onCheckedChange={setEnabled} size="md" />`
231
391
  },
232
392
  textarea: {
233
393
  name: "Textarea",
@@ -240,7 +400,13 @@ var COMPONENT_REGISTRY = {
240
400
  "Descriptions",
241
401
  "Long-form text"
242
402
  ],
243
- dependencies: []
403
+ dependencies: [],
404
+ props: {
405
+ placeholder: { type: "string", description: "Placeholder text" },
406
+ disabled: { type: "boolean", default: "false", description: "Disable interaction" },
407
+ rows: { type: "number", description: "Number of visible rows" }
408
+ },
409
+ example: `<Textarea placeholder="Write your message..." rows={4} />`
244
410
  },
245
411
  // ============================================================================
246
412
  // NAVIGATION (6)
@@ -256,7 +422,17 @@ var COMPONENT_REGISTRY = {
256
422
  "Location context",
257
423
  "Back navigation"
258
424
  ],
259
- dependencies: []
425
+ dependencies: [],
426
+ subComponents: ["BreadcrumbList", "BreadcrumbItem", "BreadcrumbLink", "BreadcrumbPage", "BreadcrumbSeparator", "BreadcrumbEllipsis"],
427
+ example: `<Breadcrumb>
428
+ <BreadcrumbList>
429
+ <BreadcrumbItem><BreadcrumbLink href="/">Home</BreadcrumbLink></BreadcrumbItem>
430
+ <BreadcrumbSeparator />
431
+ <BreadcrumbItem><BreadcrumbLink href="/docs">Docs</BreadcrumbLink></BreadcrumbItem>
432
+ <BreadcrumbSeparator />
433
+ <BreadcrumbItem><BreadcrumbPage>Current</BreadcrumbPage></BreadcrumbItem>
434
+ </BreadcrumbList>
435
+ </Breadcrumb>`
260
436
  },
261
437
  command: {
262
438
  name: "Command",
@@ -269,7 +445,18 @@ var COMPONENT_REGISTRY = {
269
445
  "Keyboard shortcuts",
270
446
  "Power user features"
271
447
  ],
272
- dependencies: ["cmdk"]
448
+ dependencies: ["cmdk"],
449
+ subComponents: ["CommandInput", "CommandList", "CommandEmpty", "CommandGroup", "CommandItem", "CommandSeparator", "CommandShortcut", "CommandDialog"],
450
+ example: `<Command>
451
+ <CommandInput placeholder="Type a command..." />
452
+ <CommandList>
453
+ <CommandEmpty>No results found.</CommandEmpty>
454
+ <CommandGroup heading="Actions">
455
+ <CommandItem>Search</CommandItem>
456
+ <CommandItem>Settings</CommandItem>
457
+ </CommandGroup>
458
+ </CommandList>
459
+ </Command>`
273
460
  },
274
461
  menubar: {
275
462
  name: "Menubar",
@@ -283,7 +470,19 @@ var COMPONENT_REGISTRY = {
283
470
  "Editor toolbars"
284
471
  ],
285
472
  dependencies: ["@radix-ui/react-menubar"],
286
- radixPrimitive: "@radix-ui/react-menubar"
473
+ radixPrimitive: "@radix-ui/react-menubar",
474
+ subComponents: ["MenubarMenu", "MenubarTrigger", "MenubarContent", "MenubarItem", "MenubarSeparator", "MenubarLabel", "MenubarCheckboxItem", "MenubarRadioGroup", "MenubarRadioItem", "MenubarSub", "MenubarSubTrigger", "MenubarSubContent", "MenubarShortcut"],
475
+ example: `<Menubar>
476
+ <MenubarMenu>
477
+ <MenubarTrigger>File</MenubarTrigger>
478
+ <MenubarContent>
479
+ <MenubarItem>New <MenubarShortcut>\u2318N</MenubarShortcut></MenubarItem>
480
+ <MenubarItem>Open <MenubarShortcut>\u2318O</MenubarShortcut></MenubarItem>
481
+ <MenubarSeparator />
482
+ <MenubarItem>Exit</MenubarItem>
483
+ </MenubarContent>
484
+ </MenubarMenu>
485
+ </Menubar>`
287
486
  },
288
487
  "navigation-menu": {
289
488
  name: "NavigationMenu",
@@ -297,7 +496,18 @@ var COMPONENT_REGISTRY = {
297
496
  "Multi-level navigation"
298
497
  ],
299
498
  dependencies: ["@radix-ui/react-navigation-menu"],
300
- radixPrimitive: "@radix-ui/react-navigation-menu"
499
+ radixPrimitive: "@radix-ui/react-navigation-menu",
500
+ subComponents: ["NavigationMenuList", "NavigationMenuItem", "NavigationMenuTrigger", "NavigationMenuContent", "NavigationMenuLink", "NavigationMenuIndicator", "NavigationMenuViewport"],
501
+ example: `<NavigationMenu>
502
+ <NavigationMenuList>
503
+ <NavigationMenuItem>
504
+ <NavigationMenuTrigger>Getting Started</NavigationMenuTrigger>
505
+ <NavigationMenuContent>
506
+ <NavigationMenuLink href="/docs">Documentation</NavigationMenuLink>
507
+ </NavigationMenuContent>
508
+ </NavigationMenuItem>
509
+ </NavigationMenuList>
510
+ </NavigationMenu>`
301
511
  },
302
512
  pagination: {
303
513
  name: "Pagination",
@@ -310,7 +520,17 @@ var COMPONENT_REGISTRY = {
310
520
  "Content lists",
311
521
  "Multi-page forms"
312
522
  ],
313
- dependencies: []
523
+ dependencies: [],
524
+ subComponents: ["PaginationContent", "PaginationItem", "PaginationLink", "PaginationPrevious", "PaginationNext", "PaginationEllipsis"],
525
+ example: `<Pagination>
526
+ <PaginationContent>
527
+ <PaginationItem><PaginationPrevious href="#" /></PaginationItem>
528
+ <PaginationItem><PaginationLink href="#">1</PaginationLink></PaginationItem>
529
+ <PaginationItem><PaginationLink href="#" isActive>2</PaginationLink></PaginationItem>
530
+ <PaginationItem><PaginationLink href="#">3</PaginationLink></PaginationItem>
531
+ <PaginationItem><PaginationNext href="#" /></PaginationItem>
532
+ </PaginationContent>
533
+ </Pagination>`
314
534
  },
315
535
  tabs: {
316
536
  name: "Tabs",
@@ -324,7 +544,21 @@ var COMPONENT_REGISTRY = {
324
544
  "Dashboard sections"
325
545
  ],
326
546
  dependencies: ["@radix-ui/react-tabs"],
327
- radixPrimitive: "@radix-ui/react-tabs"
547
+ radixPrimitive: "@radix-ui/react-tabs",
548
+ props: {
549
+ defaultValue: { type: "string", description: "Default active tab value" },
550
+ value: { type: "string", description: "Controlled active tab value" },
551
+ onValueChange: { type: "(value: string) => void", description: "Callback on tab change" }
552
+ },
553
+ subComponents: ["TabsList", "TabsTrigger", "TabsContent"],
554
+ example: `<Tabs defaultValue="account">
555
+ <TabsList>
556
+ <TabsTrigger value="account">Account</TabsTrigger>
557
+ <TabsTrigger value="password">Password</TabsTrigger>
558
+ </TabsList>
559
+ <TabsContent value="account">Account settings here.</TabsContent>
560
+ <TabsContent value="password">Password settings here.</TabsContent>
561
+ </Tabs>`
328
562
  },
329
563
  // ============================================================================
330
564
  // OVERLAYS (9)
@@ -341,7 +575,25 @@ var COMPONENT_REGISTRY = {
341
575
  "Irreversible operations"
342
576
  ],
343
577
  dependencies: ["@radix-ui/react-alert-dialog"],
344
- radixPrimitive: "@radix-ui/react-alert-dialog"
578
+ radixPrimitive: "@radix-ui/react-alert-dialog",
579
+ props: {
580
+ open: { type: "boolean", description: "Controlled open state" },
581
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" }
582
+ },
583
+ subComponents: ["AlertDialogTrigger", "AlertDialogContent", "AlertDialogHeader", "AlertDialogTitle", "AlertDialogDescription", "AlertDialogFooter", "AlertDialogAction", "AlertDialogCancel"],
584
+ example: `<AlertDialog>
585
+ <AlertDialogTrigger asChild><Button variant="destructive">Delete</Button></AlertDialogTrigger>
586
+ <AlertDialogContent>
587
+ <AlertDialogHeader>
588
+ <AlertDialogTitle>Are you sure?</AlertDialogTitle>
589
+ <AlertDialogDescription>This cannot be undone.</AlertDialogDescription>
590
+ </AlertDialogHeader>
591
+ <AlertDialogFooter>
592
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
593
+ <AlertDialogAction>Delete</AlertDialogAction>
594
+ </AlertDialogFooter>
595
+ </AlertDialogContent>
596
+ </AlertDialog>`
345
597
  },
346
598
  "context-menu": {
347
599
  name: "ContextMenu",
@@ -355,7 +607,17 @@ var COMPONENT_REGISTRY = {
355
607
  "Item actions"
356
608
  ],
357
609
  dependencies: ["@radix-ui/react-context-menu"],
358
- radixPrimitive: "@radix-ui/react-context-menu"
610
+ radixPrimitive: "@radix-ui/react-context-menu",
611
+ subComponents: ["ContextMenuTrigger", "ContextMenuContent", "ContextMenuItem", "ContextMenuCheckboxItem", "ContextMenuRadioItem", "ContextMenuLabel", "ContextMenuSeparator", "ContextMenuShortcut", "ContextMenuSub", "ContextMenuSubTrigger", "ContextMenuSubContent", "ContextMenuRadioGroup"],
612
+ example: `<ContextMenu>
613
+ <ContextMenuTrigger>Right click here</ContextMenuTrigger>
614
+ <ContextMenuContent>
615
+ <ContextMenuItem>Edit</ContextMenuItem>
616
+ <ContextMenuItem>Duplicate</ContextMenuItem>
617
+ <ContextMenuSeparator />
618
+ <ContextMenuItem>Delete</ContextMenuItem>
619
+ </ContextMenuContent>
620
+ </ContextMenu>`
359
621
  },
360
622
  dialog: {
361
623
  name: "Dialog",
@@ -369,7 +631,25 @@ var COMPONENT_REGISTRY = {
369
631
  "User input"
370
632
  ],
371
633
  dependencies: ["@radix-ui/react-dialog"],
372
- radixPrimitive: "@radix-ui/react-dialog"
634
+ radixPrimitive: "@radix-ui/react-dialog",
635
+ props: {
636
+ open: { type: "boolean", description: "Controlled open state" },
637
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" }
638
+ },
639
+ subComponents: ["DialogTrigger", "DialogContent", "DialogHeader", "DialogTitle", "DialogDescription", "DialogFooter", "DialogClose"],
640
+ example: `<Dialog>
641
+ <DialogTrigger asChild><Button>Open</Button></DialogTrigger>
642
+ <DialogContent>
643
+ <DialogHeader>
644
+ <DialogTitle>Title</DialogTitle>
645
+ <DialogDescription>Description here.</DialogDescription>
646
+ </DialogHeader>
647
+ <DialogFooter>
648
+ <Button variant="outline">Cancel</Button>
649
+ <Button>Confirm</Button>
650
+ </DialogFooter>
651
+ </DialogContent>
652
+ </Dialog>`
373
653
  },
374
654
  drawer: {
375
655
  name: "Drawer",
@@ -382,7 +662,26 @@ var COMPONENT_REGISTRY = {
382
662
  "Bottom sheets",
383
663
  "Mobile menus"
384
664
  ],
385
- dependencies: ["vaul"]
665
+ dependencies: ["vaul"],
666
+ props: {
667
+ open: { type: "boolean", description: "Controlled open state" },
668
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" }
669
+ },
670
+ subComponents: ["DrawerTrigger", "DrawerContent", "DrawerHeader", "DrawerTitle", "DrawerDescription", "DrawerFooter", "DrawerClose"],
671
+ example: `<Drawer>
672
+ <DrawerTrigger asChild><Button>Open Drawer</Button></DrawerTrigger>
673
+ <DrawerContent>
674
+ <DrawerHeader>
675
+ <DrawerTitle>Settings</DrawerTitle>
676
+ <DrawerDescription>Adjust preferences.</DrawerDescription>
677
+ </DrawerHeader>
678
+ <div className="p-4">Content here.</div>
679
+ <DrawerFooter>
680
+ <Button>Save</Button>
681
+ <DrawerClose asChild><Button variant="outline">Cancel</Button></DrawerClose>
682
+ </DrawerFooter>
683
+ </DrawerContent>
684
+ </Drawer>`
386
685
  },
387
686
  "dropdown-menu": {
388
687
  name: "DropdownMenu",
@@ -396,7 +695,21 @@ var COMPONENT_REGISTRY = {
396
695
  "Overflow menus"
397
696
  ],
398
697
  dependencies: ["@radix-ui/react-dropdown-menu"],
399
- radixPrimitive: "@radix-ui/react-dropdown-menu"
698
+ radixPrimitive: "@radix-ui/react-dropdown-menu",
699
+ props: {
700
+ open: { type: "boolean", description: "Controlled open state" },
701
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" }
702
+ },
703
+ subComponents: ["DropdownMenuTrigger", "DropdownMenuContent", "DropdownMenuItem", "DropdownMenuLabel", "DropdownMenuSeparator", "DropdownMenuCheckboxItem", "DropdownMenuRadioGroup", "DropdownMenuRadioItem", "DropdownMenuSub", "DropdownMenuSubTrigger", "DropdownMenuSubContent"],
704
+ example: `<DropdownMenu>
705
+ <DropdownMenuTrigger asChild><Button variant="ghost">Options</Button></DropdownMenuTrigger>
706
+ <DropdownMenuContent>
707
+ <DropdownMenuLabel>Actions</DropdownMenuLabel>
708
+ <DropdownMenuSeparator />
709
+ <DropdownMenuItem>Edit</DropdownMenuItem>
710
+ <DropdownMenuItem>Delete</DropdownMenuItem>
711
+ </DropdownMenuContent>
712
+ </DropdownMenu>`
400
713
  },
401
714
  "hover-card": {
402
715
  name: "HoverCard",
@@ -410,7 +723,21 @@ var COMPONENT_REGISTRY = {
410
723
  "Additional context"
411
724
  ],
412
725
  dependencies: ["@radix-ui/react-hover-card"],
413
- radixPrimitive: "@radix-ui/react-hover-card"
726
+ radixPrimitive: "@radix-ui/react-hover-card",
727
+ props: {
728
+ openDelay: { type: "number", default: "700", description: "Delay in ms before opening" },
729
+ closeDelay: { type: "number", default: "300", description: "Delay in ms before closing" }
730
+ },
731
+ subComponents: ["HoverCardTrigger", "HoverCardContent"],
732
+ example: `<HoverCard>
733
+ <HoverCardTrigger asChild><Link href="#">@username</Link></HoverCardTrigger>
734
+ <HoverCardContent className="w-80">
735
+ <div className="flex gap-4">
736
+ <Avatar />
737
+ <div><p className="text-sm font-semibold">Username</p><p className="text-sm text-muted-foreground">Bio here.</p></div>
738
+ </div>
739
+ </HoverCardContent>
740
+ </HoverCard>`
414
741
  },
415
742
  popover: {
416
743
  name: "Popover",
@@ -424,7 +751,16 @@ var COMPONENT_REGISTRY = {
424
751
  "Inline editors"
425
752
  ],
426
753
  dependencies: ["@radix-ui/react-popover"],
427
- radixPrimitive: "@radix-ui/react-popover"
754
+ radixPrimitive: "@radix-ui/react-popover",
755
+ props: {
756
+ open: { type: "boolean", description: "Controlled open state" },
757
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" }
758
+ },
759
+ subComponents: ["PopoverTrigger", "PopoverContent", "PopoverAnchor"],
760
+ example: `<Popover>
761
+ <PopoverTrigger asChild><Button variant="outline">Open</Button></PopoverTrigger>
762
+ <PopoverContent className="w-80">Content here.</PopoverContent>
763
+ </Popover>`
428
764
  },
429
765
  sheet: {
430
766
  name: "Sheet",
@@ -438,7 +774,19 @@ var COMPONENT_REGISTRY = {
438
774
  "Detail views"
439
775
  ],
440
776
  dependencies: ["@radix-ui/react-dialog"],
441
- radixPrimitive: "@radix-ui/react-dialog"
777
+ radixPrimitive: "@radix-ui/react-dialog",
778
+ props: {
779
+ open: { type: "boolean", description: "Controlled open state" },
780
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" }
781
+ },
782
+ subComponents: ["SheetTrigger", "SheetContent", "SheetHeader", "SheetTitle", "SheetDescription", "SheetClose"],
783
+ example: `<Sheet>
784
+ <SheetTrigger asChild><Button>Open</Button></SheetTrigger>
785
+ <SheetContent side="right">
786
+ <SheetHeader><SheetTitle>Settings</SheetTitle></SheetHeader>
787
+ <div className="p-4">Content here.</div>
788
+ </SheetContent>
789
+ </Sheet>`
442
790
  },
443
791
  tooltip: {
444
792
  name: "Tooltip",
@@ -452,7 +800,12 @@ var COMPONENT_REGISTRY = {
452
800
  "Keyboard shortcuts"
453
801
  ],
454
802
  dependencies: ["@radix-ui/react-tooltip"],
455
- radixPrimitive: "@radix-ui/react-tooltip"
803
+ radixPrimitive: "@radix-ui/react-tooltip",
804
+ subComponents: ["TooltipTrigger", "TooltipContent", "TooltipProvider"],
805
+ example: `<Tooltip>
806
+ <TooltipTrigger asChild><Button variant="ghost" size="icon"><Info /></Button></TooltipTrigger>
807
+ <TooltipContent><p>Helpful information</p></TooltipContent>
808
+ </Tooltip>`
456
809
  },
457
810
  // ============================================================================
458
811
  // FEEDBACK (5)
@@ -468,7 +821,15 @@ var COMPONENT_REGISTRY = {
468
821
  "Errors",
469
822
  "Success confirmations"
470
823
  ],
471
- dependencies: []
824
+ dependencies: [],
825
+ props: {
826
+ variant: { type: "'default' | 'destructive'", default: "'default'", description: "Visual variant" }
827
+ },
828
+ subComponents: ["AlertTitle", "AlertDescription"],
829
+ example: `<Alert variant="destructive">
830
+ <AlertTitle>Error</AlertTitle>
831
+ <AlertDescription>Your session has expired.</AlertDescription>
832
+ </Alert>`
472
833
  },
473
834
  progress: {
474
835
  name: "Progress",
@@ -482,7 +843,12 @@ var COMPONENT_REGISTRY = {
482
843
  "Multi-step forms"
483
844
  ],
484
845
  dependencies: ["@radix-ui/react-progress"],
485
- radixPrimitive: "@radix-ui/react-progress"
846
+ radixPrimitive: "@radix-ui/react-progress",
847
+ props: {
848
+ value: { type: "number", default: "0", description: "Progress value (0-100)" },
849
+ max: { type: "number", default: "100", description: "Maximum value" }
850
+ },
851
+ example: `<Progress value={60} />`
486
852
  },
487
853
  skeleton: {
488
854
  name: "Skeleton",
@@ -495,12 +861,22 @@ var COMPONENT_REGISTRY = {
495
861
  "Initial load",
496
862
  "Lazy loading"
497
863
  ],
498
- dependencies: []
864
+ dependencies: [],
865
+ props: {
866
+ variant: { type: "'default' | 'circular' | 'rectangular' | 'text'", default: "'default'", description: "Shape variant" },
867
+ width: { type: "string", default: "'100%'", description: "Width (CSS value)" },
868
+ height: { type: "string", default: "'20px'", description: "Height (CSS value)" }
869
+ },
870
+ example: `<div className="space-y-2">
871
+ <Skeleton className="h-12 w-12 rounded-full" />
872
+ <Skeleton className="h-4 w-[250px]" />
873
+ <Skeleton className="h-4 w-[200px]" />
874
+ </div>`
499
875
  },
500
876
  sonner: {
501
877
  name: "Sonner",
502
878
  category: "feedback",
503
- description: "Toast notification system with queuing and positioning",
879
+ description: "Toast notification system with queuing and positioning. Use Toaster component in layout, call toast() to trigger.",
504
880
  keywords: ["toast", "notification", "sonner", "message", "alert"],
505
881
  useCases: [
506
882
  "Success messages",
@@ -508,7 +884,14 @@ var COMPONENT_REGISTRY = {
508
884
  "Action feedback",
509
885
  "System messages"
510
886
  ],
511
- dependencies: ["sonner"]
887
+ dependencies: ["sonner"],
888
+ subComponents: ["Toaster"],
889
+ example: `// In layout: <Toaster />
890
+ // To trigger:
891
+ import { toast } from 'sonner'
892
+ toast.success('Saved successfully')
893
+ toast.error('Something went wrong')
894
+ toast('Default notification')`
512
895
  },
513
896
  toast: {
514
897
  name: "Toast",
@@ -522,7 +905,13 @@ var COMPONENT_REGISTRY = {
522
905
  "Confirmation messages"
523
906
  ],
524
907
  dependencies: ["@radix-ui/react-toast"],
525
- radixPrimitive: "@radix-ui/react-toast"
908
+ radixPrimitive: "@radix-ui/react-toast",
909
+ subComponents: ["ToastAction", "ToastClose", "ToastDescription", "ToastProvider", "ToastTitle", "ToastViewport"],
910
+ example: `// Prefer using Sonner (Toaster + toast()) for new projects.
911
+ // This is the Radix-based alternative.
912
+ import { useToast } from '@thesage/ui'
913
+ const { toast } = useToast()
914
+ toast({ title: 'Success', description: 'Item saved.' })`
526
915
  },
527
916
  // ============================================================================
528
917
  // DATA DISPLAY (6)
@@ -539,7 +928,12 @@ var COMPONENT_REGISTRY = {
539
928
  "Chat participants"
540
929
  ],
541
930
  dependencies: ["@radix-ui/react-avatar"],
542
- radixPrimitive: "@radix-ui/react-avatar"
931
+ radixPrimitive: "@radix-ui/react-avatar",
932
+ subComponents: ["AvatarImage", "AvatarFallback"],
933
+ example: `<Avatar>
934
+ <AvatarImage src="/avatar.jpg" alt="User" />
935
+ <AvatarFallback>JD</AvatarFallback>
936
+ </Avatar>`
543
937
  },
544
938
  badge: {
545
939
  name: "Badge",
@@ -552,7 +946,13 @@ var COMPONENT_REGISTRY = {
552
946
  "Categories",
553
947
  "Notification counts"
554
948
  ],
555
- dependencies: []
949
+ dependencies: [],
950
+ props: {
951
+ variant: { type: "'default' | 'secondary' | 'destructive' | 'outline' | 'success' | 'warning' | 'error' | 'info'", default: "'default'", description: "Visual variant" },
952
+ size: { type: "'sm' | 'md' | 'lg'", default: "'md'", description: "Size variant" },
953
+ dot: { type: "boolean", default: "false", description: "Show animated indicator dot" }
954
+ },
955
+ example: `<Badge variant="success" dot>Active</Badge>`
556
956
  },
557
957
  calendar: {
558
958
  name: "Calendar",
@@ -565,7 +965,15 @@ var COMPONENT_REGISTRY = {
565
965
  "Booking systems",
566
966
  "Date ranges"
567
967
  ],
568
- dependencies: ["react-day-picker", "date-fns"]
968
+ dependencies: ["react-day-picker", "date-fns"],
969
+ props: {
970
+ mode: { type: "'single' | 'multiple' | 'range'", default: "'single'", description: "Selection mode" },
971
+ selected: { type: "Date | Date[] | DateRange", description: "Selected date(s)" },
972
+ onSelect: { type: "(date) => void", description: "Callback on date selection" },
973
+ showOutsideDays: { type: "boolean", default: "true", description: "Show days from adjacent months" },
974
+ disabled: { type: "Matcher | Matcher[]", description: "Dates to disable" }
975
+ },
976
+ example: `<Calendar mode="single" selected={date} onSelect={setDate} />`
569
977
  },
570
978
  card: {
571
979
  name: "Card",
@@ -578,7 +986,20 @@ var COMPONENT_REGISTRY = {
578
986
  "Information panels",
579
987
  "Dashboard widgets"
580
988
  ],
581
- dependencies: []
989
+ dependencies: [],
990
+ props: {
991
+ variant: { type: "'default' | 'glass' | 'outline'", default: "'default'", description: "Visual variant" },
992
+ hoverEffect: { type: "boolean", default: "false", description: "Enable hover lift and shadow" }
993
+ },
994
+ subComponents: ["CardHeader", "CardTitle", "CardDescription", "CardContent", "CardFooter"],
995
+ example: `<Card>
996
+ <CardHeader>
997
+ <CardTitle>Notifications</CardTitle>
998
+ <CardDescription>You have 3 unread messages.</CardDescription>
999
+ </CardHeader>
1000
+ <CardContent><p>Content here.</p></CardContent>
1001
+ <CardFooter><Button>View All</Button></CardFooter>
1002
+ </Card>`
582
1003
  },
583
1004
  "data-table": {
584
1005
  name: "DataTable",
@@ -591,7 +1012,17 @@ var COMPONENT_REGISTRY = {
591
1012
  "Reports",
592
1013
  "List management"
593
1014
  ],
594
- dependencies: ["@tanstack/react-table"]
1015
+ dependencies: ["@tanstack/react-table"],
1016
+ props: {
1017
+ columns: { type: "ColumnDef<TData, TValue>[]", description: "Column definitions from @tanstack/react-table", required: true },
1018
+ data: { type: "TData[]", description: "Array of row data", required: true }
1019
+ },
1020
+ example: `import { DataTable } from '@thesage/ui/tables'
1021
+ const columns = [
1022
+ { accessorKey: 'name', header: 'Name' },
1023
+ { accessorKey: 'email', header: 'Email' },
1024
+ ]
1025
+ <DataTable columns={columns} data={users} />`
595
1026
  },
596
1027
  table: {
597
1028
  name: "Table",
@@ -604,7 +1035,132 @@ var COMPONENT_REGISTRY = {
604
1035
  "Comparison tables",
605
1036
  "Pricing tables"
606
1037
  ],
607
- dependencies: []
1038
+ dependencies: [],
1039
+ subComponents: ["TableHeader", "TableBody", "TableFooter", "TableRow", "TableHead", "TableCell", "TableCaption"],
1040
+ example: `<Table>
1041
+ <TableHeader>
1042
+ <TableRow>
1043
+ <TableHead>Name</TableHead>
1044
+ <TableHead>Status</TableHead>
1045
+ </TableRow>
1046
+ </TableHeader>
1047
+ <TableBody>
1048
+ <TableRow>
1049
+ <TableCell>John</TableCell>
1050
+ <TableCell>Active</TableCell>
1051
+ </TableRow>
1052
+ </TableBody>
1053
+ </Table>`
1054
+ },
1055
+ heading: {
1056
+ name: "Heading",
1057
+ category: "data-display",
1058
+ description: "Semantic heading with automatic token-based styling and responsive sizes",
1059
+ keywords: ["heading", "title", "h1", "h2", "h3", "h4", "h5", "h6", "typography"],
1060
+ useCases: [
1061
+ "Page titles",
1062
+ "Section headings",
1063
+ "Content hierarchy",
1064
+ "Semantic HTML structure"
1065
+ ],
1066
+ dependencies: [],
1067
+ props: {
1068
+ level: { type: "1 | 2 | 3 | 4 | 5 | 6", default: "2", description: "Heading level (renders h1-h6)" },
1069
+ as: { type: "'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'", description: "Override rendered HTML element" }
1070
+ },
1071
+ example: `<Heading level={1}>Page Title</Heading>
1072
+ <Heading level={2}>Section Title</Heading>`
1073
+ },
1074
+ text: {
1075
+ name: "Text",
1076
+ category: "data-display",
1077
+ description: "Semantic text component with variants for primary, secondary, and muted styles",
1078
+ keywords: ["text", "paragraph", "body", "typography", "content", "p", "span"],
1079
+ useCases: [
1080
+ "Body text",
1081
+ "Descriptions",
1082
+ "Helper text",
1083
+ "Labels and captions"
1084
+ ],
1085
+ dependencies: [],
1086
+ props: {
1087
+ variant: { type: "'default' | 'secondary' | 'muted' | 'lead'", default: "'default'", description: "Text style variant" },
1088
+ as: { type: "'p' | 'span' | 'div'", default: "'p'", description: "HTML element to render" },
1089
+ size: { type: "'sm' | 'base' | 'lg'", default: "'base'", description: "Font size" }
1090
+ },
1091
+ example: `<Text variant="lead">Important introductory text.</Text>
1092
+ <Text variant="muted" size="sm">Helper text below an input.</Text>`
1093
+ },
1094
+ code: {
1095
+ name: "Code",
1096
+ category: "data-display",
1097
+ description: "Code display with syntax highlighting for inline and block code",
1098
+ keywords: ["code", "syntax", "highlighting", "programming", "snippet", "pre"],
1099
+ useCases: [
1100
+ "Code snippets",
1101
+ "API documentation",
1102
+ "Technical content",
1103
+ "Inline code references"
1104
+ ],
1105
+ dependencies: [],
1106
+ props: {
1107
+ inline: { type: "boolean", default: "false", description: "Render as inline code (true) or block (false)" },
1108
+ showCopy: { type: "boolean", default: "true", description: "Show copy button for block code" }
1109
+ },
1110
+ example: `// Inline
1111
+ <Code inline>npm install @thesage/ui</Code>
1112
+
1113
+ // Block
1114
+ <Code>{\`const x = 1;
1115
+ const y = 2;\`}</Code>`
1116
+ },
1117
+ "collapsible-code-block": {
1118
+ name: "CollapsibleCodeBlock",
1119
+ category: "data-display",
1120
+ description: "Expandable code block with syntax highlighting, preview mode, and copy functionality",
1121
+ keywords: ["code", "collapsible", "expandable", "syntax", "copy", "preview"],
1122
+ useCases: [
1123
+ "Long code examples",
1124
+ "Documentation code blocks",
1125
+ "Tutorial code snippets",
1126
+ "API examples"
1127
+ ],
1128
+ dependencies: ["@thesage/tokens"],
1129
+ props: {
1130
+ code: { type: "string", description: "Source code string", required: true },
1131
+ language: { type: "'tsx' | 'typescript' | 'javascript' | 'jsx' | 'css' | 'html' | 'json' | 'bash'", default: "'tsx'", description: "Language for syntax highlighting" },
1132
+ title: { type: "string", description: "Optional title above the code block" },
1133
+ maxLines: { type: "number", default: "10", description: "Lines to show before collapsing" },
1134
+ defaultExpanded: { type: "boolean", default: "false", description: "Start in expanded state" }
1135
+ },
1136
+ example: `<CollapsibleCodeBlock
1137
+ code="const Button = () => <button>Click</button>"
1138
+ language="tsx"
1139
+ title="Button.tsx"
1140
+ maxLines={5}
1141
+ />`
1142
+ },
1143
+ "description-list": {
1144
+ name: "DescriptionList",
1145
+ category: "data-display",
1146
+ description: "Key-value pair list for displaying labeled data in row or column layout",
1147
+ keywords: ["description", "list", "key-value", "definition", "dl", "dt", "dd"],
1148
+ useCases: [
1149
+ "Product specifications",
1150
+ "User profile details",
1151
+ "Metadata display",
1152
+ "Settings summaries"
1153
+ ],
1154
+ dependencies: [],
1155
+ props: {
1156
+ items: { type: "{ label: string; value: ReactNode }[]", description: "Array of label-value pairs", required: true },
1157
+ layout: { type: "'row' | 'column'", default: "'row'", description: "Layout direction for label/value pairs" }
1158
+ },
1159
+ example: `<DescriptionList items={[
1160
+ { label: 'Name', value: 'John Doe' },
1161
+ { label: 'Email', value: 'john@example.com' },
1162
+ { label: 'Role', value: <Badge>Admin</Badge> },
1163
+ ]} />`
608
1164
  },
609
1165
  // ============================================================================
610
1166
  // LAYOUT (8)
@@ -621,7 +1177,18 @@ var COMPONENT_REGISTRY = {
621
1177
  "Information disclosure"
622
1178
  ],
623
1179
  dependencies: ["@radix-ui/react-accordion"],
624
- radixPrimitive: "@radix-ui/react-accordion"
1180
+ radixPrimitive: "@radix-ui/react-accordion",
1181
+ props: {
1182
+ type: { type: "'single' | 'multiple'", description: "Allow single or multiple open items", required: true },
1183
+ collapsible: { type: "boolean", default: "false", description: 'Allow closing all items (type="single" only)' }
1184
+ },
1185
+ subComponents: ["AccordionItem", "AccordionTrigger", "AccordionContent"],
1186
+ example: `<Accordion type="single" collapsible>
1187
+ <AccordionItem value="item-1">
1188
+ <AccordionTrigger>Is it accessible?</AccordionTrigger>
1189
+ <AccordionContent>Yes. It follows WAI-ARIA patterns.</AccordionContent>
1190
+ </AccordionItem>
1191
+ </Accordion>`
625
1192
  },
626
1193
  "aspect-ratio": {
627
1194
  name: "AspectRatio",
@@ -635,7 +1202,13 @@ var COMPONENT_REGISTRY = {
635
1202
  "Card images"
636
1203
  ],
637
1204
  dependencies: ["@radix-ui/react-aspect-ratio"],
638
- radixPrimitive: "@radix-ui/react-aspect-ratio"
1205
+ radixPrimitive: "@radix-ui/react-aspect-ratio",
1206
+ props: {
1207
+ ratio: { type: "number", default: "1", description: "Aspect ratio as a number (e.g. 16/9)" }
1208
+ },
1209
+ example: `<AspectRatio ratio={16 / 9}>
1210
+ <img src="/image.jpg" alt="Photo" className="rounded-md object-cover w-full h-full" />
1211
+ </AspectRatio>`
639
1212
  },
640
1213
  carousel: {
641
1214
  name: "Carousel",
@@ -648,7 +1221,23 @@ var COMPONENT_REGISTRY = {
648
1221
  "Content sliders",
649
1222
  "Testimonials"
650
1223
  ],
651
- dependencies: ["embla-carousel-react"]
1224
+ dependencies: ["embla-carousel-react"],
1225
+ props: {
1226
+ orientation: { type: "'horizontal' | 'vertical'", default: "'horizontal'", description: "Scroll direction" },
1227
+ opts: { type: "CarouselOptions", description: "Embla Carousel options (loop, align, etc.)" },
1228
+ plugins: { type: "CarouselPlugin", description: "Embla Carousel plugins (autoplay, etc.)" },
1229
+ setApi: { type: "(api: CarouselApi) => void", description: "Callback to get carousel API ref" }
1230
+ },
1231
+ subComponents: ["CarouselContent", "CarouselItem", "CarouselPrevious", "CarouselNext"],
1232
+ example: `<Carousel>
1233
+ <CarouselContent>
1234
+ <CarouselItem>Slide 1</CarouselItem>
1235
+ <CarouselItem>Slide 2</CarouselItem>
1236
+ <CarouselItem>Slide 3</CarouselItem>
1237
+ </CarouselContent>
1238
+ <CarouselPrevious />
1239
+ <CarouselNext />
1240
+ </Carousel>`
652
1241
  },
653
1242
  collapsible: {
654
1243
  name: "Collapsible",
@@ -662,7 +1251,19 @@ var COMPONENT_REGISTRY = {
662
1251
  "Details disclosure"
663
1252
  ],
664
1253
  dependencies: ["@radix-ui/react-collapsible"],
665
- radixPrimitive: "@radix-ui/react-collapsible"
1254
+ radixPrimitive: "@radix-ui/react-collapsible",
1255
+ props: {
1256
+ open: { type: "boolean", description: "Controlled open state" },
1257
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" },
1258
+ defaultOpen: { type: "boolean", default: "false", description: "Default open state" }
1259
+ },
1260
+ subComponents: ["CollapsibleTrigger", "CollapsibleContent"],
1261
+ example: `<Collapsible>
1262
+ <CollapsibleTrigger asChild><Button variant="ghost">Toggle</Button></CollapsibleTrigger>
1263
+ <CollapsibleContent>
1264
+ <p>Hidden content revealed on click.</p>
1265
+ </CollapsibleContent>
1266
+ </Collapsible>`
666
1267
  },
667
1268
  "date-picker": {
668
1269
  name: "DatePicker",
@@ -675,7 +1276,14 @@ var COMPONENT_REGISTRY = {
675
1276
  "Scheduling",
676
1277
  "Filters"
677
1278
  ],
678
- dependencies: ["react-day-picker", "date-fns", "@radix-ui/react-popover"]
1279
+ dependencies: ["react-day-picker", "date-fns", "@radix-ui/react-popover"],
1280
+ props: {
1281
+ date: { type: "Date", description: "Selected date" },
1282
+ onDateChange: { type: "(date: Date | undefined) => void", description: "Callback on date change" },
1283
+ placeholder: { type: "string", default: "'Pick a date'", description: "Placeholder text" },
1284
+ disabled: { type: "boolean", default: "false", description: "Disable the date picker" }
1285
+ },
1286
+ example: `<DatePicker date={date} onDateChange={setDate} placeholder="Select date" />`
679
1287
  },
680
1288
  resizable: {
681
1289
  name: "Resizable",
@@ -688,7 +1296,16 @@ var COMPONENT_REGISTRY = {
688
1296
  "Dashboard layouts",
689
1297
  "Adjustable sidebars"
690
1298
  ],
691
- dependencies: ["react-resizable-panels"]
1299
+ dependencies: ["react-resizable-panels"],
1300
+ props: {
1301
+ direction: { type: "'horizontal' | 'vertical'", default: "'horizontal'", description: "Panel layout direction" }
1302
+ },
1303
+ subComponents: ["ResizablePanelGroup", "ResizablePanel", "ResizableHandle"],
1304
+ example: `<ResizablePanelGroup direction="horizontal">
1305
+ <ResizablePanel defaultSize={50}>Left panel</ResizablePanel>
1306
+ <ResizableHandle />
1307
+ <ResizablePanel defaultSize={50}>Right panel</ResizablePanel>
1308
+ </ResizablePanelGroup>`
692
1309
  },
693
1310
  "scroll-area": {
694
1311
  name: "ScrollArea",
@@ -702,7 +1319,11 @@ var COMPONENT_REGISTRY = {
702
1319
  "Code displays"
703
1320
  ],
704
1321
  dependencies: ["@radix-ui/react-scroll-area"],
705
- radixPrimitive: "@radix-ui/react-scroll-area"
1322
+ radixPrimitive: "@radix-ui/react-scroll-area",
1323
+ subComponents: ["ScrollBar"],
1324
+ example: `<ScrollArea className="h-[200px] w-full rounded-md border p-4">
1325
+ <div>Long scrollable content here...</div>
1326
+ </ScrollArea>`
706
1327
  },
707
1328
  separator: {
708
1329
  name: "Separator",
@@ -716,7 +1337,837 @@ var COMPONENT_REGISTRY = {
716
1337
  "Visual hierarchy"
717
1338
  ],
718
1339
  dependencies: ["@radix-ui/react-separator"],
719
- radixPrimitive: "@radix-ui/react-separator"
1340
+ radixPrimitive: "@radix-ui/react-separator",
1341
+ props: {
1342
+ orientation: { type: "'horizontal' | 'vertical'", default: "'horizontal'", description: "Orientation" }
1343
+ },
1344
+ example: `<Separator orientation="horizontal" />`
1345
+ },
1346
+ grid: {
1347
+ name: "Grid",
1348
+ category: "layout",
1349
+ description: "Responsive CSS grid with column and gap configuration",
1350
+ keywords: ["grid", "layout", "columns", "responsive", "css-grid"],
1351
+ useCases: [
1352
+ "Card grids",
1353
+ "Gallery layouts",
1354
+ "Dashboard layouts",
1355
+ "Responsive content grids"
1356
+ ],
1357
+ dependencies: [],
1358
+ props: {
1359
+ columns: { type: "number | { sm?: number; md?: number; lg?: number }", default: "3", description: "Number of grid columns (responsive object supported)" },
1360
+ gap: { type: "number | string", default: "4", description: "Gap between grid items (Tailwind spacing scale)" }
1361
+ },
1362
+ example: `<Grid columns={{ sm: 1, md: 2, lg: 3 }} gap={4}>
1363
+ <Card>Item 1</Card>
1364
+ <Card>Item 2</Card>
1365
+ <Card>Item 3</Card>
1366
+ </Grid>`
1367
+ },
1368
+ container: {
1369
+ name: "Container",
1370
+ category: "layout",
1371
+ description: "Content wrapper with consistent max-width and padding variants",
1372
+ keywords: ["container", "wrapper", "max-width", "centered", "layout"],
1373
+ useCases: [
1374
+ "Page content wrapper",
1375
+ "Centered layouts",
1376
+ "Responsive widths",
1377
+ "Content alignment"
1378
+ ],
1379
+ dependencies: [],
1380
+ props: {
1381
+ size: { type: "'sm' | 'md' | 'lg' | 'xl' | 'full'", default: "'lg'", description: "Max-width variant" },
1382
+ padding: { type: "boolean", default: "true", description: "Apply horizontal padding" }
1383
+ },
1384
+ example: `<Container size="lg">
1385
+ <Heading level={1}>Page Title</Heading>
1386
+ <Text>Content within max-width container.</Text>
1387
+ </Container>`
1388
+ },
1389
+ stack: {
1390
+ name: "Stack",
1391
+ category: "layout",
1392
+ description: "Flexbox layout for vertical or horizontal stacking with gap control",
1393
+ keywords: ["stack", "flex", "vertical", "horizontal", "spacing", "layout"],
1394
+ useCases: [
1395
+ "Vertical layouts",
1396
+ "Horizontal layouts",
1397
+ "Form layouts",
1398
+ "Button groups"
1399
+ ],
1400
+ dependencies: [],
1401
+ props: {
1402
+ direction: { type: "'vertical' | 'horizontal'", default: "'vertical'", description: "Stack direction" },
1403
+ gap: { type: "number | string", default: "4", description: "Gap between items (Tailwind spacing scale)" },
1404
+ align: { type: "'start' | 'center' | 'end' | 'stretch'", default: "'stretch'", description: "Cross-axis alignment" },
1405
+ justify: { type: "'start' | 'center' | 'end' | 'between'", description: "Main-axis alignment" }
1406
+ },
1407
+ example: `<Stack direction="horizontal" gap={2} align="center">
1408
+ <Button>Save</Button>
1409
+ <Button variant="outline">Cancel</Button>
1410
+ </Stack>`
1411
+ },
1412
+ sidebar: {
1413
+ name: "Sidebar",
1414
+ category: "layout",
1415
+ description: "Navigation sidebar with header, content, footer sections and mobile overlay",
1416
+ keywords: ["sidebar", "navigation", "panel", "drawer", "menu"],
1417
+ useCases: [
1418
+ "App navigation",
1419
+ "Dashboard sidebars",
1420
+ "Settings panels",
1421
+ "Mobile menus"
1422
+ ],
1423
+ dependencies: ["@radix-ui/react-slot"],
1424
+ radixPrimitive: "@radix-ui/react-slot",
1425
+ props: {
1426
+ isOpen: { type: "boolean", default: "true", description: "Whether sidebar is visible/expanded" }
1427
+ },
1428
+ subComponents: ["SidebarHeader", "SidebarContent", "SidebarFooter", "SidebarItem"],
1429
+ example: `<Sidebar>
1430
+ <SidebarHeader><h2>My App</h2></SidebarHeader>
1431
+ <SidebarContent>
1432
+ <SidebarItem icon={<Home />} isActive>Dashboard</SidebarItem>
1433
+ <SidebarItem icon={<Settings />}>Settings</SidebarItem>
1434
+ </SidebarContent>
1435
+ <SidebarFooter>
1436
+ <SidebarItem icon={<LogOut />}>Logout</SidebarItem>
1437
+ </SidebarFooter>
1438
+ </Sidebar>`
1439
+ },
1440
+ header: {
1441
+ name: "Header",
1442
+ category: "layout",
1443
+ description: "Page header with sticky positioning, glass morphism, and mobile menu",
1444
+ keywords: ["header", "navbar", "navigation", "sticky", "mobile-menu"],
1445
+ useCases: [
1446
+ "Site headers",
1447
+ "App navigation bars",
1448
+ "Sticky headers",
1449
+ "Mobile-friendly navigation"
1450
+ ],
1451
+ dependencies: ["lucide-react"],
1452
+ props: {
1453
+ logo: { type: "ReactNode", description: "Logo element for header" },
1454
+ links: { type: "{ label: string; href: string }[]", description: "Navigation links" },
1455
+ sticky: { type: "boolean", default: "true", description: "Stick to top on scroll" },
1456
+ transparent: { type: "boolean", default: "false", description: "Transparent background (for hero sections)" }
1457
+ },
1458
+ example: `<Header
1459
+ logo={<Brand />}
1460
+ links={[
1461
+ { label: 'Home', href: '/' },
1462
+ { label: 'About', href: '/about' },
1463
+ ]}
1464
+ />`
1465
+ },
1466
+ footer: {
1467
+ name: "Footer",
1468
+ category: "layout",
1469
+ description: "Page footer with multi-column layout, social links, and copyright",
1470
+ keywords: ["footer", "navigation", "links", "copyright", "social"],
1471
+ useCases: [
1472
+ "Site footers",
1473
+ "Navigation sections",
1474
+ "Contact information",
1475
+ "Copyright notices"
1476
+ ],
1477
+ dependencies: [],
1478
+ props: {
1479
+ columns: { type: "{ title: string; links: { label: string; href: string }[] }[]", description: "Footer navigation columns" },
1480
+ copyright: { type: "string", description: "Copyright text" },
1481
+ socialLinks: { type: "{ icon: ReactNode; href: string }[]", description: "Social media links" }
1482
+ },
1483
+ example: `<Footer
1484
+ columns={[{ title: 'Product', links: [{ label: 'Docs', href: '/docs' }] }]}
1485
+ copyright="\xA9 2026 My Company"
1486
+ />`
1487
+ },
1488
+ "customizer-panel": {
1489
+ name: "CustomizerPanel",
1490
+ category: "layout",
1491
+ description: "Floating panel for theme, mode, and motion customization. Reads from ThemeProvider context.",
1492
+ keywords: ["customizer", "theme", "settings", "preferences", "dark-mode"],
1493
+ useCases: [
1494
+ "Theme selection",
1495
+ "Dark mode toggle",
1496
+ "Motion preferences",
1497
+ "User experience customization"
1498
+ ],
1499
+ dependencies: ["lucide-react", "@thesage/tokens"],
1500
+ example: `// Place in your layout. It reads theme state from ThemeProvider.
1501
+ <CustomizerPanel />`
1502
+ },
1503
+ "page-layout": {
1504
+ name: "PageLayout",
1505
+ category: "layout",
1506
+ description: "Flexible page layout with header, nav stacks, breadcrumbs, and footer",
1507
+ keywords: ["layout", "page", "template", "structure", "swiss-grid"],
1508
+ useCases: [
1509
+ "Page structure",
1510
+ "Content layouts",
1511
+ "Documentation pages",
1512
+ "Dashboard layouts"
1513
+ ],
1514
+ dependencies: [],
1515
+ props: {
1516
+ header: { type: "ReactNode", description: "Header element" },
1517
+ footer: { type: "ReactNode", description: "Footer element" },
1518
+ sidebar: { type: "ReactNode", description: "Optional sidebar" },
1519
+ breadcrumbs: { type: "ReactNode", description: "Breadcrumb navigation" }
1520
+ },
1521
+ example: `<PageLayout
1522
+ header={<Header />}
1523
+ footer={<Footer />}
1524
+ >
1525
+ <main>Page content</main>
1526
+ </PageLayout>`
1527
+ },
1528
+ "page-template": {
1529
+ name: "PageTemplate",
1530
+ category: "layout",
1531
+ description: "Opinionated page template with Swiss Grid design and customizer",
1532
+ keywords: ["template", "page", "swiss-grid", "layout", "documentation"],
1533
+ useCases: [
1534
+ "Blog pages",
1535
+ "Documentation pages",
1536
+ "Standard app pages",
1537
+ "Content-focused layouts"
1538
+ ],
1539
+ dependencies: [],
1540
+ props: {
1541
+ title: { type: "string", description: "Page title" },
1542
+ description: { type: "string", description: "Page description" },
1543
+ showCustomizer: { type: "boolean", default: "true", description: "Show customizer panel" }
1544
+ },
1545
+ example: `<PageTemplate title="Documentation" description="Learn the design system.">
1546
+ <div>Content here.</div>
1547
+ </PageTemplate>`
1548
+ },
1549
+ // ============================================================================
1550
+ // ACTIONS - Additional (2 more)
1551
+ // ============================================================================
1552
+ link: {
1553
+ name: "Link",
1554
+ category: "actions",
1555
+ description: "Styled anchor element with theme-aware colors and hover states",
1556
+ keywords: ["link", "anchor", "href", "navigation", "a", "url"],
1557
+ useCases: [
1558
+ "Text links",
1559
+ "Navigation links",
1560
+ "External references",
1561
+ "Inline actions"
1562
+ ],
1563
+ dependencies: [],
1564
+ props: {
1565
+ href: { type: "string", description: "Link URL", required: true },
1566
+ variant: { type: "'default' | 'inline'", default: "'default'", description: "Default for standalone links, inline for text links" },
1567
+ hoverEffect: { type: "boolean", default: "true", description: "Enable hover effect" }
1568
+ },
1569
+ example: `<Link href="/about" variant="inline">Learn More</Link>`
1570
+ },
1571
+ magnetic: {
1572
+ name: "Magnetic",
1573
+ category: "actions",
1574
+ description: "Magnetic hover effect that attracts elements toward cursor",
1575
+ keywords: ["magnetic", "hover", "effect", "cursor", "animation", "interactive"],
1576
+ useCases: [
1577
+ "Interactive buttons",
1578
+ "Hover effects",
1579
+ "Playful interactions",
1580
+ "Cursor attraction"
1581
+ ],
1582
+ dependencies: ["framer-motion"],
1583
+ props: {
1584
+ children: { type: "ReactNode", description: "Element to apply magnetic effect to", required: true },
1585
+ strength: { type: "number", default: "0.5", description: "Magnetic pull strength (0-1)" }
1586
+ },
1587
+ example: `<Magnetic strength={0.5}>
1588
+ <Button>Hover me</Button>
1589
+ </Magnetic>`
1590
+ },
1591
+ // ============================================================================
1592
+ // FORMS - Additional (7 more)
1593
+ // ============================================================================
1594
+ "search-bar": {
1595
+ name: "SearchBar",
1596
+ category: "forms",
1597
+ description: "Search input with icon, clear button, and keyboard shortcuts",
1598
+ keywords: ["search", "input", "find", "query", "filter", "bar"],
1599
+ useCases: [
1600
+ "Site search",
1601
+ "Content filtering",
1602
+ "Command palette trigger",
1603
+ "Data filtering"
1604
+ ],
1605
+ dependencies: ["lucide-react"],
1606
+ props: {
1607
+ value: { type: "string", description: "Controlled search value" },
1608
+ onChange: { type: "(value: string) => void", description: "Callback on value change" },
1609
+ placeholder: { type: "string", default: "'Search...'", description: "Placeholder text" },
1610
+ onClear: { type: "() => void", description: "Callback on clear button click" }
1611
+ },
1612
+ example: `<SearchBar value={query} onChange={setQuery} placeholder="Search components..." />`
1613
+ },
1614
+ "filter-button": {
1615
+ name: "FilterButton",
1616
+ category: "forms",
1617
+ description: "Button for filtering content with active/inactive states",
1618
+ keywords: ["filter", "button", "toggle", "category", "selection"],
1619
+ useCases: [
1620
+ "Category filters",
1621
+ "Tag selection",
1622
+ "Content filtering",
1623
+ "Quick filters"
1624
+ ],
1625
+ dependencies: [],
1626
+ props: {
1627
+ active: { type: "boolean", default: "false", description: "Whether filter is active" },
1628
+ onClick: { type: "() => void", description: "Click handler" },
1629
+ children: { type: "ReactNode", description: "Filter label", required: true }
1630
+ },
1631
+ example: `<FilterButton active={category === 'all'} onClick={() => setCategory('all')}>All</FilterButton>`
1632
+ },
1633
+ "theme-switcher": {
1634
+ name: "ThemeSwitcher",
1635
+ category: "forms",
1636
+ description: "Multi-theme selector for switching between Studio, Terra, and Volt. Reads/writes to ThemeProvider context.",
1637
+ keywords: ["theme", "switcher", "selector", "studio", "terra", "volt"],
1638
+ useCases: [
1639
+ "Theme selection",
1640
+ "Brand customization",
1641
+ "User preferences",
1642
+ "Design switching"
1643
+ ],
1644
+ dependencies: [],
1645
+ example: `// Reads from ThemeProvider context, no props needed.
1646
+ <ThemeSwitcher />`
1647
+ },
1648
+ "theme-toggle": {
1649
+ name: "ThemeToggle",
1650
+ category: "forms",
1651
+ description: "Light/dark mode toggle with smooth transitions. Reads/writes to ThemeProvider context.",
1652
+ keywords: ["theme", "toggle", "dark-mode", "light-mode", "mode"],
1653
+ useCases: [
1654
+ "Dark mode switch",
1655
+ "Light mode switch",
1656
+ "Theme mode control",
1657
+ "Accessibility preference"
1658
+ ],
1659
+ dependencies: ["lucide-react"],
1660
+ example: `// Reads from ThemeProvider context, no props needed.
1661
+ <ThemeToggle />`
1662
+ },
1663
+ "color-picker": {
1664
+ name: "ColorPicker",
1665
+ category: "forms",
1666
+ description: "Color selection input with preset swatches and custom color support",
1667
+ keywords: ["color", "picker", "palette", "swatch", "hex", "customization"],
1668
+ useCases: [
1669
+ "Brand color selection",
1670
+ "Theme customization",
1671
+ "Design tools",
1672
+ "User preferences"
1673
+ ],
1674
+ dependencies: [],
1675
+ props: {
1676
+ value: { type: "string", description: "Selected color (hex string)" },
1677
+ onChange: { type: "(color: string) => void", description: "Callback on color change" },
1678
+ presets: { type: "string[]", description: "Preset color swatches (hex values)" }
1679
+ },
1680
+ example: `<ColorPicker value={color} onChange={setColor} presets={['#ef4444', '#3b82f6', '#22c55e']} />`
1681
+ },
1682
+ "drag-drop": {
1683
+ name: "DragDrop",
1684
+ category: "forms",
1685
+ description: "Drag and drop file upload zone with preview support",
1686
+ keywords: ["drag", "drop", "upload", "file", "dropzone", "input"],
1687
+ useCases: [
1688
+ "File uploads",
1689
+ "Image uploads",
1690
+ "Document uploads",
1691
+ "Bulk imports"
1692
+ ],
1693
+ dependencies: [],
1694
+ props: {
1695
+ onDrop: { type: "(files: File[]) => void", description: "Callback when files are dropped", required: true },
1696
+ accept: { type: "string", description: 'Accepted file types (e.g. "image/*")' },
1697
+ maxSize: { type: "number", description: "Max file size in bytes" },
1698
+ multiple: { type: "boolean", default: "true", description: "Allow multiple files" }
1699
+ },
1700
+ example: `<DragDrop onDrop={(files) => handleUpload(files)} accept="image/*" maxSize={5242880} />`
1701
+ },
1702
+ "text-field": {
1703
+ name: "TextField",
1704
+ category: "forms",
1705
+ description: "Complete text input with label, helper text, and error states",
1706
+ keywords: ["text", "field", "input", "label", "form", "validation"],
1707
+ useCases: [
1708
+ "Form fields",
1709
+ "Labeled inputs",
1710
+ "Validated inputs",
1711
+ "Complete form controls"
1712
+ ],
1713
+ dependencies: [],
1714
+ props: {
1715
+ label: { type: "string", description: "Field label text" },
1716
+ helperText: { type: "string", description: "Helper text below input" },
1717
+ error: { type: "string", description: "Error message (shows error state when set)" },
1718
+ required: { type: "boolean", default: "false", description: "Mark as required" }
1719
+ },
1720
+ example: `<TextField label="Email" helperText="We'll never share your email." error={errors.email} required />`
1721
+ },
1722
+ // ============================================================================
1723
+ // NAVIGATION - Additional (4 more)
1724
+ // ============================================================================
1725
+ "nav-link": {
1726
+ name: "NavLink",
1727
+ category: "navigation",
1728
+ description: "Navigation link with active state indicators and variants",
1729
+ keywords: ["nav", "link", "navigation", "active", "menu", "item"],
1730
+ useCases: [
1731
+ "Navigation menus",
1732
+ "Sidebar links",
1733
+ "Header navigation",
1734
+ "Active page indicators"
1735
+ ],
1736
+ dependencies: [],
1737
+ props: {
1738
+ href: { type: "string", description: "Link URL", required: true },
1739
+ isActive: { type: "boolean", default: "false", description: "Active state indicator" },
1740
+ variant: { type: "'default' | 'subtle'", default: "'default'", description: "Visual variant" }
1741
+ },
1742
+ example: `<NavLink href="/dashboard" isActive>Dashboard</NavLink>`
1743
+ },
1744
+ "secondary-nav": {
1745
+ name: "SecondaryNav",
1746
+ category: "navigation",
1747
+ description: "Horizontal secondary navigation bar for section switching",
1748
+ keywords: ["secondary", "navigation", "tabs", "sections", "subnav"],
1749
+ useCases: [
1750
+ "Section navigation",
1751
+ "Page subsections",
1752
+ "Tab-like navigation",
1753
+ "Category switching"
1754
+ ],
1755
+ dependencies: [],
1756
+ props: {
1757
+ items: { type: "{ label: string; href: string; isActive?: boolean }[]", description: "Navigation items", required: true }
1758
+ },
1759
+ example: `<SecondaryNav items={[
1760
+ { label: 'Overview', href: '/overview', isActive: true },
1761
+ { label: 'Settings', href: '/settings' },
1762
+ ]} />`
1763
+ },
1764
+ "tertiary-nav": {
1765
+ name: "TertiaryNav",
1766
+ category: "navigation",
1767
+ description: "Third-level navigation for deep content hierarchies",
1768
+ keywords: ["tertiary", "navigation", "deep", "hierarchy", "subnav"],
1769
+ useCases: [
1770
+ "Deep navigation",
1771
+ "Documentation sections",
1772
+ "Multi-level content",
1773
+ "Nested categories"
1774
+ ],
1775
+ dependencies: [],
1776
+ props: {
1777
+ items: { type: "{ label: string; href: string; isActive?: boolean }[]", description: "Navigation items", required: true }
1778
+ },
1779
+ example: `<TertiaryNav items={[
1780
+ { label: 'Props', href: '#props', isActive: true },
1781
+ { label: 'Examples', href: '#examples' },
1782
+ ]} />`
1783
+ },
1784
+ breadcrumbs: {
1785
+ name: "Breadcrumbs",
1786
+ category: "navigation",
1787
+ description: "Breadcrumb navigation with home icon and variants",
1788
+ keywords: ["breadcrumbs", "navigation", "path", "trail", "hierarchy"],
1789
+ useCases: [
1790
+ "Page location",
1791
+ "Navigation trail",
1792
+ "Hierarchical navigation",
1793
+ "Back navigation"
1794
+ ],
1795
+ dependencies: ["lucide-react"],
1796
+ props: {
1797
+ items: { type: "{ label: string; href?: string }[]", description: "Breadcrumb trail items (last item is current page)", required: true },
1798
+ showHome: { type: "boolean", default: "true", description: "Show home icon as first item" }
1799
+ },
1800
+ example: `<Breadcrumbs items={[
1801
+ { label: 'Home', href: '/' },
1802
+ { label: 'Components', href: '/components' },
1803
+ { label: 'Button' },
1804
+ ]} />`
1805
+ },
1806
+ // ============================================================================
1807
+ // OVERLAYS - Additional (2 more)
1808
+ // ============================================================================
1809
+ modal: {
1810
+ name: "Modal",
1811
+ category: "overlays",
1812
+ description: "Simple modal wrapper around Dialog with common patterns",
1813
+ keywords: ["modal", "dialog", "popup", "overlay", "window"],
1814
+ useCases: [
1815
+ "Simple modals",
1816
+ "Confirmation dialogs",
1817
+ "Form modals",
1818
+ "Content overlays"
1819
+ ],
1820
+ dependencies: ["@radix-ui/react-dialog"],
1821
+ radixPrimitive: "@radix-ui/react-dialog",
1822
+ props: {
1823
+ open: { type: "boolean", description: "Controlled open state" },
1824
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" },
1825
+ title: { type: "string", description: "Modal title" },
1826
+ description: { type: "string", description: "Modal description" }
1827
+ },
1828
+ example: `<Modal open={isOpen} onOpenChange={setIsOpen} title="Confirm" description="Are you sure?">
1829
+ <div className="flex gap-2 justify-end">
1830
+ <Button variant="outline" onClick={() => setIsOpen(false)}>Cancel</Button>
1831
+ <Button onClick={handleConfirm}>Confirm</Button>
1832
+ </div>
1833
+ </Modal>`
1834
+ },
1835
+ dropdown: {
1836
+ name: "Dropdown",
1837
+ category: "overlays",
1838
+ description: "Simple dropdown wrapper for common dropdown patterns",
1839
+ keywords: ["dropdown", "menu", "select", "options", "popover"],
1840
+ useCases: [
1841
+ "Action menus",
1842
+ "User menus",
1843
+ "Quick selections",
1844
+ "Option lists"
1845
+ ],
1846
+ dependencies: ["@radix-ui/react-dropdown-menu"],
1847
+ radixPrimitive: "@radix-ui/react-dropdown-menu",
1848
+ props: {
1849
+ open: { type: "boolean", description: "Controlled open state" },
1850
+ onOpenChange: { type: "(open: boolean) => void", description: "Callback on open/close" }
1851
+ },
1852
+ example: `// For most cases, use DropdownMenu directly. This is a simplified wrapper.`
1853
+ },
1854
+ // ============================================================================
1855
+ // FEEDBACK - Additional (2 more)
1856
+ // ============================================================================
1857
+ spinner: {
1858
+ name: "Spinner",
1859
+ category: "feedback",
1860
+ description: "Animated loading spinner with size variants",
1861
+ keywords: ["spinner", "loading", "loader", "progress", "waiting"],
1862
+ useCases: [
1863
+ "Loading states",
1864
+ "Button loading",
1865
+ "Data fetching",
1866
+ "Async operations"
1867
+ ],
1868
+ dependencies: [],
1869
+ props: {
1870
+ size: { type: "'xs' | 'sm' | 'md' | 'lg' | 'xl'", default: "'md'", description: "Spinner size" },
1871
+ variant: { type: "'primary' | 'secondary' | 'inherit'", default: "'primary'", description: "Color variant" }
1872
+ },
1873
+ example: `<Spinner size="md" />
1874
+ <Button disabled><Spinner size="xs" variant="inherit" /> Loading...</Button>`
1875
+ },
1876
+ "progress-bar": {
1877
+ name: "ProgressBar",
1878
+ category: "feedback",
1879
+ description: "Horizontal progress bar with percentage display",
1880
+ keywords: ["progress", "bar", "loading", "percentage", "completion"],
1881
+ useCases: [
1882
+ "File uploads",
1883
+ "Task progress",
1884
+ "Loading indicators",
1885
+ "Step completion"
1886
+ ],
1887
+ dependencies: [],
1888
+ props: {
1889
+ value: { type: "number", default: "0", description: "Progress value (0-100)" },
1890
+ variant: { type: "'primary' | 'success' | 'warning' | 'error' | 'info'", default: "'primary'", description: "Color variant" },
1891
+ size: { type: "'sm' | 'md' | 'lg'", default: "'md'", description: "Bar height" },
1892
+ showLabel: { type: "boolean", default: "false", description: "Show percentage label" }
1893
+ },
1894
+ example: `<ProgressBar value={75} variant="success" showLabel />`
1895
+ },
1896
+ // ============================================================================
1897
+ // DATA DISPLAY - Additional (5 more)
1898
+ // ============================================================================
1899
+ brand: {
1900
+ name: "Brand",
1901
+ category: "data-display",
1902
+ description: "Theme-aware brand/logo component with size variants and link support",
1903
+ keywords: ["brand", "logo", "identity", "header", "company"],
1904
+ useCases: [
1905
+ "Site logos",
1906
+ "Header branding",
1907
+ "Footer branding",
1908
+ "App identity"
1909
+ ],
1910
+ dependencies: [],
1911
+ props: {
1912
+ variant: { type: "'default' | 'mark'", default: "'default'", description: "Full logo or mark only" },
1913
+ size: { type: "'sm' | 'md' | 'lg'", default: "'md'", description: "Logo size" },
1914
+ href: { type: "string", description: "Optional link URL (wraps in anchor)" }
1915
+ },
1916
+ example: `<Brand size="md" href="/" />`
1917
+ },
1918
+ "aspect-image": {
1919
+ name: "AspectImage",
1920
+ category: "data-display",
1921
+ description: "Image with configurable aspect ratio, rounded corners, and captions",
1922
+ keywords: ["image", "aspect", "ratio", "figure", "caption", "media"],
1923
+ useCases: [
1924
+ "Gallery images",
1925
+ "Article images",
1926
+ "Product images",
1927
+ "Thumbnails with captions"
1928
+ ],
1929
+ dependencies: [],
1930
+ props: {
1931
+ src: { type: "string", description: "Image source URL", required: true },
1932
+ alt: { type: "string", description: "Alt text for accessibility", required: true },
1933
+ ratio: { type: "number", default: "16/9", description: "Aspect ratio" },
1934
+ rounded: { type: "'none' | 'sm' | 'md' | 'lg' | 'full'", default: "'md'", description: "Border radius" },
1935
+ caption: { type: "string", description: "Optional caption text below image" }
1936
+ },
1937
+ example: `<AspectImage src="/photo.jpg" alt="Team photo" ratio={4/3} caption="Our team" />`
1938
+ },
1939
+ "variable-weight-text": {
1940
+ name: "VariableWeightText",
1941
+ category: "data-display",
1942
+ description: "Animated text with breathing font-weight effect using variable fonts",
1943
+ keywords: ["variable", "font", "weight", "animation", "breathing", "motion"],
1944
+ useCases: [
1945
+ "Hero text",
1946
+ "Emphasis text",
1947
+ "Attention grabbing",
1948
+ "Variable font showcase"
1949
+ ],
1950
+ dependencies: ["framer-motion"],
1951
+ props: {
1952
+ children: { type: "string", description: "Text content", required: true },
1953
+ speed: { type: "number", default: "2", description: "Animation speed in seconds" },
1954
+ minWeight: { type: "number", default: "100", description: "Minimum font weight" },
1955
+ maxWeight: { type: "number", default: "900", description: "Maximum font weight" }
1956
+ },
1957
+ example: `<VariableWeightText speed={2} minWeight={200} maxWeight={800}>Design</VariableWeightText>`
1958
+ },
1959
+ typewriter: {
1960
+ name: "Typewriter",
1961
+ category: "data-display",
1962
+ description: "Typewriter text animation with cursor and loop support",
1963
+ keywords: ["typewriter", "typing", "animation", "cursor", "text", "effect"],
1964
+ useCases: [
1965
+ "Hero taglines",
1966
+ "Terminal effects",
1967
+ "Dynamic headings",
1968
+ "Attention text"
1969
+ ],
1970
+ dependencies: ["framer-motion"],
1971
+ props: {
1972
+ words: { type: "string[]", description: "Words to cycle through", required: true },
1973
+ speed: { type: "number", default: "100", description: "Typing speed in ms per character" },
1974
+ loop: { type: "boolean", default: "true", description: "Loop through words continuously" },
1975
+ cursor: { type: "boolean", default: "true", description: "Show blinking cursor" }
1976
+ },
1977
+ example: `<Typewriter words={['Developer', 'Designer', 'Creator']} speed={80} />`
1978
+ },
1979
+ "github-icon": {
1980
+ name: "GitHubIcon",
1981
+ category: "data-display",
1982
+ description: "GitHub logo icon that inherits text color for theme support",
1983
+ keywords: ["github", "icon", "social", "logo", "svg"],
1984
+ useCases: [
1985
+ "Social links",
1986
+ "Footer icons",
1987
+ "Repository links",
1988
+ "Open source badges"
1989
+ ],
1990
+ dependencies: [],
1991
+ props: {
1992
+ size: { type: "number", default: "24", description: "Icon size in pixels" }
1993
+ },
1994
+ example: `<a href="https://github.com/you"><GitHubIcon size={20} /></a>`
1995
+ },
1996
+ // ============================================================================
1997
+ // SPECIALTY - Backgrounds (3)
1998
+ // ============================================================================
1999
+ "warp-background": {
2000
+ name: "WarpBackground",
2001
+ category: "backgrounds",
2002
+ description: "Animated warp speed star field background effect",
2003
+ keywords: ["warp", "stars", "background", "animation", "space", "effect"],
2004
+ useCases: [
2005
+ "Hero backgrounds",
2006
+ "Landing pages",
2007
+ "Loading screens",
2008
+ "Sci-fi themes"
2009
+ ],
2010
+ dependencies: ["framer-motion"],
2011
+ props: {
2012
+ speed: { type: "number", default: "1", description: "Warp speed multiplier" },
2013
+ density: { type: "number", default: "200", description: "Number of stars" },
2014
+ color: { type: "string", default: "'white'", description: "Star color" }
2015
+ },
2016
+ example: `<WarpBackground speed={1.5} density={300}>
2017
+ <div className="relative z-10">Content over stars</div>
2018
+ </WarpBackground>`
2019
+ },
2020
+ "faulty-terminal": {
2021
+ name: "FaultyTerminal",
2022
+ category: "backgrounds",
2023
+ description: "Glitchy terminal background with flickering and scan lines",
2024
+ keywords: ["terminal", "glitch", "background", "retro", "crt", "effect"],
2025
+ useCases: [
2026
+ "Retro themes",
2027
+ "Hacker aesthetics",
2028
+ "Error pages",
2029
+ "Terminal UIs"
2030
+ ],
2031
+ dependencies: [],
2032
+ props: {
2033
+ children: { type: "ReactNode", description: "Content to render inside terminal" }
2034
+ },
2035
+ example: `<FaultyTerminal>
2036
+ <p>$ system initializing...</p>
2037
+ </FaultyTerminal>`
2038
+ },
2039
+ "orb-background": {
2040
+ name: "OrbBackground",
2041
+ category: "backgrounds",
2042
+ description: "Animated floating orb with gradient blur effect",
2043
+ keywords: ["orb", "gradient", "background", "animation", "blur", "ambient"],
2044
+ useCases: [
2045
+ "Landing pages",
2046
+ "Hero sections",
2047
+ "Ambient backgrounds",
2048
+ "Modern aesthetics"
2049
+ ],
2050
+ dependencies: ["framer-motion"],
2051
+ props: {
2052
+ color: { type: "string", description: "Primary orb color" },
2053
+ size: { type: "number", default: "400", description: "Orb diameter in pixels" }
2054
+ },
2055
+ example: `<OrbBackground color="var(--color-primary)" size={500}>
2056
+ <div className="relative z-10">Content</div>
2057
+ </OrbBackground>`
2058
+ },
2059
+ // ============================================================================
2060
+ // SPECIALTY - Cursor (2)
2061
+ // ============================================================================
2062
+ "splash-cursor": {
2063
+ name: "SplashCursor",
2064
+ category: "cursor",
2065
+ description: "Custom cursor with splash/ripple effect on click. WebGL-based fluid simulation.",
2066
+ keywords: ["cursor", "splash", "ripple", "click", "effect", "interactive"],
2067
+ useCases: [
2068
+ "Interactive experiences",
2069
+ "Creative portfolios",
2070
+ "Playful interfaces",
2071
+ "Click feedback"
2072
+ ],
2073
+ dependencies: [],
2074
+ example: `// Place once in layout. Replaces default cursor globally.
2075
+ <SplashCursor />`
2076
+ },
2077
+ "target-cursor": {
2078
+ name: "TargetCursor",
2079
+ category: "cursor",
2080
+ description: "Custom cursor with target/crosshair appearance",
2081
+ keywords: ["cursor", "target", "crosshair", "pointer", "custom"],
2082
+ useCases: [
2083
+ "Gaming interfaces",
2084
+ "Precision tools",
2085
+ "Interactive elements",
2086
+ "Custom pointers"
2087
+ ],
2088
+ dependencies: [],
2089
+ example: `// Place once in layout. Replaces default cursor globally.
2090
+ <TargetCursor />`
2091
+ },
2092
+ // ============================================================================
2093
+ // SPECIALTY - Motion (1)
2094
+ // ============================================================================
2095
+ "animated-beam": {
2096
+ name: "AnimatedBeam",
2097
+ category: "motion",
2098
+ description: "Animated beam/line connecting two elements",
2099
+ keywords: ["beam", "animation", "connection", "line", "flow", "motion"],
2100
+ useCases: [
2101
+ "Connecting elements",
2102
+ "Data flow visualization",
2103
+ "Architecture diagrams",
2104
+ "Interactive connections"
2105
+ ],
2106
+ dependencies: ["framer-motion"],
2107
+ props: {
2108
+ fromRef: { type: "RefObject<HTMLElement>", description: "Ref to source element", required: true },
2109
+ toRef: { type: "RefObject<HTMLElement>", description: "Ref to target element", required: true },
2110
+ duration: { type: "number", default: "3", description: "Animation duration in seconds" }
2111
+ },
2112
+ example: `const fromRef = useRef(null)
2113
+ const toRef = useRef(null)
2114
+ <div ref={fromRef}>Source</div>
2115
+ <div ref={toRef}>Target</div>
2116
+ <AnimatedBeam fromRef={fromRef} toRef={toRef} />`
2117
+ },
2118
+ // ============================================================================
2119
+ // SPECIALTY - Blocks (2)
2120
+ // ============================================================================
2121
+ hero: {
2122
+ name: "Hero",
2123
+ category: "blocks",
2124
+ description: "Full-width hero section with title, subtitle, and CTA",
2125
+ keywords: ["hero", "banner", "header", "landing", "cta", "section"],
2126
+ useCases: [
2127
+ "Landing pages",
2128
+ "Page headers",
2129
+ "Marketing sections",
2130
+ "Feature highlights"
2131
+ ],
2132
+ dependencies: [],
2133
+ props: {
2134
+ title: { type: "string", description: "Main heading text", required: true },
2135
+ subtitle: { type: "string", description: "Subtitle or tagline" },
2136
+ cta: { type: "ReactNode", description: "Call-to-action element (Button, etc.)" },
2137
+ background: { type: "ReactNode", description: "Optional background element (WarpBackground, OrbBackground, etc.)" }
2138
+ },
2139
+ example: `<Hero
2140
+ title="Build Something Beautiful"
2141
+ subtitle="A design system that brings joy."
2142
+ cta={<Button size="lg">Get Started</Button>}
2143
+ />`
2144
+ },
2145
+ "open-graph-card": {
2146
+ name: "OpenGraphCard",
2147
+ category: "blocks",
2148
+ description: "Social media preview card for Open Graph metadata. Use in opengraph-image.tsx.",
2149
+ keywords: ["open-graph", "social", "preview", "card", "meta", "share"],
2150
+ useCases: [
2151
+ "Social sharing previews",
2152
+ "Link previews",
2153
+ "Meta card generation",
2154
+ "Marketing previews"
2155
+ ],
2156
+ dependencies: [],
2157
+ props: {
2158
+ title: { type: "string", default: "'Sage Design Engine'", description: "Main title text" },
2159
+ description: { type: "string", description: "Subtitle text" },
2160
+ variant: { type: "'primary' | 'secondary' | 'accent' | 'sage' | 'emerald' | 'gradient'", default: "'sage'", description: "Visual style variant" },
2161
+ icon: { type: "ReactNode", description: "Custom logo or icon element" },
2162
+ gradient: { type: "{ type: string; angle: number; colors: string[] }", description: 'Custom gradient config (variant="gradient")' },
2163
+ primaryColor: { type: "string", description: "Override primary color (hex)" },
2164
+ secondaryColor: { type: "string", description: "Override secondary color (hex)" },
2165
+ accentColor: { type: "string", description: "Override accent color (hex)" }
2166
+ },
2167
+ example: `// In opengraph-image.tsx:
2168
+ export default function OGImage() {
2169
+ return <OpenGraphCard title="My Page" description="A great description" variant="primary" />
2170
+ }`
720
2171
  }
721
2172
  };
722
2173
  function getComponentsByCategory(category) {
@@ -756,13 +2207,13 @@ var server = new import_server.Server(
756
2207
  var TOOLS = [
757
2208
  {
758
2209
  name: "list_components",
759
- description: "List all available Sage UI components. Optionally filter by category (actions, forms, navigation, overlays, feedback, data-display, layout).",
2210
+ description: "List all available Sage UI components. Optionally filter by category (core: actions, forms, navigation, overlays, feedback, data-display, layout; specialty: backgrounds, cursor, motion, blocks).",
760
2211
  inputSchema: {
761
2212
  type: "object",
762
2213
  properties: {
763
2214
  category: {
764
2215
  type: "string",
765
- description: "Filter by category: actions, forms, navigation, overlays, feedback, data-display, or layout",
2216
+ description: "Filter by category. Core: actions, forms, navigation, overlays, feedback, data-display, layout. Specialty: backgrounds, cursor, motion, blocks.",
766
2217
  enum: [
767
2218
  "actions",
768
2219
  "forms",
@@ -770,7 +2221,11 @@ var TOOLS = [
770
2221
  "overlays",
771
2222
  "feedback",
772
2223
  "data-display",
773
- "layout"
2224
+ "layout",
2225
+ "backgrounds",
2226
+ "cursor",
2227
+ "motion",
2228
+ "blocks"
774
2229
  ]
775
2230
  }
776
2231
  }
@@ -862,6 +2317,47 @@ function formatComponentDetails(component) {
862
2317
  ${component.description}
863
2318
 
864
2319
  `;
2320
+ const importParts = [component.name];
2321
+ if (component.subComponents) {
2322
+ importParts.push(...component.subComponents);
2323
+ }
2324
+ output += `## Import
2325
+ `;
2326
+ output += `\`\`\`typescript
2327
+ import { ${importParts.join(", ")} } from '@thesage/ui';
2328
+ \`\`\`
2329
+
2330
+ `;
2331
+ if (component.props && Object.keys(component.props).length > 0) {
2332
+ output += `## Props
2333
+
2334
+ `;
2335
+ output += `| Prop | Type | Default | Description |
2336
+ `;
2337
+ output += `|------|------|---------|-------------|
2338
+ `;
2339
+ Object.entries(component.props).forEach(([name, prop]) => {
2340
+ const required = prop.required ? " **(required)**" : "";
2341
+ const defaultVal = prop.default || "-";
2342
+ output += `| ${name} | \`${prop.type}\` | ${defaultVal} | ${prop.description}${required} |
2343
+ `;
2344
+ });
2345
+ output += "\n";
2346
+ }
2347
+ if (component.subComponents && component.subComponents.length > 0) {
2348
+ output += `## Sub-Components
2349
+ `;
2350
+ output += component.subComponents.join(", ") + "\n\n";
2351
+ }
2352
+ if (component.example) {
2353
+ output += `## Example
2354
+ `;
2355
+ output += `\`\`\`tsx
2356
+ ${component.example}
2357
+ \`\`\`
2358
+
2359
+ `;
2360
+ }
865
2361
  output += `## Use Cases
866
2362
  `;
867
2363
  component.useCases.forEach((useCase) => {
@@ -869,9 +2365,6 @@ ${component.description}
869
2365
  `;
870
2366
  });
871
2367
  output += "\n";
872
- output += `## Keywords
873
- `;
874
- output += component.keywords.join(", ") + "\n\n";
875
2368
  if (component.dependencies.length > 0) {
876
2369
  output += `## Dependencies
877
2370
  `;
@@ -888,16 +2381,12 @@ ${component.description}
888
2381
 
889
2382
  `;
890
2383
  }
891
- output += `## Import
892
- `;
893
- output += `\`\`\`typescript
894
- import { ${component.name} } from '@thesage/ui';
895
- \`\`\`
896
-
897
- `;
898
2384
  output += `## Documentation
899
2385
  `;
900
- output += `View full documentation at: https://thesage.dev/#${component.category}/${component.name.toLowerCase().replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()}
2386
+ output += `View full documentation at: https://thesage.dev/docs#${component.category}/${component.name.toLowerCase().replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()}
2387
+ `;
2388
+ output += `
2389
+ Full API reference: https://thesage.dev/llms-full.txt
901
2390
  `;
902
2391
  return output;
903
2392
  }