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,27 @@
1
+ /**
2
+ * Drawer Primitive
3
+ *
4
+ * Central export point for the Drawer primitive component and its related types.
5
+ */
6
+ export {
7
+ Drawer,
8
+ DrawerPortal,
9
+ DrawerOverlay,
10
+ DrawerTrigger,
11
+ DrawerClose,
12
+ DrawerContent,
13
+ DrawerHeader,
14
+ DrawerFooter,
15
+ DrawerTitle,
16
+ DrawerDescription,
17
+ } from './Drawer'
18
+
19
+ export type {
20
+ DrawerProps,
21
+ DrawerOverlayProps,
22
+ DrawerContentProps,
23
+ DrawerHeaderProps,
24
+ DrawerFooterProps,
25
+ DrawerTitleProps,
26
+ DrawerDescriptionProps,
27
+ } from './Drawer'
@@ -0,0 +1,150 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import {
3
+ DropdownMenu,
4
+ DropdownMenuCheckboxItem,
5
+ DropdownMenuContent,
6
+ DropdownMenuGroup,
7
+ DropdownMenuItem,
8
+ DropdownMenuLabel,
9
+ DropdownMenuRadioGroup,
10
+ DropdownMenuRadioItem,
11
+ DropdownMenuSeparator,
12
+ DropdownMenuShortcut,
13
+ DropdownMenuSub,
14
+ DropdownMenuSubContent,
15
+ DropdownMenuSubTrigger,
16
+ DropdownMenuTrigger,
17
+ } from "./DropdownMenu"
18
+ import { Button } from "../Button"
19
+ import * as React from "react"
20
+
21
+ const meta = {
22
+ title: "Primitives/DropdownMenu",
23
+ component: DropdownMenu,
24
+ parameters: {
25
+ layout: "centered",
26
+ },
27
+ tags: ["autodocs"],
28
+ } satisfies Meta<typeof DropdownMenu>
29
+
30
+ export default meta
31
+ type Story = StoryObj<typeof meta>
32
+
33
+ export const Default: Story = {
34
+ render: () => (
35
+ <DropdownMenu>
36
+ <DropdownMenuTrigger asChild>
37
+ <Button variant="outline">Open Menu</Button>
38
+ </DropdownMenuTrigger>
39
+ <DropdownMenuContent>
40
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
41
+ <DropdownMenuSeparator />
42
+ <DropdownMenuItem>Profile</DropdownMenuItem>
43
+ <DropdownMenuItem>Settings</DropdownMenuItem>
44
+ <DropdownMenuSeparator />
45
+ <DropdownMenuItem>Logout</DropdownMenuItem>
46
+ </DropdownMenuContent>
47
+ </DropdownMenu>
48
+ ),
49
+ }
50
+
51
+ export const WithShortcuts: Story = {
52
+ render: () => (
53
+ <DropdownMenu>
54
+ <DropdownMenuTrigger asChild>
55
+ <Button variant="outline">Actions</Button>
56
+ </DropdownMenuTrigger>
57
+ <DropdownMenuContent className="w-56">
58
+ <DropdownMenuLabel>Actions</DropdownMenuLabel>
59
+ <DropdownMenuSeparator />
60
+ <DropdownMenuItem>
61
+ New File
62
+ <DropdownMenuShortcut>⌘N</DropdownMenuShortcut>
63
+ </DropdownMenuItem>
64
+ <DropdownMenuItem>
65
+ Save
66
+ <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
67
+ </DropdownMenuItem>
68
+ <DropdownMenuItem>
69
+ Print
70
+ <DropdownMenuShortcut>⌘P</DropdownMenuShortcut>
71
+ </DropdownMenuItem>
72
+ </DropdownMenuContent>
73
+ </DropdownMenu>
74
+ ),
75
+ }
76
+
77
+ export const WithCheckboxes: Story = {
78
+ render: () => {
79
+ const [showPanel, setShowPanel] = React.useState(true)
80
+ const [showToolbar, setShowToolbar] = React.useState(false)
81
+
82
+ return (
83
+ <DropdownMenu>
84
+ <DropdownMenuTrigger asChild>
85
+ <Button variant="outline">View</Button>
86
+ </DropdownMenuTrigger>
87
+ <DropdownMenuContent className="w-56">
88
+ <DropdownMenuLabel>Panels</DropdownMenuLabel>
89
+ <DropdownMenuSeparator />
90
+ <DropdownMenuCheckboxItem
91
+ checked={showPanel}
92
+ onCheckedChange={setShowPanel}
93
+ >
94
+ Side Panel
95
+ </DropdownMenuCheckboxItem>
96
+ <DropdownMenuCheckboxItem
97
+ checked={showToolbar}
98
+ onCheckedChange={setShowToolbar}
99
+ >
100
+ Toolbar
101
+ </DropdownMenuCheckboxItem>
102
+ </DropdownMenuContent>
103
+ </DropdownMenu>
104
+ )
105
+ },
106
+ }
107
+
108
+ export const WithRadioGroup: Story = {
109
+ render: () => {
110
+ const [position, setPosition] = React.useState("bottom")
111
+
112
+ return (
113
+ <DropdownMenu>
114
+ <DropdownMenuTrigger asChild>
115
+ <Button variant="outline">Position</Button>
116
+ </DropdownMenuTrigger>
117
+ <DropdownMenuContent className="w-56">
118
+ <DropdownMenuLabel>Panel Position</DropdownMenuLabel>
119
+ <DropdownMenuSeparator />
120
+ <DropdownMenuRadioGroup value={position} onValueChange={setPosition}>
121
+ <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>
122
+ <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>
123
+ <DropdownMenuRadioItem value="right">Right</DropdownMenuRadioItem>
124
+ </DropdownMenuRadioGroup>
125
+ </DropdownMenuContent>
126
+ </DropdownMenu>
127
+ )
128
+ },
129
+ }
130
+
131
+ export const DarkMode: Story = {
132
+ parameters: {
133
+ backgrounds: { default: "dark" },
134
+ },
135
+ render: () => (
136
+ <div className="dark">
137
+ <DropdownMenu>
138
+ <DropdownMenuTrigger asChild>
139
+ <Button variant="outline">Open Menu</Button>
140
+ </DropdownMenuTrigger>
141
+ <DropdownMenuContent>
142
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
143
+ <DropdownMenuSeparator />
144
+ <DropdownMenuItem>Profile</DropdownMenuItem>
145
+ <DropdownMenuItem>Settings</DropdownMenuItem>
146
+ </DropdownMenuContent>
147
+ </DropdownMenu>
148
+ </div>
149
+ ),
150
+ }
@@ -0,0 +1,73 @@
1
+ import * as React from "react"
2
+ import {
3
+ DropdownMenu as ShadcnDropdownMenu,
4
+ DropdownMenuCheckboxItem,
5
+ DropdownMenuContent,
6
+ DropdownMenuGroup,
7
+ DropdownMenuItem,
8
+ DropdownMenuLabel,
9
+ DropdownMenuPortal,
10
+ DropdownMenuRadioGroup,
11
+ DropdownMenuRadioItem,
12
+ DropdownMenuSeparator,
13
+ DropdownMenuShortcut,
14
+ DropdownMenuSub,
15
+ DropdownMenuSubContent,
16
+ DropdownMenuSubTrigger,
17
+ DropdownMenuTrigger,
18
+ } from "../../ui/dropdown-menu"
19
+
20
+ /**
21
+ * DropdownMenu Primitive
22
+ *
23
+ * Displays a menu with actions or options triggered by a button.
24
+ * Built on Radix UI DropdownMenu primitive with WCAG 2.1 Level AA compliance.
25
+ *
26
+ * @see https://ui.shadcn.com/docs/components/dropdown-menu
27
+ * @see https://www.radix-ui.com/primitives/docs/components/dropdown-menu
28
+ */
29
+
30
+ export type DropdownMenuProps = React.ComponentProps<typeof ShadcnDropdownMenu>
31
+
32
+ /**
33
+ * DropdownMenu component
34
+ *
35
+ * Displays a menu with actions or options triggered by a button.
36
+ * Built on Radix UI DropdownMenu primitive with full accessibility support.
37
+ *
38
+ * Features:
39
+ * - Keyboard navigation
40
+ * - Checkbox and radio item support
41
+ * - Submenu support
42
+ * - Keyboard shortcuts display
43
+ * - ARIA attributes
44
+ * - Dark mode support
45
+ */
46
+ export const DropdownMenu = React.forwardRef<
47
+ React.ElementRef<typeof ShadcnDropdownMenu>,
48
+ DropdownMenuProps
49
+ >((props, ref) => {
50
+ return <ShadcnDropdownMenu {...props} />
51
+ })
52
+
53
+ DropdownMenu.displayName = "DropdownMenu"
54
+
55
+ /**
56
+ * Re-export DropdownMenu sub-components for composition
57
+ */
58
+ export {
59
+ DropdownMenuCheckboxItem,
60
+ DropdownMenuContent,
61
+ DropdownMenuGroup,
62
+ DropdownMenuItem,
63
+ DropdownMenuLabel,
64
+ DropdownMenuPortal,
65
+ DropdownMenuRadioGroup,
66
+ DropdownMenuRadioItem,
67
+ DropdownMenuSeparator,
68
+ DropdownMenuShortcut,
69
+ DropdownMenuSub,
70
+ DropdownMenuSubContent,
71
+ DropdownMenuSubTrigger,
72
+ DropdownMenuTrigger,
73
+ }
@@ -0,0 +1 @@
1
+ export * from "./DropdownMenu"
@@ -0,0 +1,26 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { HoverCard, HoverCardContent, HoverCardTrigger } from "./HoverCard";
3
+
4
+ const meta: Meta<typeof HoverCard> = {
5
+ title: "Primitives/HoverCard",
6
+ component: HoverCard,
7
+ parameters: { layout: "centered" },
8
+ tags: ["autodocs"],
9
+ };
10
+
11
+ export default meta;
12
+ type Story = StoryObj<typeof HoverCard>;
13
+
14
+ export const Default: Story = {
15
+ render: () => (
16
+ <HoverCard>
17
+ <HoverCardTrigger>Hover me</HoverCardTrigger>
18
+ <HoverCardContent>
19
+ <div className="space-y-2">
20
+ <h4 className="text-sm font-semibold">@username</h4>
21
+ <p className="text-sm">Additional information appears here.</p>
22
+ </div>
23
+ </HoverCardContent>
24
+ </HoverCard>
25
+ ),
26
+ };
@@ -0,0 +1,39 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import {
5
+ HoverCard as ShadcnHoverCard,
6
+ HoverCardContent as ShadcnHoverCardContent,
7
+ HoverCardTrigger as ShadcnHoverCardTrigger,
8
+ } from "@/components/ui/hover-card";
9
+
10
+ export type HoverCardProps = React.ComponentProps<typeof ShadcnHoverCard>;
11
+ export type HoverCardTriggerProps = React.ComponentProps<typeof ShadcnHoverCardTrigger>;
12
+ export type HoverCardContentProps = React.ComponentProps<typeof ShadcnHoverCardContent>;
13
+
14
+ export const HoverCard = React.memo<HoverCardProps>(
15
+ React.forwardRef<React.ElementRef<typeof ShadcnHoverCard>, HoverCardProps>(
16
+ (props, ref) => {
17
+ return <ShadcnHoverCard {...props} />;
18
+ }
19
+ )
20
+ );
21
+ HoverCard.displayName = "HoverCard";
22
+
23
+ export const HoverCardTrigger = React.memo<HoverCardTriggerProps>(
24
+ React.forwardRef<React.ElementRef<typeof ShadcnHoverCardTrigger>, HoverCardTriggerProps>(
25
+ (props, ref) => {
26
+ return <ShadcnHoverCardTrigger ref={ref} {...props} />;
27
+ }
28
+ )
29
+ );
30
+ HoverCardTrigger.displayName = "HoverCardTrigger";
31
+
32
+ export const HoverCardContent = React.memo<HoverCardContentProps>(
33
+ React.forwardRef<React.ElementRef<typeof ShadcnHoverCardContent>, HoverCardContentProps>(
34
+ (props, ref) => {
35
+ return <ShadcnHoverCardContent ref={ref} {...props} />;
36
+ }
37
+ )
38
+ );
39
+ HoverCardContent.displayName = "HoverCardContent";
@@ -0,0 +1,8 @@
1
+ export {
2
+ HoverCard,
3
+ HoverCardContent,
4
+ HoverCardTrigger,
5
+ type HoverCardProps,
6
+ type HoverCardContentProps,
7
+ type HoverCardTriggerProps,
8
+ } from "./HoverCard";
@@ -0,0 +1,281 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Icon } from "./Icon";
3
+ import { iconRegistry } from "@/registry/icons";
4
+ import { Button } from "../Button";
5
+
6
+ const meta: Meta<typeof Icon> = {
7
+ title: "Primitives/Icon",
8
+ component: Icon,
9
+ parameters: {
10
+ layout: "padded",
11
+ },
12
+ argTypes: {
13
+ name: {
14
+ control: "select",
15
+ options: iconRegistry.getNames(),
16
+ description: "Name of the icon from the registry",
17
+ },
18
+ size: {
19
+ control: "select",
20
+ options: ["xs", "sm", "default", "lg", "xl"],
21
+ description: "Size variant of the icon",
22
+ },
23
+ "aria-label": {
24
+ control: "text",
25
+ description: "Accessibility label for screen readers",
26
+ },
27
+ },
28
+ } satisfies Meta<typeof Icon>;
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof meta>;
32
+
33
+ /**
34
+ * Default icon display
35
+ */
36
+ export const Default: Story = {
37
+ args: {
38
+ name: "check",
39
+ size: "default",
40
+ },
41
+ };
42
+
43
+ /**
44
+ * Icon gallery showing all available icons
45
+ */
46
+ export const AllIcons: Story = {
47
+ render: () => {
48
+ const iconNames = iconRegistry.getNames();
49
+
50
+ return (
51
+ <div className="space-y-6">
52
+ <div>
53
+ <h3 className="mb-4 font-semibold text-lg">
54
+ All Available Icons ({iconNames.length})
55
+ </h3>
56
+ <div className="grid grid-cols-8 gap-4 md:grid-cols-12">
57
+ {iconNames.map((name) => (
58
+ <div
59
+ key={name}
60
+ className="flex flex-col items-center gap-2 rounded-md border border-border p-3 hover:bg-accent"
61
+ >
62
+ <Icon name={name} size="default" aria-label={name} />
63
+ <span className="text-center text-muted-foreground text-xs">
64
+ {name}
65
+ </span>
66
+ </div>
67
+ ))}
68
+ </div>
69
+ </div>
70
+ </div>
71
+ );
72
+ },
73
+ };
74
+
75
+ /**
76
+ * Size variants comparison
77
+ */
78
+ export const AllSizes: Story = {
79
+ render: () => (
80
+ <div className="space-y-6">
81
+ <div className="flex items-center gap-8">
82
+ <div className="flex flex-col items-center gap-2">
83
+ <Icon name="check" size="xs" />
84
+ <span className="text-muted-foreground text-xs">xs (12px)</span>
85
+ </div>
86
+ <div className="flex flex-col items-center gap-2">
87
+ <Icon name="check" size="sm" />
88
+ <span className="text-muted-foreground text-xs">sm (16px)</span>
89
+ </div>
90
+ <div className="flex flex-col items-center gap-2">
91
+ <Icon name="check" size="default" />
92
+ <span className="text-muted-foreground text-xs">default (20px)</span>
93
+ </div>
94
+ <div className="flex flex-col items-center gap-2">
95
+ <Icon name="check" size="lg" />
96
+ <span className="text-muted-foreground text-xs">lg (24px)</span>
97
+ </div>
98
+ <div className="flex flex-col items-center gap-2">
99
+ <Icon name="check" size="xl" />
100
+ <span className="text-muted-foreground text-xs">xl (32px)</span>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ ),
105
+ };
106
+
107
+ /**
108
+ * Icons with different colors (inherits from currentColor)
109
+ */
110
+ export const WithColor: Story = {
111
+ render: () => (
112
+ <div className="flex items-center gap-6">
113
+ <div className="flex flex-col items-center gap-2">
114
+ <Icon name="check-circle" size="lg" className="text-green-600" />
115
+ <span className="text-muted-foreground text-xs">Success</span>
116
+ </div>
117
+ <div className="flex flex-col items-center gap-2">
118
+ <Icon name="alert-circle" size="lg" className="text-yellow-600" />
119
+ <span className="text-muted-foreground text-xs">Warning</span>
120
+ </div>
121
+ <div className="flex flex-col items-center gap-2">
122
+ <Icon name="info" size="lg" className="text-blue-600" />
123
+ <span className="text-muted-foreground text-xs">Info</span>
124
+ </div>
125
+ <div className="flex flex-col items-center gap-2">
126
+ <Icon name="x" size="lg" className="text-red-600" />
127
+ <span className="text-muted-foreground text-xs">Error</span>
128
+ </div>
129
+ <div className="flex flex-col items-center gap-2">
130
+ <Icon name="settings" size="lg" className="text-purple-600" />
131
+ <span className="text-muted-foreground text-xs">Custom</span>
132
+ </div>
133
+ </div>
134
+ ),
135
+ };
136
+
137
+ /**
138
+ * Accessible icons with aria-label
139
+ */
140
+ export const Accessible: Story = {
141
+ render: () => (
142
+ <div className="space-y-4">
143
+ <div className="rounded-md border border-border bg-muted p-4">
144
+ <p className="mb-4 text-sm">
145
+ Icons with aria-label are announced by screen readers:
146
+ </p>
147
+ <div className="flex items-center gap-4">
148
+ <Icon name="check" size="default" aria-label="Success" />
149
+ <Icon name="x" size="default" aria-label="Error" />
150
+ <Icon name="info" size="default" aria-label="Information" />
151
+ <Icon name="warning" size="default" aria-label="Warning" />
152
+ </div>
153
+ </div>
154
+ <div className="rounded-md border border-border bg-muted p-4">
155
+ <p className="mb-4 text-sm">
156
+ Decorative icons without aria-label are hidden from screen readers:
157
+ </p>
158
+ <div className="flex items-center gap-4">
159
+ <Icon name="chevron-right" size="sm" />
160
+ <Icon name="menu" size="sm" />
161
+ <Icon name="more-horizontal" size="sm" />
162
+ </div>
163
+ </div>
164
+ </div>
165
+ ),
166
+ };
167
+
168
+ /**
169
+ * Error handling for missing icons
170
+ */
171
+ export const NotFound: Story = {
172
+ render: () => (
173
+ <div className="space-y-4">
174
+ <div className="rounded-md border border-border bg-muted p-4">
175
+ <p className="mb-4 text-sm">
176
+ Missing icons are handled gracefully (returns null and logs warning in
177
+ dev):
178
+ </p>
179
+ <div className="flex items-center gap-4">
180
+ <Icon name="check" size="default" />
181
+ <Icon name="invalid-icon-name" size="default" />
182
+ <Icon name="x" size="default" />
183
+ </div>
184
+ <p className="mt-4 text-muted-foreground text-xs">
185
+ Open browser console to see the warning for "invalid-icon-name"
186
+ </p>
187
+ </div>
188
+ </div>
189
+ ),
190
+ };
191
+
192
+ /**
193
+ * Icons in buttons
194
+ */
195
+ export const InButtons: Story = {
196
+ render: () => (
197
+ <div className="flex flex-wrap items-center gap-4">
198
+ <Button>
199
+ <Icon name="plus" size="sm" className="mr-2" />
200
+ Add Item
201
+ </Button>
202
+ <Button variant="secondary">
203
+ <Icon name="download" size="sm" className="mr-2" />
204
+ Download
205
+ </Button>
206
+ <Button variant="outline">
207
+ <Icon name="settings" size="sm" className="mr-2" />
208
+ Settings
209
+ </Button>
210
+ <Button variant="ghost">
211
+ <Icon name="refresh-cw" size="sm" className="mr-2" />
212
+ Refresh
213
+ </Button>
214
+ <Button variant="destructive">
215
+ <Icon name="x" size="sm" className="mr-2" />
216
+ Delete
217
+ </Button>
218
+ <Button size="icon" variant="outline">
219
+ <Icon name="search" size="sm" aria-label="Search" />
220
+ </Button>
221
+ <Button size="icon" variant="ghost">
222
+ <Icon name="more-vertical" size="sm" aria-label="More options" />
223
+ </Button>
224
+ </div>
225
+ ),
226
+ };
227
+
228
+ /**
229
+ * Loading spinner animation
230
+ */
231
+ export const LoadingSpinner: Story = {
232
+ render: () => (
233
+ <div className="flex items-center gap-6">
234
+ <Icon
235
+ name="loader-2"
236
+ size="default"
237
+ className="animate-spin"
238
+ aria-label="Loading"
239
+ />
240
+ <Icon
241
+ name="loader-2"
242
+ size="lg"
243
+ className="animate-spin text-primary"
244
+ aria-label="Loading"
245
+ />
246
+ <Icon
247
+ name="loader-2"
248
+ size="xl"
249
+ className="animate-spin text-muted-foreground"
250
+ aria-label="Loading"
251
+ />
252
+ </div>
253
+ ),
254
+ };
255
+
256
+ /**
257
+ * Navigation icons
258
+ */
259
+ export const Navigation: Story = {
260
+ render: () => (
261
+ <div className="space-y-6">
262
+ <div>
263
+ <h4 className="mb-3 font-semibold text-sm">Chevrons</h4>
264
+ <div className="flex items-center gap-4">
265
+ <Icon name="chevron-up" size="default" />
266
+ <Icon name="chevron-down" size="default" />
267
+ <Icon name="chevron-left" size="default" />
268
+ <Icon name="chevron-right" size="default" />
269
+ <Icon name="chevrons-up-down" size="default" />
270
+ </div>
271
+ </div>
272
+ <div>
273
+ <h4 className="mb-3 font-semibold text-sm">Arrows</h4>
274
+ <div className="flex items-center gap-4">
275
+ <Icon name="arrow-left" size="default" />
276
+ <Icon name="arrow-right" size="default" />
277
+ </div>
278
+ </div>
279
+ </div>
280
+ ),
281
+ };
@@ -0,0 +1,87 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { iconRegistry, type IconName } from "@/registry/icons";
5
+ import { cn } from "@/lib/utils";
6
+ import { cva, type VariantProps } from "class-variance-authority";
7
+
8
+ /**
9
+ * Icon Primitive
10
+ *
11
+ * A reusable icon component that uses the centralized icon registry.
12
+ * All icons MUST use this component or the iconRegistry directly.
13
+ *
14
+ * Features:
15
+ * - Size variants (xs, sm, default, lg, xl)
16
+ * - Accessibility support with aria-label
17
+ * - Error handling for missing icons
18
+ * - Color inherits from currentColor
19
+ */
20
+
21
+ const iconVariants = cva("inline-block flex-shrink-0", {
22
+ variants: {
23
+ size: {
24
+ xs: "h-3 w-3",
25
+ sm: "h-4 w-4",
26
+ default: "h-5 w-5",
27
+ lg: "h-6 w-6",
28
+ xl: "h-8 w-8",
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ size: "default",
33
+ },
34
+ });
35
+
36
+ export interface IconProps
37
+ extends Omit<React.SVGProps<SVGSVGElement>, "viewBox" | "children">,
38
+ VariantProps<typeof iconVariants> {
39
+ /**
40
+ * Name of the icon from the icon registry
41
+ * Type-safe: only accepts valid icon names
42
+ */
43
+ name: IconName | string;
44
+ /**
45
+ * Optional aria-label for accessibility
46
+ * If provided, aria-hidden will be false
47
+ */
48
+ "aria-label"?: string;
49
+ }
50
+
51
+ /**
52
+ * Icon component - renders icons from the icon registry
53
+ */
54
+ export const Icon = React.memo<IconProps>(
55
+ ({ name, size, className, "aria-label": ariaLabel, ...props }) => {
56
+ const icon = iconRegistry.get(name);
57
+
58
+ if (!icon) {
59
+ if (process.env.NODE_ENV === "development") {
60
+ console.warn(
61
+ `Icon "${name}" not found in registry. Available icons:`,
62
+ iconRegistry.getNames().join(", ")
63
+ );
64
+ }
65
+ return null;
66
+ }
67
+
68
+ return (
69
+ <svg
70
+ viewBox={icon.viewBox}
71
+ className={cn(iconVariants({ size }), className)}
72
+ aria-hidden={!ariaLabel}
73
+ aria-label={ariaLabel}
74
+ fill="none"
75
+ stroke="currentColor"
76
+ strokeWidth="2"
77
+ strokeLinecap="round"
78
+ strokeLinejoin="round"
79
+ {...props}
80
+ >
81
+ <path d={icon.path} />
82
+ </svg>
83
+ );
84
+ }
85
+ );
86
+
87
+ Icon.displayName = "Icon";