@gradeui/ui 0.8.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/components/ui/accordion.md +30 -0
  2. package/components/ui/ai-chat.md +35 -0
  3. package/components/ui/alert.md +21 -0
  4. package/components/ui/app-shell.md +61 -0
  5. package/components/ui/avatar.md +18 -0
  6. package/components/ui/badge.md +18 -0
  7. package/components/ui/breadcrumb.md +54 -0
  8. package/components/ui/button.md +31 -0
  9. package/components/ui/calendar.md +39 -0
  10. package/components/ui/card.md +25 -0
  11. package/components/ui/chart.md +48 -0
  12. package/components/ui/checkbox.md +19 -0
  13. package/components/ui/collapsible.md +28 -0
  14. package/components/ui/command.md +38 -0
  15. package/components/ui/date-picker.md +52 -0
  16. package/components/ui/dialog.md +29 -0
  17. package/components/ui/dropdown-menu.md +39 -0
  18. package/components/ui/flex.md +41 -0
  19. package/components/ui/grid.md +44 -0
  20. package/components/ui/hover-card.md +35 -0
  21. package/components/ui/input.md +17 -0
  22. package/components/ui/label.md +14 -0
  23. package/components/ui/map.md +80 -0
  24. package/components/ui/media-surface.md +18 -0
  25. package/components/ui/popover.md +36 -0
  26. package/components/ui/progress.md +14 -0
  27. package/components/ui/radio-group.md +37 -0
  28. package/components/ui/resizable.md +30 -0
  29. package/components/ui/rive-player.md +38 -0
  30. package/components/ui/row.md +32 -0
  31. package/components/ui/scroll-area.md +27 -0
  32. package/components/ui/select.md +24 -0
  33. package/components/ui/separator.md +16 -0
  34. package/components/ui/shader-preset-picker.md +26 -0
  35. package/components/ui/shader-preset-preview.md +24 -0
  36. package/components/ui/sheet.md +46 -0
  37. package/components/ui/side-menu.md +40 -0
  38. package/components/ui/simple-tabs.md +27 -0
  39. package/components/ui/skeleton.md +17 -0
  40. package/components/ui/slider.md +48 -0
  41. package/components/ui/stack.md +32 -0
  42. package/components/ui/switch.md +20 -0
  43. package/components/ui/table.md +27 -0
  44. package/components/ui/tabs.md +39 -0
  45. package/components/ui/textarea.md +14 -0
  46. package/components/ui/three-scene.md +226 -0
  47. package/components/ui/toast.md +38 -0
  48. package/components/ui/toggle-group.md +36 -0
  49. package/components/ui/toggle.md +36 -0
  50. package/components/ui/tooltip.md +28 -0
  51. package/components/ui/video-player.md +27 -0
  52. package/dist/index.d.mts +252 -90
  53. package/dist/index.d.ts +252 -90
  54. package/dist/index.js +240 -240
  55. package/dist/index.js.map +1 -1
  56. package/dist/index.mjs +240 -240
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/map/google.d.mts +6 -0
  59. package/dist/map/google.d.ts +6 -0
  60. package/dist/map/google.js +2 -0
  61. package/dist/map/google.js.map +1 -0
  62. package/dist/map/google.mjs +2 -0
  63. package/dist/map/google.mjs.map +1 -0
  64. package/dist/map/mapbox.d.mts +6 -0
  65. package/dist/map/mapbox.d.ts +6 -0
  66. package/dist/map/mapbox.js +3 -0
  67. package/dist/map/mapbox.js.map +1 -0
  68. package/dist/map/mapbox.mjs +3 -0
  69. package/dist/map/mapbox.mjs.map +1 -0
  70. package/dist/map/maplibre.d.mts +6 -0
  71. package/dist/map/maplibre.d.ts +6 -0
  72. package/dist/map/maplibre.js +3 -0
  73. package/dist/map/maplibre.js.map +1 -0
  74. package/dist/map/maplibre.mjs +3 -0
  75. package/dist/map/maplibre.mjs.map +1 -0
  76. package/dist/styles.css +1 -1
  77. package/dist/types-BxywIwvG.d.mts +160 -0
  78. package/dist/types-BxywIwvG.d.ts +160 -0
  79. package/package.json +42 -5
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: Accordion
3
+ import: "@gradeui/ui"
4
+ subcomponents: [AccordionItem, AccordionTrigger, AccordionContent]
5
+ props:
6
+ - Accordion: type: "single" | "multiple" — single keeps one open at a time, multiple lets several be open at once
7
+ - Accordion: collapsible?: boolean — only valid with type="single"; allows the open item to be toggled shut
8
+ - Accordion: defaultValue?: string | string[] — initial open item(s)
9
+ - Accordion: value?: string | string[] — controlled
10
+ - Accordion: onValueChange?: (value: string | string[]) => void
11
+ - AccordionItem: value: string — id used by the open-state machinery
12
+ - AccordionTrigger: children: React.ReactNode — the row label users click to expand
13
+ - AccordionContent: children: React.ReactNode — the body that animates in
14
+ when_to_use: Long-form content that would overwhelm if shown all at once — FAQs, settings groups, "what's included" sections, nested help. For tab-style peer views with one always visible, reach for Tabs. For a single show/hide reveal use Collapsible.
15
+ composes_with: [Card (as a faq inside a card body), Section primitives]
16
+ aliases: [accordion, faq, expand, collapse list, disclosure list]
17
+ ---
18
+
19
+ ```jsx
20
+ <Accordion type="single" collapsible defaultValue="one">
21
+ <AccordionItem value="one">
22
+ <AccordionTrigger>What's included?</AccordionTrigger>
23
+ <AccordionContent>Everything in the design system, plus Studio.</AccordionContent>
24
+ </AccordionItem>
25
+ <AccordionItem value="two">
26
+ <AccordionTrigger>Can I bring my own theme?</AccordionTrigger>
27
+ <AccordionContent>Yes — three hues in, full theme out.</AccordionContent>
28
+ </AccordionItem>
29
+ </Accordion>
30
+ ```
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: AIChat
3
+ import: "@gradeui/ui"
4
+ props:
5
+ - messages?: ChatMessage[] — `{ id, role: "user" | "assistant", content, timestamp }`; defaults to empty
6
+ - onSendMessage?: (message: string) => void — fires when the user submits a query
7
+ - isLoading?: boolean — shows a typing indicator on the last assistant turn
8
+ - placeholder?: string — input placeholder text
9
+ - suggestedPrompts?: { icon?: React.ReactNode; text: string }[] — empty-state quick prompts
10
+ - className?: string
11
+ when_to_use: A pre-built chat block — paste it in to get a working LLM chat surface without composing the message list, autoscroll, suggested prompts, and submit input yourself. Reach for it as the "AI panel" in an admin/support tool, or to demo an LLM-driven feature inside a marketing page. For Studio-grade chat with file refs and streaming structured output, you'll outgrow this and want a custom composition built on Textarea + Card + ScrollArea.
12
+ composes_with: [Card (host in a sidebar panel), Sheet (mobile drawer), Stack (place above other content)]
13
+ aliases: [ai chat, chat panel, chat block, llm chat, assistant panel, copilot chat]
14
+ ---
15
+
16
+ ```jsx
17
+ const [messages, setMessages] = useState([]);
18
+ const [loading, setLoading] = useState(false);
19
+
20
+ <AIChat
21
+ messages={messages}
22
+ isLoading={loading}
23
+ onSendMessage={async (text) => {
24
+ setMessages((m) => [...m, { id: uid(), role: "user", content: text, timestamp: new Date() }]);
25
+ setLoading(true);
26
+ const reply = await fetchAssistant(text);
27
+ setMessages((m) => [...m, { id: uid(), role: "assistant", content: reply, timestamp: new Date() }]);
28
+ setLoading(false);
29
+ }}
30
+ suggestedPrompts={[
31
+ { icon: <Sparkles />, text: "Summarise this page" },
32
+ { icon: <Lightbulb />, text: "Suggest next steps" },
33
+ ]}
34
+ />
35
+ ```
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: Alert
3
+ import: "@gradeui/ui"
4
+ subcomponents: [AlertTitle, AlertDescription]
5
+ variants: [default, destructive, success, warning, info, highlight]
6
+ props:
7
+ - variant? (default | destructive | success | warning | info | highlight)
8
+ - All native div HTML attrs
9
+ when_to_use: Inline status/feedback that sits inside the layout flow. NOT a toast (use Sonner for transient). NOT a modal (use Dialog). Put an icon as first child — it will be auto-positioned; AlertTitle + AlertDescription follow.
10
+ composes_with: [lucide-react icons as first child, Button (inside AlertDescription), Card (as a section callout)]
11
+ ---
12
+
13
+ Variant tokens come from theme (`--destructive-soft`, `--success-deep`, etc.) so they restyle with the active Grade theme.
14
+
15
+ ```jsx
16
+ <Alert variant="warning">
17
+ <AlertTriangle />
18
+ <AlertTitle>Low disk space</AlertTitle>
19
+ <AlertDescription>2GB remaining on /dev/sda1.</AlertDescription>
20
+ </Alert>
21
+ ```
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: AppShell
3
+ import: "@gradeui/ui"
4
+ role: layout
5
+ subcomponents: [AppShellNav, AppShellMain]
6
+ props:
7
+ - nav?: "none" | "top" | "side" (default "none") — layout structure. "top" puts the nav above main, "side" to the left, "none" hides it
8
+ - asChild?: boolean (default false) — render as the child element via Slot
9
+ - className?: string
10
+ - children: React.ReactNode
11
+ when_to_use: The top-level page scaffold for app-like layouts — any screen that needs a nav region plus a content region. Reach for AppShell instead of hand-rolled `grid grid-cols-[auto_1fr]` so the layout shape (top vs side nav, constrained vs full-width main) is a prop the settings panel can mutate. Drop a Stack of nav items into AppShellNav for the nav region; drop a Stack into AppShellMain for the page's vertical rhythm.
12
+ composes_with: [Stack, Row, Card, Button, Separator, any page content]
13
+ aliases: [app shell, page shell, layout, app layout, dashboard shell, scaffold]
14
+ notes: |
15
+ Three parts:
16
+ AppShell — <div> by default; sets the grid (nav=none|top|side)
17
+ AppShellNav — <nav> by default; props: placement ("top"|"side"|"none", match AppShell.nav), sticky (boolean, default true)
18
+ AppShellMain — <main> by default; props: maxWidth ("full"|"container", default "full")
19
+ All three support asChild and emit data-gds-part ("app-shell", "app-shell-nav", "app-shell-main").
20
+ Pure structure — no collapse state, no context. Server-renders cleanly.
21
+ For nav placement="side" + sticky=true the nav gets h-screen + self-scroll, so long nav lists don't push main down.
22
+ ---
23
+
24
+ ```jsx
25
+ // Side nav + full-width main — the classic dashboard shape.
26
+ <AppShell nav="side">
27
+ <AppShellNav placement="side">
28
+ {/* nav items — Stack of Buttons, a SideMenu, etc. */}
29
+ </AppShellNav>
30
+ <AppShellMain>
31
+ <Stack gap="lg" className="p-6">
32
+ {/* page content */}
33
+ </Stack>
34
+ </AppShellMain>
35
+ </AppShell>
36
+ ```
37
+
38
+ ```jsx
39
+ // Top nav + constrained content — marketing / docs / settings pages.
40
+ <AppShell nav="top">
41
+ <AppShellNav placement="top">
42
+ <Row justify="between" align="center" className="px-6 py-3">
43
+ {/* logo + nav buttons */}
44
+ </Row>
45
+ </AppShellNav>
46
+ <AppShellMain maxWidth="container">
47
+ <Stack gap="lg" className="py-8">
48
+ {/* page content */}
49
+ </Stack>
50
+ </AppShellMain>
51
+ </AppShell>
52
+ ```
53
+
54
+ ```jsx
55
+ // No nav — just a shell for a single-screen prototype.
56
+ <AppShell nav="none">
57
+ <AppShellMain maxWidth="container">
58
+ {/* page content */}
59
+ </AppShellMain>
60
+ </AppShell>
61
+ ```
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: Avatar
3
+ import: "@gradeui/ui"
4
+ subcomponents: [AvatarImage, AvatarFallback]
5
+ props:
6
+ - Avatar: className? — set size via utilities (default h-10 w-10)
7
+ - AvatarImage: src, alt
8
+ - AvatarFallback: initials/icon rendered when image fails or loads
9
+ when_to_use: User/entity identity in lists, cards, headers. Always include AvatarFallback so load failure doesn't leave a gap.
10
+ composes_with: [Card (in CardHeader), Table cells, Badge (placed next to for status), Skeleton (loading state)]
11
+ ---
12
+
13
+ ```jsx
14
+ <Avatar>
15
+ <AvatarImage src="/ada.jpg" alt="Ada Lovelace" />
16
+ <AvatarFallback>AL</AvatarFallback>
17
+ </Avatar>
18
+ ```
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: Badge
3
+ import: "@gradeui/ui"
4
+ variants: [default, secondary, destructive, outline, highlight, success, warning, info, success-soft, warning-soft, destructive-soft, info-soft, highlight-soft, success-outline, warning-outline, destructive-outline, info-outline]
5
+ props:
6
+ - variant? (see list above)
7
+ - rounded? (default | full) — "full" gives a pill shape
8
+ - All native div HTML attrs
9
+ when_to_use: Compact status chips, counts, tags, pills. For higher-signal inline status → use Alert. For solid CTAs → Button. Soft/outline variants are quieter; solid variants are loud.
10
+ composes_with: [Card, Table (inside a cell), Avatar (next to it), anywhere inline]
11
+ aliases: [chip, tag, pill, label chip]
12
+ ---
13
+
14
+ ```jsx
15
+ <Badge>New</Badge>
16
+ <Badge variant="success-soft" rounded="full">Active</Badge>
17
+ <Badge variant="destructive-outline">Blocked</Badge>
18
+ ```
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: Breadcrumb
3
+ import: "@gradeui/ui"
4
+ subcomponents: [BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis]
5
+ props:
6
+ - Breadcrumb: aria-label? (defaults to "breadcrumb") — passed to the underlying <nav>
7
+ - BreadcrumbList: className? — the <ol> wrapper; usually no overrides needed
8
+ - BreadcrumbItem: className? — wraps a single crumb (link or page)
9
+ - BreadcrumbLink: href? — renders as <a> when set, <button> when not; asChild? wraps a custom element
10
+ - BreadcrumbPage: className? — the current page; rendered as a non-interactive <span> with aria-current="page"
11
+ - BreadcrumbSeparator: children? (defaults to a chevron) — the visual separator between crumbs
12
+ - BreadcrumbEllipsis: className? — collapsed middle crumbs marker, use between BreadcrumbItems
13
+ when_to_use: Reach for Breadcrumb whenever a screen sits inside a hierarchy and you want the path back to the top to be visible. Common spots: above page titles in admin/CMS screens, top of Settings detail pages, after a router redirect when the URL implies depth. Use the current page as a <BreadcrumbPage> (non-clickable) and prior levels as <BreadcrumbLink>. For a horizontal "top nav" of peer destinations use Side Menu or Tabs instead — Breadcrumb is strictly for hierarchical path.
14
+ composes_with: [AppShellMain, Card (in CardHeader), Dialog]
15
+ aliases: [breadcrumb, breadcrumbs, crumbs, path, page hierarchy]
16
+ ---
17
+
18
+ ```jsx
19
+ // Two-level path — Dashboard → current page.
20
+ <Breadcrumb>
21
+ <BreadcrumbList>
22
+ <BreadcrumbItem>
23
+ <BreadcrumbLink href="/">Dashboard</BreadcrumbLink>
24
+ </BreadcrumbItem>
25
+ <BreadcrumbSeparator />
26
+ <BreadcrumbItem>
27
+ <BreadcrumbPage>Settings</BreadcrumbPage>
28
+ </BreadcrumbItem>
29
+ </BreadcrumbList>
30
+ </Breadcrumb>
31
+ ```
32
+
33
+ ```jsx
34
+ // Deep path with collapsed middle — useful when the path is long.
35
+ <Breadcrumb>
36
+ <BreadcrumbList>
37
+ <BreadcrumbItem>
38
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
39
+ </BreadcrumbItem>
40
+ <BreadcrumbSeparator />
41
+ <BreadcrumbItem>
42
+ <BreadcrumbEllipsis />
43
+ </BreadcrumbItem>
44
+ <BreadcrumbSeparator />
45
+ <BreadcrumbItem>
46
+ <BreadcrumbLink href="/projects/acme">Acme</BreadcrumbLink>
47
+ </BreadcrumbItem>
48
+ <BreadcrumbSeparator />
49
+ <BreadcrumbItem>
50
+ <BreadcrumbPage>Billing</BreadcrumbPage>
51
+ </BreadcrumbItem>
52
+ </BreadcrumbList>
53
+ </Breadcrumb>
54
+ ```
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: Button
3
+ import: "@gradeui/ui"
4
+ variants: [default, destructive, outline, secondary, ghost, link]
5
+ sizes: [sm, md, lg, icon]
6
+ props:
7
+ - variant? (default | destructive | outline | secondary | ghost | link)
8
+ - size? (sm | md | lg | icon) — t-shirt scale aligned with Tabs/ToggleGroup heights (sm=h-7, md=h-8, lg=h-10). `default` still works as an alias for `md`.
9
+ - asChild?: boolean — renders as the child element (use to wrap <a>/<Link>)
10
+ - disabled?: boolean
11
+ - All native button HTML attrs (onClick, type, etc.)
12
+ when_to_use: Any clickable action. Use size="icon" for square icon-only buttons, variant="link" for inline links that should look like Button. A Button placed next to a TabsList of the same size lines up edge-to-edge without per-call overrides.
13
+ composes_with: [Dialog, DropdownMenu, Tooltip, Card (in CardFooter), Row, Form controls]
14
+ ---
15
+
16
+ ```jsx
17
+ <Button>Save</Button>
18
+ <Button variant="outline" size="sm">Cancel</Button>
19
+ <Button size="icon" variant="ghost"><Mail /></Button>
20
+ ```
21
+
22
+ ```jsx
23
+ // Lined up next to a TabsList — same size = same height.
24
+ <Row gap="sm" align="center">
25
+ <TabsList size="sm">
26
+ <TabsTrigger value="all">All</TabsTrigger>
27
+ <TabsTrigger value="open">Open</TabsTrigger>
28
+ </TabsList>
29
+ <Button size="sm">New issue</Button>
30
+ </Row>
31
+ ```
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: Calendar
3
+ import: "@gradeui/ui"
4
+ subcomponents: [CalendarDayButton]
5
+ props:
6
+ - mode?: "single" | "multiple" | "range" — picks one date, several dates, or a [from, to] range
7
+ - selected?: Date | Date[] | { from: Date; to?: Date } — controlled selection; shape matches `mode`
8
+ - onSelect?: (value) => void — fires with the new selection
9
+ - month?: Date — controlled displayed month
10
+ - defaultMonth?: Date — uncontrolled initial month
11
+ - onMonthChange?: (date: Date) => void
12
+ - numberOfMonths?: number (default 1) — render multiple months side by side, useful for range pickers
13
+ - disabled?: Date | Date[] | { before?: Date; after?: Date } | (date: Date) => boolean
14
+ - captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years"
15
+ - className?: string
16
+ when_to_use: An inline date grid — date-of-birth pickers in profile forms, scheduling screens with a month view, range selection in reporting filters. For a compact trigger-and-popover input, use DatePicker / DateRangePicker (which wrap Calendar internally). For one-off relative dates ("yesterday", "last week") use a Select instead.
17
+ composes_with: [Popover (DatePicker composes them), Card (inline scheduling card), Dialog (full-screen mobile date pick)]
18
+ aliases: [calendar, date grid, month view, scheduler grid]
19
+ ---
20
+
21
+ ```jsx
22
+ // Single-date inline calendar.
23
+ <Calendar
24
+ mode="single"
25
+ selected={date}
26
+ onSelect={setDate}
27
+ captionLayout="dropdown"
28
+ />
29
+ ```
30
+
31
+ ```jsx
32
+ // Two-month range picker — typical reporting filter shape.
33
+ <Calendar
34
+ mode="range"
35
+ numberOfMonths={2}
36
+ selected={range}
37
+ onSelect={setRange}
38
+ />
39
+ ```
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: Card
3
+ import: "@gradeui/ui"
4
+ subcomponents: [CardHeader, CardTitle, CardDescription, CardContent, CardFooter]
5
+ props:
6
+ - Each subcomponent accepts native div HTML attrs (className, etc.)
7
+ - No variants — Card is a flexible container surface
8
+ when_to_use: Grouped content with a distinct surface — settings panels, dashboard tiles, list-of-cards layouts. Pair CardHeader (title + description) with CardContent and optional CardFooter (actions).
9
+ composes_with: [Button (in CardFooter), Badge, Separator, Avatar, any form controls]
10
+ ---
11
+
12
+ Canonical structure — do NOT skip CardHeader if the card has a title:
13
+
14
+ ```jsx
15
+ <Card>
16
+ <CardHeader>
17
+ <CardTitle>Billing</CardTitle>
18
+ <CardDescription>Manage your subscription.</CardDescription>
19
+ </CardHeader>
20
+ <CardContent>…</CardContent>
21
+ <CardFooter>
22
+ <Button>Save</Button>
23
+ </CardFooter>
24
+ </Card>
25
+ ```
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: ChartContainer
3
+ import: "@gradeui/ui"
4
+ subcomponents: [ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle]
5
+ notes: ChartContainer wraps a Recharts chart — bring your own Bar/Line/Area/Pie/Radar from "recharts" and place it inside. The wrapper threads design-system tokens through Recharts' style props and provides a styled tooltip + legend.
6
+ props:
7
+ - ChartContainer: config: ChartConfig — `{ [seriesKey]: { label: string; color?: string; theme?: { light: string; dark: string } } }`; the keys here are the names you reference in your Recharts <Bar dataKey="…" /> calls
8
+ - ChartContainer: id?: string — used for the inlined <style> tag
9
+ - ChartContainer: children: React.ReactNode — typically a single Recharts ResponsiveContainer or chart
10
+ - ChartTooltip: passes through to Recharts <Tooltip> — pair with `content={<ChartTooltipContent />}`
11
+ - ChartTooltipContent: indicator? "dot" | "line" | "dashed"; hideLabel?, hideIndicator?, nameKey?, labelKey?
12
+ - ChartLegend / ChartLegendContent: pair the same way for the legend
13
+ when_to_use: Reporting dashboards, single-purpose analytics cards (revenue, conversions, active users), or anywhere you'd otherwise hand-roll a Recharts setup. Bring the actual chart type from `recharts` — ChartContainer doesn't pick the chart shape for you, it themes whatever you nest. For sparkline-style decorative trends consider just rendering a small SVG line directly; ChartContainer is overkill for non-interactive ornament.
14
+ composes_with: [Card (chart-in-a-card pattern), Tabs (multi-metric switcher), Recharts components (Bar, Line, Area, Pie, Radar from "recharts")]
15
+ aliases: [chart, charts, graph, bar chart, line chart, area chart, recharts, analytics chart]
16
+ ---
17
+
18
+ ```jsx
19
+ // Revenue-by-month bar chart inside a Card.
20
+ import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
21
+
22
+ const data = [
23
+ { month: "Jan", revenue: 12400 },
24
+ { month: "Feb", revenue: 14210 },
25
+ { month: "Mar", revenue: 15880 },
26
+ { month: "Apr", revenue: 17050 },
27
+ ];
28
+
29
+ const config = {
30
+ revenue: { label: "Revenue", color: "hsl(var(--primary))" },
31
+ } satisfies ChartConfig;
32
+
33
+ <Card>
34
+ <CardHeader>
35
+ <CardTitle>Revenue</CardTitle>
36
+ </CardHeader>
37
+ <CardContent>
38
+ <ChartContainer config={config} className="h-64">
39
+ <BarChart data={data}>
40
+ <CartesianGrid vertical={false} />
41
+ <XAxis dataKey="month" tickLine={false} axisLine={false} />
42
+ <ChartTooltip content={<ChartTooltipContent />} />
43
+ <Bar dataKey="revenue" fill="var(--color-revenue)" radius={4} />
44
+ </BarChart>
45
+ </ChartContainer>
46
+ </CardContent>
47
+ </Card>
48
+ ```
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: Checkbox
3
+ import: "@gradeui/ui"
4
+ props:
5
+ - checked?: boolean | "indeterminate"
6
+ - onCheckedChange?: (checked: boolean) => void
7
+ - defaultChecked?: boolean
8
+ - disabled?: boolean
9
+ - id?: string — bind a Label's htmlFor to this
10
+ when_to_use: Binary on/off tied to a list (select multiple, agree to terms). Single on/off that controls a setting is better with Switch.
11
+ composes_with: [Label (via htmlFor), Card, Form rows, Table (for row selection)]
12
+ ---
13
+
14
+ ```jsx
15
+ <div className="flex items-center gap-2">
16
+ <Checkbox id="terms" />
17
+ <Label htmlFor="terms">I agree to the terms</Label>
18
+ </div>
19
+ ```
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: Collapsible
3
+ import: "@gradeui/ui"
4
+ subcomponents: [CollapsibleTrigger, CollapsibleContent]
5
+ props:
6
+ - Collapsible: open?: boolean — controlled open state
7
+ - Collapsible: defaultOpen?: boolean — uncontrolled initial state
8
+ - Collapsible: onOpenChange?: (open: boolean) => void
9
+ - CollapsibleTrigger: children: React.ReactNode — the clickable header (often a Button asChild)
10
+ - CollapsibleContent: children: React.ReactNode — the content that animates in/out
11
+ when_to_use: A single show/hide reveal — "Show advanced settings" rows, expandable inline help, "More details" sections inside cards. For multiple rows of expandable content where one-at-a-time matters, reach for Accordion. For a separate panel that floats above content, use Popover.
12
+ composes_with: [Button (as the trigger, asChild), Card (expandable settings group), Row (header + chevron)]
13
+ aliases: [collapsible, expand, show more, disclosure, advanced settings]
14
+ ---
15
+
16
+ ```jsx
17
+ <Collapsible defaultOpen={false}>
18
+ <CollapsibleTrigger asChild>
19
+ <Button variant="ghost" size="sm">
20
+ Advanced settings <ChevronDown />
21
+ </Button>
22
+ </CollapsibleTrigger>
23
+ <CollapsibleContent className="space-y-2 pt-2">
24
+ <Label htmlFor="cors">CORS origins</Label>
25
+ <Input id="cors" placeholder="https://example.com" />
26
+ </CollapsibleContent>
27
+ </Collapsible>
28
+ ```
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: Command
3
+ import: "@gradeui/ui"
4
+ subcomponents: [CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, CommandDialog]
5
+ props:
6
+ - Command: value?: string — controlled active item value
7
+ - Command: onValueChange?: (value: string) => void
8
+ - CommandInput: placeholder?: string
9
+ - CommandList: children: React.ReactNode — wraps groups and empty state
10
+ - CommandEmpty: children: React.ReactNode — fallback when no items match
11
+ - CommandGroup: heading?: string
12
+ - CommandItem: value?: string — used for filter matching and selection emit
13
+ - CommandItem: onSelect?: (value: string) => void
14
+ - CommandItem: disabled?: boolean
15
+ - CommandShortcut: children: React.ReactNode — right-aligned keyboard hint (⌘K, ⌥F)
16
+ - CommandDialog: open, onOpenChange — when you want the command palette mounted in a modal (cmd+k pattern)
17
+ when_to_use: A searchable list of actions or destinations — global ⌘K palettes, "jump to" inputs, account switchers with filter. Wrap in CommandDialog when it should pop over the entire app on a hotkey. For straight forms with filter, prefer a Select with a search input. For free-text autocomplete tied to a single value, prefer Combobox built on Popover + Command.
18
+ composes_with: [Dialog (CommandDialog wraps it), Popover (inline combobox), Tooltip]
19
+ aliases: [command palette, command menu, cmd k, quick switcher, action menu]
20
+ ---
21
+
22
+ ```jsx
23
+ // Global ⌘K palette — toggled with a keydown listener at the app root.
24
+ <CommandDialog open={open} onOpenChange={setOpen}>
25
+ <CommandInput placeholder="Type a command…" />
26
+ <CommandList>
27
+ <CommandEmpty>No results found.</CommandEmpty>
28
+ <CommandGroup heading="Navigate">
29
+ <CommandItem onSelect={() => router.push("/docs")}>
30
+ <Book /> Docs <CommandShortcut>⌘D</CommandShortcut>
31
+ </CommandItem>
32
+ <CommandItem onSelect={() => router.push("/studio")}>
33
+ <Sparkles /> Studio <CommandShortcut>⌘S</CommandShortcut>
34
+ </CommandItem>
35
+ </CommandGroup>
36
+ </CommandList>
37
+ </CommandDialog>
38
+ ```
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: DatePicker
3
+ import: "@gradeui/ui"
4
+ props:
5
+ - value?: Date (single) | DateRange (range)
6
+ - onChange?: (value) => void — called on select or clear
7
+ - placeholder?: string — trigger label when empty (default "Pick a date" / "Pick a date range")
8
+ - disabled?: boolean
9
+ - format?: string — date-fns format token for the trigger label (default "PPP" single, "LLL dd, y" range)
10
+ - align?: "start" | "center" | "end" — popover align (default "start")
11
+ - side?: "top" | "right" | "bottom" | "left" — popover side
12
+ - captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years"
13
+ - className?: string — on the trigger button
14
+ - contentClassName?: string — on the PopoverContent
15
+ - icon?: ReactNode — replaces the default CalendarIcon
16
+ - numberOfMonths?: number — DateRangePicker only, default 2
17
+ when_to_use: Any date or date-range entry. Use DatePicker for a single date (DOB, due date, booking). Use DateRangePicker for a span (report period, stay dates, filter window). Prefer these over <Input type="date"> — consistent theming, keyboard nav, a11y, and no browser-native UI drift.
18
+ composes_with: [Label, Form, Card (in CardContent), Button (form submit)]
19
+ subcomponents: [DateRangePicker]
20
+ aliases: [datepicker, calendar input, date field, date range]
21
+ ---
22
+
23
+ ```jsx
24
+ // Single date
25
+ <div className="grid gap-1.5">
26
+ <Label htmlFor="dob">Date of birth</Label>
27
+ <DatePicker
28
+ value={date}
29
+ onChange={setDate}
30
+ placeholder="Select your birthday"
31
+ />
32
+ </div>
33
+ ```
34
+
35
+ ```jsx
36
+ // Date range
37
+ <DateRangePicker
38
+ value={range}
39
+ onChange={setRange}
40
+ numberOfMonths={2}
41
+ />
42
+ ```
43
+
44
+ ```jsx
45
+ // With presets — pair with Button shortcuts
46
+ <div className="flex items-center gap-2">
47
+ <DatePicker value={date} onChange={setDate} />
48
+ <Button variant="outline" size="sm" onClick={() => setDate(new Date())}>Today</Button>
49
+ </div>
50
+ ```
51
+
52
+ Built internally from Popover + Button + Calendar. If you need a custom trigger or different popover positioning, compose the primitives directly — Calendar and Popover are exported from the same barrel.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Dialog
3
+ import: "@gradeui/ui"
4
+ subcomponents: [DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose]
5
+ props:
6
+ - Dialog: open?, onOpenChange? — Radix controlled/uncontrolled pattern
7
+ - DialogTrigger: asChild? (wrap a Button)
8
+ - DialogContent: accepts native div HTML attrs
9
+ - DialogFooter: used for action rows
10
+ when_to_use: Modal interruptions — confirmations, focused forms, detail views. For non-blocking messaging use Alert or Sonner. Always include DialogTitle (a11y requirement).
11
+ composes_with: [Button (as DialogTrigger asChild, and inside DialogFooter), Input/Textarea/Select inside DialogContent]
12
+ aliases: [modal, popup, overlay]
13
+ ---
14
+
15
+ ```jsx
16
+ <Dialog>
17
+ <DialogTrigger asChild><Button>Delete</Button></DialogTrigger>
18
+ <DialogContent>
19
+ <DialogHeader>
20
+ <DialogTitle>Delete project?</DialogTitle>
21
+ <DialogDescription>This cannot be undone.</DialogDescription>
22
+ </DialogHeader>
23
+ <DialogFooter>
24
+ <Button variant="outline">Cancel</Button>
25
+ <Button variant="destructive">Delete</Button>
26
+ </DialogFooter>
27
+ </DialogContent>
28
+ </Dialog>
29
+ ```
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: DropdownMenu
3
+ import: "@gradeui/ui"
4
+ subcomponents: [DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent]
5
+ props:
6
+ - DropdownMenu: open?, defaultOpen?, onOpenChange?, modal? (default true)
7
+ - DropdownMenuTrigger: asChild?: boolean — usually wraps a Button
8
+ - DropdownMenuContent: align? "start" | "center" | "end"; side? "top" | "right" | "bottom" | "left"; sideOffset? number
9
+ - DropdownMenuItem: onSelect?, disabled?, asChild?, inset?
10
+ - DropdownMenuCheckboxItem / DropdownMenuRadioItem: checked? / value, onCheckedChange? / onValueChange? (radio is on the group)
11
+ - DropdownMenuSub / DropdownMenuSubTrigger / DropdownMenuSubContent: nested menu — sub-trigger shows children, sub-content holds the deeper items
12
+ - DropdownMenuShortcut: children — right-aligned kbd hint
13
+ when_to_use: A small action menu attached to a trigger — overflow "…" buttons on cards, user-avatar menus in headers, "Insert" menus in editors. For a full searchable list, use Command. For ONE primary action plus a secondary, use a Button next to a smaller ghost Button instead of a dropdown.
14
+ composes_with: [Button (as trigger asChild), Avatar (user menu), Card (overflow on a tile), Tooltip (on the trigger)]
15
+ aliases: [dropdown, dropdown menu, overflow menu, kebab menu, more menu, action menu, context-style menu]
16
+ ---
17
+
18
+ ```jsx
19
+ // Overflow menu on a card/row — trigger an icon-only Button.
20
+ <DropdownMenu>
21
+ <DropdownMenuTrigger asChild>
22
+ <Button variant="ghost" size="icon" aria-label="Open menu">
23
+ <MoreHorizontal />
24
+ </Button>
25
+ </DropdownMenuTrigger>
26
+ <DropdownMenuContent align="end">
27
+ <DropdownMenuItem onSelect={onDuplicate}>
28
+ <Copy /> Duplicate
29
+ </DropdownMenuItem>
30
+ <DropdownMenuItem onSelect={onShare}>
31
+ <Share2 /> Share
32
+ </DropdownMenuItem>
33
+ <DropdownMenuSeparator />
34
+ <DropdownMenuItem onSelect={onDelete} className="text-destructive">
35
+ <Trash /> Delete
36
+ </DropdownMenuItem>
37
+ </DropdownMenuContent>
38
+ </DropdownMenu>
39
+ ```
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: Flex
3
+ import: "@gradeui/ui"
4
+ role: layout
5
+ props:
6
+ - direction?: "row" | "col" | "row-reverse" | "col-reverse" (default "row") — main-axis direction
7
+ - gap?: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" (default "none") — gap between children
8
+ - align?: "start" | "center" | "end" | "stretch" | "baseline" (default "stretch") — cross-axis alignment
9
+ - justify?: "start" | "center" | "end" | "between" | "around" | "evenly" (default "start") — main-axis distribution
10
+ - wrap?: "nowrap" | "wrap" | "wrap-reverse" (default "nowrap") — wrap behaviour when children overflow
11
+ - asChild?: boolean (default false) — render as the child element via Slot
12
+ - className?: string
13
+ - children: React.ReactNode
14
+ when_to_use: The unopinionated flexbox primitive — reach for Flex when Stack, Row, or Grid don't quite fit. Specifically when you need reverse direction (`row-reverse` / `col-reverse`), CSS defaults instead of Row's baked-in `items-center gap-md`, or baseline alignment. Otherwise prefer Stack / Row / Grid — they're easier to read and tuned for the 95% case. Flex is the escape hatch, not the default.
15
+ composes_with: [any content component]
16
+ aliases: [flex, flexbox, flex container, hstack, vstack, horizontal, vertical]
17
+ ---
18
+
19
+ ```jsx
20
+ // Reverse direction — last child appears first (e.g. timestamp before avatar).
21
+ <Flex direction="row-reverse" gap="sm" align="center">
22
+ <Avatar />
23
+ <span>2m ago</span>
24
+ </Flex>
25
+ ```
26
+
27
+ ```jsx
28
+ // CSS-default Flex — no rhythm baked in, opt into each axis deliberately.
29
+ <Flex direction="col" justify="between" className="h-full">
30
+ <Header />
31
+ <Footer />
32
+ </Flex>
33
+ ```
34
+
35
+ ```jsx
36
+ // Baseline alignment for icon + text where the caps line should line up.
37
+ <Flex gap="sm" align="baseline">
38
+ <Icon />
39
+ <h2 className="text-2xl">Heading</h2>
40
+ </Flex>
41
+ ```