ai-design-system 0.1.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 (290) hide show
  1. package/README.md +307 -0
  2. package/components/ai-elements/actions.tsx +65 -0
  3. package/components/ai-elements/artifact.tsx +147 -0
  4. package/components/ai-elements/branch.tsx +212 -0
  5. package/components/ai-elements/canvas.tsx +24 -0
  6. package/components/ai-elements/chain-of-thought.tsx +228 -0
  7. package/components/ai-elements/code-block.tsx +179 -0
  8. package/components/ai-elements/confirmation.tsx +169 -0
  9. package/components/ai-elements/connection.tsx +28 -0
  10. package/components/ai-elements/context.tsx +408 -0
  11. package/components/ai-elements/controls.tsx +18 -0
  12. package/components/ai-elements/conversation.tsx +97 -0
  13. package/components/ai-elements/edge.tsx +140 -0
  14. package/components/ai-elements/image.tsx +24 -0
  15. package/components/ai-elements/inline-citation.tsx +287 -0
  16. package/components/ai-elements/loader.tsx +96 -0
  17. package/components/ai-elements/message.tsx +80 -0
  18. package/components/ai-elements/node.tsx +71 -0
  19. package/components/ai-elements/open-in-chat.tsx +363 -0
  20. package/components/ai-elements/panel.tsx +15 -0
  21. package/components/ai-elements/plan.tsx +142 -0
  22. package/components/ai-elements/prompt-input.tsx +1352 -0
  23. package/components/ai-elements/queue.tsx +274 -0
  24. package/components/ai-elements/reasoning.tsx +178 -0
  25. package/components/ai-elements/response.tsx +22 -0
  26. package/components/ai-elements/shimmer.tsx +64 -0
  27. package/components/ai-elements/sources.tsx +77 -0
  28. package/components/ai-elements/suggestion.tsx +56 -0
  29. package/components/ai-elements/task.tsx +87 -0
  30. package/components/ai-elements/tool.tsx +179 -0
  31. package/components/ai-elements/toolbar.tsx +16 -0
  32. package/components/ai-elements/web-preview.tsx +263 -0
  33. package/components/blocks/AIConversation/AIConversation.stories.tsx +164 -0
  34. package/components/blocks/AIConversation/AIConversation.tsx +186 -0
  35. package/components/blocks/AIConversation/index.ts +8 -0
  36. package/components/blocks/AppSidebar/AppSidebar.stories.tsx +63 -0
  37. package/components/blocks/AppSidebar/AppSidebar.tsx +87 -0
  38. package/components/blocks/AppSidebar/index.ts +2 -0
  39. package/components/blocks/DocumentEditorWithComments/DocumentEditorWithComments.stories.tsx +341 -0
  40. package/components/blocks/DocumentEditorWithComments/DocumentEditorWithComments.tsx +255 -0
  41. package/components/blocks/DocumentEditorWithComments/index.ts +9 -0
  42. package/components/blocks/FileChangeQueue/FileChangeQueue.stories.tsx +207 -0
  43. package/components/blocks/FileChangeQueue/FileChangeQueue.tsx +143 -0
  44. package/components/blocks/FileChangeQueue/index.ts +7 -0
  45. package/components/blocks/LayoutProvider/LayoutProvider.tsx +34 -0
  46. package/components/blocks/LayoutProvider/index.ts +1 -0
  47. package/components/blocks/index.ts +2 -0
  48. package/components/composites/AgentIndicator/AgentIndicator.stories.tsx +154 -0
  49. package/components/composites/AgentIndicator/AgentIndicator.tsx +102 -0
  50. package/components/composites/AgentIndicator/index.ts +8 -0
  51. package/components/composites/AppHeader/AppHeader.stories.tsx +46 -0
  52. package/components/composites/AppHeader/AppHeader.tsx +24 -0
  53. package/components/composites/AppHeader/index.ts +2 -0
  54. package/components/composites/CommentBox/CommentBox.stories.tsx +192 -0
  55. package/components/composites/CommentBox/CommentBox.tsx +364 -0
  56. package/components/composites/CommentBox/index.ts +8 -0
  57. package/components/composites/Confirmation/Confirmation.stories.tsx +151 -0
  58. package/components/composites/Confirmation/Confirmation.tsx +93 -0
  59. package/components/composites/Confirmation/index.ts +7 -0
  60. package/components/composites/DataTable/DataTable.stories.tsx +35 -0
  61. package/components/composites/DataTable/DataTable.tsx +95 -0
  62. package/components/composites/DataTable/index.ts +2 -0
  63. package/components/composites/DocumentEditor/DocumentEditor.css +106 -0
  64. package/components/composites/DocumentEditor/DocumentEditor.stories.tsx +927 -0
  65. package/components/composites/DocumentEditor/DocumentEditor.tsx +279 -0
  66. package/components/composites/DocumentEditor/index.ts +8 -0
  67. package/components/composites/FileQueue/FileQueue.stories.tsx +175 -0
  68. package/components/composites/FileQueue/FileQueue.tsx +161 -0
  69. package/components/composites/FileQueue/FileStatusBadge.tsx +74 -0
  70. package/components/composites/FileQueue/index.ts +24 -0
  71. package/components/composites/InteractiveChart/InteractiveChart.stories.tsx +49 -0
  72. package/components/composites/InteractiveChart/InteractiveChart.tsx +69 -0
  73. package/components/composites/InteractiveChart/index.ts +2 -0
  74. package/components/composites/ModeToggle/ModeToggle.stories.tsx +212 -0
  75. package/components/composites/ModeToggle/ModeToggle.tsx +100 -0
  76. package/components/composites/ModeToggle/index.ts +7 -0
  77. package/components/composites/NavUser/NavUser.stories.tsx +50 -0
  78. package/components/composites/NavUser/NavUser.tsx +60 -0
  79. package/components/composites/NavUser/index.ts +2 -0
  80. package/components/composites/NavigationList/NavigationList.stories.tsx +46 -0
  81. package/components/composites/NavigationList/NavigationList.tsx +46 -0
  82. package/components/composites/NavigationList/index.ts +2 -0
  83. package/components/composites/OrchestratorMessage/OrchestratorMessage.stories.tsx +188 -0
  84. package/components/composites/OrchestratorMessage/OrchestratorMessage.tsx +72 -0
  85. package/components/composites/OrchestratorMessage/index.ts +8 -0
  86. package/components/composites/PageContainer/PageContainer.stories.tsx +41 -0
  87. package/components/composites/PageContainer/PageContainer.tsx +24 -0
  88. package/components/composites/PageContainer/index.ts +2 -0
  89. package/components/composites/PromptInput/PromptInput.stories.tsx +200 -0
  90. package/components/composites/PromptInput/PromptInput.tsx +129 -0
  91. package/components/composites/PromptInput/index.ts +8 -0
  92. package/components/composites/SpecialistMessage/SpecialistMessage.stories.tsx +286 -0
  93. package/components/composites/SpecialistMessage/SpecialistMessage.tsx +107 -0
  94. package/components/composites/SpecialistMessage/index.ts +8 -0
  95. package/components/composites/StatsCard/StatsCard.stories.tsx +76 -0
  96. package/components/composites/StatsCard/StatsCard.tsx +81 -0
  97. package/components/composites/StatsCard/index.ts +2 -0
  98. package/components/composites/TablePagination/TablePagination.stories.tsx +38 -0
  99. package/components/composites/TablePagination/TablePagination.tsx +119 -0
  100. package/components/composites/TablePagination/index.ts +2 -0
  101. package/components/composites/TableToolbar/TableToolbar.stories.tsx +60 -0
  102. package/components/composites/TableToolbar/TableToolbar.tsx +66 -0
  103. package/components/composites/TableToolbar/index.ts +2 -0
  104. package/components/composites/ThemeSelector/ThemeSelector.stories.tsx +48 -0
  105. package/components/composites/ThemeSelector/ThemeSelector.tsx +79 -0
  106. package/components/composites/ThemeSelector/index.ts +2 -0
  107. package/components/composites/ToolCallDisplay/ToolCallDisplay.stories.tsx +49 -0
  108. package/components/composites/ToolCallDisplay/ToolCallDisplay.tsx +108 -0
  109. package/components/composites/ToolCallDisplay/index.ts +8 -0
  110. package/components/composites/UserMessage/UserMessage.stories.tsx +59 -0
  111. package/components/composites/UserMessage/UserMessage.tsx +52 -0
  112. package/components/composites/UserMessage/index.ts +8 -0
  113. package/components/composites/index.ts +90 -0
  114. package/components/features/AIDocEditor/AIDocEditor.behaviors.stories.tsx +451 -0
  115. package/components/features/AIDocEditor/AIDocEditor.mocks.ts +96 -0
  116. package/components/features/AIDocEditor/AIDocEditor.stories.tsx +140 -0
  117. package/components/features/AIDocEditor/AIDocEditor.tsx +130 -0
  118. package/components/features/AIDocEditor/index.ts +8 -0
  119. package/components/features/AIDocEditor/useAIDocEditor.d.ts +97 -0
  120. package/components/features/AIDocEditor/useAIDocEditor.mock.ts +83 -0
  121. package/components/features/PageLayout/PageLayout.behaviors.stories.tsx +119 -0
  122. package/components/features/PageLayout/PageLayout.mocks.ts +27 -0
  123. package/components/features/PageLayout/PageLayout.stories.tsx +142 -0
  124. package/components/features/PageLayout/PageLayout.tsx +94 -0
  125. package/components/features/PageLayout/index.ts +4 -0
  126. package/components/features/PageLayout/usePageLayout.d.ts +24 -0
  127. package/components/features/PageLayout/usePageLayout.mock.ts +19 -0
  128. package/components/features/RefinementPanel/README.md +189 -0
  129. package/components/features/RefinementPanel/RefinementPanel.behaviors.stories.tsx +475 -0
  130. package/components/features/RefinementPanel/RefinementPanel.mocks.ts +131 -0
  131. package/components/features/RefinementPanel/RefinementPanel.stories.tsx +141 -0
  132. package/components/features/RefinementPanel/RefinementPanel.tsx +160 -0
  133. package/components/features/RefinementPanel/index.ts +25 -0
  134. package/components/features/RefinementPanel/useRefinementPanel.d.ts +74 -0
  135. package/components/features/RefinementPanel/useRefinementPanel.mock.ts +121 -0
  136. package/components/features/SpecNavigator/SpecNavigator.behaviors.stories.tsx +379 -0
  137. package/components/features/SpecNavigator/SpecNavigator.mocks.ts +131 -0
  138. package/components/features/SpecNavigator/SpecNavigator.stories.tsx +122 -0
  139. package/components/features/SpecNavigator/SpecNavigator.tsx +43 -0
  140. package/components/features/SpecNavigator/index.ts +2 -0
  141. package/components/features/SpecNavigator/useSpecNavigator.d.ts +122 -0
  142. package/components/features/SpecNavigator/useSpecNavigator.mock.ts +93 -0
  143. package/components/features/index.ts +18 -0
  144. package/components/index.ts +14 -0
  145. package/components/primitives/Accordion/Accordion.stories.tsx +87 -0
  146. package/components/primitives/Accordion/Accordion.tsx +66 -0
  147. package/components/primitives/Accordion/index.ts +13 -0
  148. package/components/primitives/Alert/Alert.stories.tsx +422 -0
  149. package/components/primitives/Alert/Alert.tsx +61 -0
  150. package/components/primitives/Alert/index.ts +8 -0
  151. package/components/primitives/AlertDialog/AlertDialog.stories.tsx +367 -0
  152. package/components/primitives/AlertDialog/AlertDialog.tsx +182 -0
  153. package/components/primitives/AlertDialog/index.ts +25 -0
  154. package/components/primitives/Avatar/Avatar.stories.tsx +321 -0
  155. package/components/primitives/Avatar/Avatar.tsx +63 -0
  156. package/components/primitives/Avatar/index.ts +8 -0
  157. package/components/primitives/Badge/Badge.stories.tsx +74 -0
  158. package/components/primitives/Badge/Badge.tsx +49 -0
  159. package/components/primitives/Badge/index.ts +2 -0
  160. package/components/primitives/Button/Button.stories.tsx +445 -0
  161. package/components/primitives/Button/Button.tsx +89 -0
  162. package/components/primitives/Button/index.ts +7 -0
  163. package/components/primitives/Card/Card.stories.tsx +831 -0
  164. package/components/primitives/Card/Card.tsx +242 -0
  165. package/components/primitives/Card/index.ts +30 -0
  166. package/components/primitives/Carousel/Carousel.stories.tsx +32 -0
  167. package/components/primitives/Carousel/Carousel.tsx +63 -0
  168. package/components/primitives/Carousel/index.ts +13 -0
  169. package/components/primitives/Chart/Chart.stories.tsx +346 -0
  170. package/components/primitives/Chart/Chart.tsx +117 -0
  171. package/components/primitives/Chart/index.ts +20 -0
  172. package/components/primitives/Checkbox/Checkbox.stories.tsx +87 -0
  173. package/components/primitives/Checkbox/Checkbox.tsx +38 -0
  174. package/components/primitives/Checkbox/index.ts +2 -0
  175. package/components/primitives/Collapsible/Collapsible.stories.tsx +38 -0
  176. package/components/primitives/Collapsible/Collapsible.tsx +39 -0
  177. package/components/primitives/Collapsible/index.ts +8 -0
  178. package/components/primitives/Command/Command.stories.tsx +150 -0
  179. package/components/primitives/Command/Command.tsx +147 -0
  180. package/components/primitives/Command/index.ts +20 -0
  181. package/components/primitives/Dialog/Dialog.stories.tsx +390 -0
  182. package/components/primitives/Dialog/Dialog.tsx +140 -0
  183. package/components/primitives/Dialog/index.ts +22 -0
  184. package/components/primitives/Drawer/Drawer.stories.tsx +327 -0
  185. package/components/primitives/Drawer/Drawer.tsx +208 -0
  186. package/components/primitives/Drawer/index.ts +27 -0
  187. package/components/primitives/DropdownMenu/DropdownMenu.stories.tsx +150 -0
  188. package/components/primitives/DropdownMenu/DropdownMenu.tsx +73 -0
  189. package/components/primitives/DropdownMenu/index.ts +1 -0
  190. package/components/primitives/HoverCard/HoverCard.stories.tsx +26 -0
  191. package/components/primitives/HoverCard/HoverCard.tsx +39 -0
  192. package/components/primitives/HoverCard/index.ts +8 -0
  193. package/components/primitives/Icon/Icon.stories.tsx +281 -0
  194. package/components/primitives/Icon/Icon.tsx +87 -0
  195. package/components/primitives/Icon/index.ts +8 -0
  196. package/components/primitives/Input/Input.stories.tsx +370 -0
  197. package/components/primitives/Input/Input.tsx +88 -0
  198. package/components/primitives/Input/index.ts +7 -0
  199. package/components/primitives/InputGroup/InputGroup.stories.tsx +40 -0
  200. package/components/primitives/InputGroup/InputGroup.tsx +72 -0
  201. package/components/primitives/InputGroup/index.ts +14 -0
  202. package/components/primitives/Label/Label.stories.tsx +227 -0
  203. package/components/primitives/Label/Label.tsx +53 -0
  204. package/components/primitives/Label/index.ts +7 -0
  205. package/components/primitives/Popover/Popover.stories.tsx +42 -0
  206. package/components/primitives/Popover/Popover.tsx +107 -0
  207. package/components/primitives/Popover/index.ts +2 -0
  208. package/components/primitives/Progress/Progress.stories.tsx +340 -0
  209. package/components/primitives/Progress/Progress.tsx +31 -0
  210. package/components/primitives/Progress/index.ts +1 -0
  211. package/components/primitives/ScrollArea/ScrollArea.stories.tsx +26 -0
  212. package/components/primitives/ScrollArea/ScrollArea.tsx +28 -0
  213. package/components/primitives/ScrollArea/index.ts +6 -0
  214. package/components/primitives/Select/Select.stories.tsx +288 -0
  215. package/components/primitives/Select/Select.tsx +162 -0
  216. package/components/primitives/Select/index.ts +22 -0
  217. package/components/primitives/Separator/Separator.stories.tsx +264 -0
  218. package/components/primitives/Separator/Separator.tsx +48 -0
  219. package/components/primitives/Separator/index.ts +7 -0
  220. package/components/primitives/Sidebar/Sidebar.stories.tsx +358 -0
  221. package/components/primitives/Sidebar/Sidebar.tsx +317 -0
  222. package/components/primitives/Sidebar/index.ts +41 -0
  223. package/components/primitives/Table/Table.stories.tsx +389 -0
  224. package/components/primitives/Table/Table.tsx +191 -0
  225. package/components/primitives/Table/index.ts +26 -0
  226. package/components/primitives/Tabs/Tabs.stories.tsx +129 -0
  227. package/components/primitives/Tabs/Tabs.tsx +70 -0
  228. package/components/primitives/Tabs/index.ts +13 -0
  229. package/components/primitives/Textarea/Textarea.stories.tsx +358 -0
  230. package/components/primitives/Textarea/Textarea.tsx +91 -0
  231. package/components/primitives/Textarea/index.ts +7 -0
  232. package/components/primitives/ToggleGroup/ToggleGroup.stories.tsx +87 -0
  233. package/components/primitives/ToggleGroup/ToggleGroup.tsx +52 -0
  234. package/components/primitives/ToggleGroup/index.ts +6 -0
  235. package/components/primitives/Tooltip/Tooltip.stories.tsx +336 -0
  236. package/components/primitives/Tooltip/Tooltip.tsx +78 -0
  237. package/components/primitives/Tooltip/index.ts +10 -0
  238. package/components/primitives/index.ts +34 -0
  239. package/components/ui/accordion.tsx +66 -0
  240. package/components/ui/alert-dialog.tsx +157 -0
  241. package/components/ui/alert.tsx +66 -0
  242. package/components/ui/avatar.tsx +53 -0
  243. package/components/ui/badge.tsx +46 -0
  244. package/components/ui/button.tsx +60 -0
  245. package/components/ui/card.tsx +117 -0
  246. package/components/ui/carousel.tsx +241 -0
  247. package/components/ui/chart.tsx +334 -0
  248. package/components/ui/checkbox.tsx +32 -0
  249. package/components/ui/collapsible.tsx +33 -0
  250. package/components/ui/command.tsx +184 -0
  251. package/components/ui/dialog.tsx +143 -0
  252. package/components/ui/drawer.tsx +118 -0
  253. package/components/ui/dropdown-menu.tsx +257 -0
  254. package/components/ui/hover-card.tsx +44 -0
  255. package/components/ui/input-group.tsx +170 -0
  256. package/components/ui/input.tsx +48 -0
  257. package/components/ui/label.tsx +26 -0
  258. package/components/ui/popover.tsx +33 -0
  259. package/components/ui/progress.tsx +31 -0
  260. package/components/ui/scroll-area.tsx +58 -0
  261. package/components/ui/select.tsx +187 -0
  262. package/components/ui/separator.tsx +31 -0
  263. package/components/ui/sidebar.tsx +577 -0
  264. package/components/ui/table.tsx +120 -0
  265. package/components/ui/tabs.tsx +66 -0
  266. package/components/ui/textarea.tsx +46 -0
  267. package/components/ui/toggle-group.tsx +83 -0
  268. package/components/ui/toggle.tsx +47 -0
  269. package/components/ui/tooltip.tsx +61 -0
  270. package/dist/index.cjs +7389 -0
  271. package/dist/index.cjs.map +1 -0
  272. package/dist/index.css +75 -0
  273. package/dist/index.css.map +1 -0
  274. package/dist/index.js +7160 -0
  275. package/dist/index.js.map +1 -0
  276. package/hooks/useAIDocReviewer.d.ts +0 -0
  277. package/lib/utils.ts +6 -0
  278. package/package.json +140 -0
  279. package/tokens/color/base.json +14 -0
  280. package/tokens/color/dark.json +40 -0
  281. package/tokens/color/green.json +21 -0
  282. package/tokens/color/light.json +52 -0
  283. package/tokens/color/neutral.json +20 -0
  284. package/tokens/color/violet.json +21 -0
  285. package/tokens/spacing.json +22 -0
  286. package/utils/ai-editor/format-date.ts +41 -0
  287. package/utils/ai-editor/index.ts +22 -0
  288. package/utils/ai-editor/type-guards.ts +72 -0
  289. package/utils/ai-editor/validation.ts +130 -0
  290. package/utils/editor-annotations.ts +122 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * FileQueue Block
