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