3
+ *
4
+ * Central export point for the FileQueue block component and its related types.
5
+ */
6
+ export { FileQueue } from "./FileQueue";
7
+ export type { FileQueueProps, FileGroup, FileItem } from "./FileQueue";
8
+
9
+ // Legacy exports for backward compatibility (used by RefinementPanel)
10
+ export { FileStatusBadge } from "./FileStatusBadge";
11
+ export type { FileStatusBadgeProps, FileStatus } from "./FileStatusBadge";
12
+
13
+ import type { FileStatus } from "./FileStatusBadge";
14
+
15
+ /**
16
+ * Legacy FileChangeData type for backward compatibility
17
+ * @deprecated Use FileGroup and FileItem instead
18
+ */
19
+ export interface FileChangeData {
20
+ id: string;
21
+ filename: string;
22
+ status: FileStatus;
23
+ path: string;
24
+ }
@@ -0,0 +1,49 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { InteractiveChart } from './InteractiveChart'
3
+ import { AreaChart, Area, XAxis, CartesianGrid } from 'recharts'
4
+ import type { ChartConfig } from '@/components/primitives/Chart'
5
+
6
+ const meta = {
7
+ title: 'Composites/InteractiveChart',
8
+ component: InteractiveChart,
9
+ tags: ['autodocs'],
10
+ parameters: { layout: 'padded' },
11
+ } satisfies Meta<typeof InteractiveChart>
12
+
13
+ export default meta
14
+ type Story = StoryObj<typeof meta>
15
+
16
+ const chartData = [
17
+ { month: 'Jan', desktop: 186 },
18
+ { month: 'Feb', desktop: 305 },
19
+ { month: 'Mar', desktop: 237 },
20
+ { month: 'Apr', desktop: 73 },
21
+ { month: 'May', desktop: 209 },
22
+ { month: 'Jun', desktop: 214 },
23
+ ]
24
+
25
+ const chartConfig = {
26
+ desktop: { label: 'Desktop', color: 'hsl(var(--chart-1))' },
27
+ } satisfies ChartConfig
28
+
29
+ export const Default: Story = {
30
+ args: {
31
+ title: 'Area Chart',
32
+ description: 'Showing total visitors for the last 6 months',
33
+ data: chartData,
34
+ config: chartConfig,
35
+ timeRanges: [
36
+ { label: '7D', value: '7d' },
37
+ { label: '30D', value: '30d' },
38
+ { label: '90D', value: '90d' },
39
+ ],
40
+ defaultTimeRange: '30d',
41
+ children: (
42
+ <AreaChart data={chartData}>
43
+ <CartesianGrid vertical={false} />
44
+ <XAxis dataKey="month" tickLine={false} axisLine={false} tickMargin={8} />
45
+ <Area dataKey="desktop" type="monotone" fill="var(--color-desktop)" fillOpacity={0.4} stroke="var(--color-desktop)" />
46
+ </AreaChart>
47
+ ),
48
+ },
49
+ }
@@ -0,0 +1,69 @@
1
+ import * as React from "react"
2
+ import { ChartContainer, ChartConfig } from "@/components/primitives/Chart"
3
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/primitives/Card"
4
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/primitives/Select"
5
+ import { ToggleGroup, ToggleGroupItem } from "@/components/primitives/ToggleGroup"
6
+
7
+ export interface InteractiveChartProps {
8
+ title: string
9
+ description?: string
10
+ data: any[]
11
+ config: ChartConfig
12
+ timeRanges?: { label: string; value: string }[]
13
+ defaultTimeRange?: string
14
+ children: React.ReactNode
15
+ className?: string
16
+ }
17
+
18
+ export const InteractiveChart = React.memo<InteractiveChartProps>(
19
+ ({ title, description, data, config, timeRanges, defaultTimeRange, children, className }) => {
20
+ const [timeRange, setTimeRange] = React.useState(defaultTimeRange || timeRanges?.[0]?.value)
21
+
22
+ return (
23
+ <Card className={className}>
24
+ <CardHeader>
25
+ <div className="flex items-center justify-between">
26
+ <div>
27
+ <CardTitle>{title}</CardTitle>
28
+ {description && <CardDescription>{description}</CardDescription>}
29
+ </div>
30
+ {timeRanges && timeRanges.length > 0 && (
31
+ <div className="flex items-center gap-2">
32
+ <div className="hidden sm:block">
33
+ <ToggleGroup type="single" value={timeRange} onValueChange={setTimeRange}>
34
+ {timeRanges.map((range) => (
35
+ <ToggleGroupItem key={range.value} value={range.value} size="sm">
36
+ {range.label}
37
+ </ToggleGroupItem>
38
+ ))}
39
+ </ToggleGroup>
40
+ </div>
41
+ <div className="sm:hidden">
42
+ <Select value={timeRange} onValueChange={setTimeRange}>
43
+ <SelectTrigger className="w-[120px]">
44
+ <SelectValue />
45
+ </SelectTrigger>
46
+ <SelectContent>
47
+ {timeRanges.map((range) => (
48
+ <SelectItem key={range.value} value={range.value}>
49
+ {range.label}
50
+ </SelectItem>
51
+ ))}
52
+ </SelectContent>
53
+ </Select>
54
+ </div>
55
+ </div>
56
+ )}
57
+ </div>
58
+ </CardHeader>
59
+ <CardContent>
60
+ <ChartContainer config={config} className="h-[300px] w-full">
61
+ {children}
62
+ </ChartContainer>
63
+ </CardContent>
64
+ </Card>
65
+ )
66
+ }
67
+ )
68
+
69
+ InteractiveChart.displayName = "InteractiveChart"
@@ -0,0 +1,2 @@
1
+ export { InteractiveChart } from './InteractiveChart'
2
+ export type { InteractiveChartProps } from './InteractiveChart'
@@ -0,0 +1,212 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { ModeToggle } from './ModeToggle'
3
+
4
+ /**
5
+ * ModeToggle Composite Stories
6
+ *
7
+ * The ModeToggle component is a composite that allows users to switch between light, dark, and system themes.
8
+ * It composes Button and DropdownMenu primitives.
9
+ *
10
+ * ## Features
11
+ * - Light, dark, and system theme modes
12
+ * - Persistent theme preference via localStorage
13
+ * - Automatic system theme detection
14
+ * - Accessible dropdown menu
15
+ * - Icon-based toggle button
16
+ *
17
+ * ## Accessibility
18
+ * - Keyboard navigation support
19
+ * - Screen reader labels
20
+ * - Focus management
21
+ * - ARIA attributes
22
+ *
23
+ * ## Usage Guidelines
24
+ *
25
+ * ### Do's
26
+ * - Place in application header or settings
27
+ * - Use consistent placement across pages
28
+ * - Provide visual feedback for current theme
29
+ *
30
+ * ### Don'ts
31
+ * - Don't place multiple theme toggles
32
+ * - Don't override user's system preference without consent
33
+ * - Don't hide the toggle in nested menus
34
+ */
35
+ const meta = {
36
+ title: 'Composites/ModeToggle',
37
+ component: ModeToggle,
38
+ tags: ['autodocs'],
39
+ parameters: {
40
+ layout: 'centered',
41
+ docs: {
42
+ description: {
43
+ component: 'A theme mode switcher component that composes Button and DropdownMenu primitives.',
44
+ },
45
+ },
46
+ },
47
+ } satisfies Meta<typeof ModeToggle>
48
+
49
+ export default meta
50
+ type Story = StoryObj<typeof meta>
51
+
52
+ /**
53
+ * Default mode toggle
54
+ *
55
+ * Basic theme switcher with light, dark, and system options.
56
+ */
57
+ export const Default: Story = {
58
+ render: () => <ModeToggle />,
59
+ }
60
+
61
+ /**
62
+ * In Header
63
+ *
64
+ * Mode toggle as it would appear in an application header.
65
+ */
66
+ export const InHeader: Story = {
67
+ render: () => (
68
+ <div
69
+ style={{
70
+ display: 'flex',
71
+ alignItems: 'center',
72
+ justifyContent: 'space-between',
73
+ padding: '16px',
74
+ borderBottom: '1px solid hsl(var(--border))',
75
+ width: '600px',
76
+ }}
77
+ >
78
+ <div style={{ fontWeight: 600, fontSize: '18px' }}>My Application</div>
79
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
80
+ <span style={{ fontSize: '14px', color: 'hsl(var(--muted-foreground))' }}>Settings</span>
81
+ <ModeToggle />
82
+ </div>
83
+ </div>
84
+ ),
85
+ parameters: {
86
+ docs: {
87
+ description: {
88
+ story: 'Common placement of the mode toggle in an application header.',
89
+ },
90
+ },
91
+ },
92
+ }
93
+
94
+ /**
95
+ * With Navigation
96
+ *
97
+ * Mode toggle alongside other navigation items.
98
+ */
99
+ export const WithNavigation: Story = {
100
+ render: () => (
101
+ <div
102
+ style={{
103
+ display: 'flex',
104
+ alignItems: 'center',
105
+ gap: '16px',
106
+ padding: '16px',
107
+ borderBottom: '1px solid hsl(var(--border))',
108
+ }}
109
+ >
110
+ <div style={{ fontWeight: 600, fontSize: '18px', marginRight: 'auto' }}>Logo</div>
111
+ <a href="#" style={{ fontSize: '14px', textDecoration: 'none', color: 'hsl(var(--foreground))' }}>
112
+ Home
113
+ </a>
114
+ <a href="#" style={{ fontSize: '14px', textDecoration: 'none', color: 'hsl(var(--foreground))' }}>
115
+ About
116
+ </a>
117
+ <a href="#" style={{ fontSize: '14px', textDecoration: 'none', color: 'hsl(var(--foreground))' }}>
118
+ Contact
119
+ </a>
120
+ <ModeToggle />
121
+ </div>
122
+ ),
123
+ parameters: {
124
+ docs: {
125
+ description: {
126
+ story: 'Mode toggle integrated with navigation menu.',
127
+ },
128
+ },
129
+ },
130
+ }
131
+
132
+ /**
133
+ * Light Theme Preview
134
+ *
135
+ * Mode toggle in light theme context.
136
+ */
137
+ export const LightTheme: Story = {
138
+ render: () => (
139
+ <div className="light" style={{ padding: '24px', background: 'hsl(0 0% 100%)', borderRadius: '8px' }}>
140
+ <div style={{ marginBottom: '16px', color: 'hsl(222.2 47.4% 11.2%)' }}>
141
+ <p style={{ marginBottom: '8px' }}>Current theme: Light</p>
142
+ <ModeToggle />
143
+ </div>
144
+ </div>
145
+ ),
146
+ parameters: {
147
+ docs: {
148
+ description: {
149
+ story: 'Mode toggle appearance in light theme.',
150
+ },
151
+ },
152
+ backgrounds: { disable: true },
153
+ },
154
+ }
155
+
156
+ /**
157
+ * Dark Theme Preview
158
+ *
159
+ * Mode toggle in dark theme context.
160
+ */
161
+ export const DarkTheme: Story = {
162
+ render: () => (
163
+ <div className="dark" style={{ padding: '24px', background: 'hsl(222.2 84% 4.9%)', borderRadius: '8px' }}>
164
+ <div style={{ marginBottom: '16px', color: 'hsl(210 40% 98%)' }}>
165
+ <p style={{ marginBottom: '8px' }}>Current theme: Dark</p>
166
+ <ModeToggle />
167
+ </div>
168
+ </div>
169
+ ),
170
+ parameters: {
171
+ docs: {
172
+ description: {
173
+ story: 'Mode toggle appearance in dark theme.',
174
+ },
175
+ },
176
+ backgrounds: { disable: true },
177
+ },
178
+ }
179
+
180
+ /**
181
+ * Interactive Demo
182
+ *
183
+ * Try switching themes to see the effect.
184
+ */
185
+ export const InteractiveDemo: Story = {
186
+ render: () => (
187
+ <div style={{ padding: '24px', border: '1px solid hsl(var(--border))', borderRadius: '8px', minWidth: '400px' }}>
188
+ <div style={{ marginBottom: '16px' }}>
189
+ <h3 style={{ fontSize: '16px', fontWeight: 600, marginBottom: '8px' }}>Theme Switcher Demo</h3>
190
+ <p style={{ fontSize: '14px', color: 'hsl(var(--muted-foreground))', marginBottom: '16px' }}>
191
+ Click the button below to switch between light, dark, and system themes.
192
+ </p>
193
+ </div>
194
+ <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
195
+ <span style={{ fontSize: '14px' }}>Theme:</span>
196
+ <ModeToggle />
197
+ </div>
198
+ <div style={{ marginTop: '24px', padding: '16px', background: 'hsl(var(--muted))', borderRadius: '6px' }}>
199
+ <p style={{ fontSize: '14px' }}>
200
+ This content will adapt to the selected theme. The theme preference is saved to localStorage.
201
+ </p>
202
+ </div>
203
+ </div>
204
+ ),
205
+ parameters: {
206
+ docs: {
207
+ description: {
208
+ story: 'Interactive demo showing theme switching in action.',
209
+ },
210
+ },
211
+ },
212
+ }
@@ -0,0 +1,100 @@
1
+ import * as React from "react"
2
+ import { Button } from "@/components/primitives/Button"
3
+ import {
4
+ DropdownMenu,
5
+ DropdownMenuContent,
6
+ DropdownMenuItem,
7
+ DropdownMenuTrigger,
8
+ } from "@/components/primitives/DropdownMenu"
9
+ import { Icon } from "@/components/primitives/Icon"
10
+
11
+ /**
12
+ * ModeToggle Composite
13
+ *
14
+ * A theme mode switcher component that allows users to toggle between light, dark, and system themes.
15
+ * Composes Button and DropdownMenu primitives.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <ModeToggle />
20
+ * ```
21
+ */
22
+
23
+ export interface ModeToggleProps {
24
+ /**
25
+ * Additional CSS classes
26
+ */
27
+ className?: string
28
+ }
29
+
30
+ /**
31
+ * ModeToggle component
32
+ *
33
+ * Provides a dropdown menu to switch between light, dark, and system theme modes.
34
+ * Uses local storage to persist the user's theme preference.
35
+ */
36
+ export const ModeToggle = React.memo<ModeToggleProps>(({ className }) => {
37
+ const [theme, setThemeState] = React.useState<"light" | "dark" | "system">("system")
38
+
39
+ React.useEffect(() => {
40
+ // Load theme from localStorage on mount
41
+ const stored = localStorage.getItem("theme") as "light" | "dark" | "system" | null
42
+ if (stored) {
43
+ setThemeState(stored)
44
+ }
45
+ }, [])
46
+
47
+ React.useEffect(() => {
48
+ // Apply theme to document
49
+ const root = window.document.documentElement
50
+ root.classList.remove("light", "dark")
51
+
52
+ if (theme === "system") {
53
+ const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
54
+ ? "dark"
55
+ : "light"
56
+ root.classList.add(systemTheme)
57
+ } else {
58
+ root.classList.add(theme)
59
+ }
60
+ }, [theme])
61
+
62
+ const setTheme = (newTheme: "light" | "dark" | "system") => {
63
+ localStorage.setItem("theme", newTheme)
64
+ setThemeState(newTheme)
65
+ }
66
+
67
+ return (
68
+ <DropdownMenu>
69
+ <DropdownMenuTrigger asChild>
70
+ <Button variant="ghost" size="icon" className={className}>
71
+ <Icon
72
+ name="sun"
73
+ className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
74
+ />
75
+ <Icon
76
+ name="moon"
77
+ className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
78
+ />
79
+ <span className="sr-only">Toggle theme</span>
80
+ </Button>
81
+ </DropdownMenuTrigger>
82
+ <DropdownMenuContent align="end">
83
+ <DropdownMenuItem onClick={() => setTheme("light")}>
84
+ <Icon name="sun" className="mr-2 h-4 w-4" />
85
+ <span>Light</span>
86
+ </DropdownMenuItem>
87
+ <DropdownMenuItem onClick={() => setTheme("dark")}>
88
+ <Icon name="moon" className="mr-2 h-4 w-4" />
89
+ <span>Dark</span>
90
+ </DropdownMenuItem>
91
+ <DropdownMenuItem onClick={() => setTheme("system")}>
92
+ <Icon name="laptop" className="mr-2 h-4 w-4" />
93
+ <span>System</span>
94
+ </DropdownMenuItem>
95
+ </DropdownMenuContent>
96
+ </DropdownMenu>
97
+ )
98
+ })
99
+
100
+ ModeToggle.displayName = "ModeToggle"
@@ -0,0 +1,7 @@
1
+ /**
2
+ * ModeToggle Composite
3
+ *
4
+ * Central export point for the ModeToggle composite component.
5
+ */
6
+ export { ModeToggle } from './ModeToggle'
7
+ export type { ModeToggleProps } from './ModeToggle'
@@ -0,0 +1,50 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { NavUser } from './NavUser'
3
+ import { SidebarProvider, Sidebar, SidebarFooter } from '@/components/primitives/Sidebar'
4
+
5
+ const meta = {
6
+ title: 'Composites/NavUser',
7
+ component: NavUser,
8
+ tags: ['autodocs'],
9
+ parameters: { layout: 'padded' },
10
+ } satisfies Meta<typeof NavUser>
11
+
12
+ export default meta
13
+ type Story = StoryObj<typeof meta>
14
+
15
+ const user = {
16
+ name: 'John Doe',
17
+ email: 'john@example.com',
18
+ avatar: 'https://github.com/shadcn.png',
19
+ }
20
+
21
+ export const Default: Story = {
22
+ render: () => (
23
+ <SidebarProvider>
24
+ <Sidebar>
25
+ <SidebarFooter>
26
+ <NavUser user={user} />
27
+ </SidebarFooter>
28
+ </Sidebar>
29
+ </SidebarProvider>
30
+ ),
31
+ }
32
+
33
+ export const WithActions: Story = {
34
+ render: () => (
35
+ <SidebarProvider>
36
+ <Sidebar>
37
+ <SidebarFooter>
38
+ <NavUser
39
+ user={user}
40
+ actions={[
41
+ { label: 'Profile', onClick: () => console.log('Profile') },
42
+ { label: 'Settings', onClick: () => console.log('Settings') },
43
+ { label: 'Logout', onClick: () => console.log('Logout') },
44
+ ]}
45
+ />
46
+ </SidebarFooter>
47
+ </Sidebar>
48
+ </SidebarProvider>
49
+ ),
50
+ }
@@ -0,0 +1,60 @@
1
+ import * as React from "react"
2
+ import {
3
+ SidebarMenu,
4
+ SidebarMenuItem,
5
+ SidebarMenuButton,
6
+ } from "@/components/primitives/Sidebar"
7
+ import { Avatar, AvatarImage, AvatarFallback } from "@/components/primitives/Avatar"
8
+ import {
9
+ DropdownMenu,
10
+ DropdownMenuContent,
11
+ DropdownMenuItem,
12
+ DropdownMenuTrigger,
13
+ } from "@/components/primitives/DropdownMenu"
14
+
15
+ export interface NavUserProps {
16
+ user: {
17
+ name: string
18
+ email: string
19
+ avatar?: string
20
+ }
21
+ actions?: { label: string; onClick: () => void }[]
22
+ className?: string
23
+ }
24
+
25
+ export const NavUser = React.memo<NavUserProps>(({ user, actions, className }) => {
26
+ return (
27
+ <SidebarMenu className={className}>
28
+ <SidebarMenuItem>
29
+ <DropdownMenu>
30
+ <DropdownMenuTrigger asChild>
31
+ <SidebarMenuButton
32
+ size="lg"
33
+ className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
34
+ >
35
+ <Avatar className="h-8 w-8 rounded-lg">
36
+ <AvatarImage src={user.avatar} alt={user.name} />
37
+ <AvatarFallback className="rounded-lg">{user.name[0]}</AvatarFallback>
38
+ </Avatar>
39
+ <div className="grid flex-1 text-left text-sm leading-tight">
40
+ <span className="truncate font-medium">{user.name}</span>
41
+ <span className="truncate text-xs text-muted-foreground">{user.email}</span>
42
+ </div>
43
+ </SidebarMenuButton>
44
+ </DropdownMenuTrigger>
45
+ {actions && actions.length > 0 && (
46
+ <DropdownMenuContent align="end" className="w-56">
47
+ {actions.map((action) => (
48
+ <DropdownMenuItem key={action.label} onClick={action.onClick}>
49
+ {action.label}
50
+ </DropdownMenuItem>
51
+ ))}
52
+ </DropdownMenuContent>
53
+ )}
54
+ </DropdownMenu>
55
+ </SidebarMenuItem>
56
+ </SidebarMenu>
57
+ )
58
+ })
59
+
60
+ NavUser.displayName = "NavUser"
@@ -0,0 +1,2 @@
1
+ export { NavUser } from './NavUser'
2
+ export type { NavUserProps } from './NavUser'
@@ -0,0 +1,46 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { NavigationList } from './NavigationList'
3
+ import { SidebarProvider, Sidebar, SidebarContent } from '@/components/primitives/Sidebar'
4
+
5
+ const meta = {
6
+ title: 'Composites/NavigationList',
7
+ component: NavigationList,
8
+ tags: ['autodocs'],
9
+ parameters: { layout: 'padded' },
10
+ } satisfies Meta<typeof NavigationList>
11
+
12
+ export default meta
13
+ type Story = StoryObj<typeof meta>
14
+
15
+ const items = [
16
+ { title: 'Dashboard', url: '#', icon: 'layout-dashboard' },
17
+ { title: 'Projects', url: '#', icon: 'folder' },
18
+ { title: 'Tasks', url: '#', icon: 'check-square' },
19
+ { title: 'Settings', url: '#', icon: 'settings' },
20
+ ]
21
+
22
+ export const Default: Story = {
23
+ render: () => (
24
+ <SidebarProvider>
25
+ <Sidebar>
26
+ <SidebarContent>
27
+ <NavigationList items={items} />
28
+ </SidebarContent>
29
+ </Sidebar>
30
+ </SidebarProvider>
31
+ ),
32
+ }
33
+
34
+ export const WithActiveState: Story = {
35
+ render: () => (
36
+ <SidebarProvider>
37
+ <Sidebar>
38
+ <SidebarContent>
39
+ <NavigationList
40
+ items={items.map((item, i) => ({ ...item, isActive: i === 0 }))}
41
+ />
42
+ </SidebarContent>
43
+ </Sidebar>
44
+ </SidebarProvider>
45
+ ),
46
+ }
@@ -0,0 +1,46 @@
1
+ import * as React from "react"
2
+ import {
3
+ SidebarMenu,
4
+ SidebarMenuItem,
5
+ SidebarMenuButton,
6
+ } from "@/components/primitives/Sidebar"
7
+ import { Icon } from "@/components/primitives/Icon"
8
+
9
+ export interface NavigationItem {
10
+ title: string
11
+ url: string
12
+ icon?: string
13
+ isActive?: boolean
14
+ }
15
+
16
+ export interface NavigationListProps {
17
+ items: NavigationItem[]
18
+ onItemClick?: (item: NavigationItem) => void
19
+ className?: string
20
+ }
21
+
22
+ export const NavigationList = React.memo<NavigationListProps>(
23
+ ({ items, onItemClick, className }) => {
24
+ return (
25
+ <SidebarMenu className={className}>
26
+ {items.map((item) => (
27
+ <SidebarMenuItem key={item.title}>
28
+ <SidebarMenuButton
29
+ tooltip={item.title}
30
+ isActive={item.isActive}
31
+ onClick={() => onItemClick?.(item)}
32
+ asChild
33
+ >
34
+ <a href={item.url}>
35
+ {item.icon && <Icon name={item.icon} />}
36
+ <span>{item.title}</span>
37
+ </a>
38
+ </SidebarMenuButton>
39
+ </SidebarMenuItem>
40
+ ))}
41
+ </SidebarMenu>
42
+ )
43
+ }
44
+ )
45
+
46
+ NavigationList.displayName = "NavigationList"
@@ -0,0 +1,2 @@
1
+ export { NavigationList } from './NavigationList'
2
+ export type { NavigationListProps, NavigationItem } from './NavigationList'