@otfdashkit/ui 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 (658) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.js +14886 -0
  3. package/dist/index.mjs +14389 -0
  4. package/package.json +124 -0
  5. package/src/advanced/BulkActions/BulkActions.stories.tsx +14 -0
  6. package/src/advanced/BulkActions/BulkActions.test.tsx +9 -0
  7. package/src/advanced/BulkActions/BulkActions.tsx +46 -0
  8. package/src/advanced/BulkActions/index.ts +2 -0
  9. package/src/advanced/CommandBar/CommandBar.stories.tsx +14 -0
  10. package/src/advanced/CommandBar/CommandBar.test.tsx +9 -0
  11. package/src/advanced/CommandBar/CommandBar.tsx +115 -0
  12. package/src/advanced/CommandBar/index.ts +2 -0
  13. package/src/advanced/Filters/Filters.stories.tsx +14 -0
  14. package/src/advanced/Filters/Filters.test.tsx +9 -0
  15. package/src/advanced/Filters/Filters.tsx +103 -0
  16. package/src/advanced/Filters/index.ts +2 -0
  17. package/src/advanced/Kanban/Kanban.stories.tsx +14 -0
  18. package/src/advanced/Kanban/Kanban.test.tsx +9 -0
  19. package/src/advanced/Kanban/Kanban.tsx +95 -0
  20. package/src/advanced/Kanban/index.ts +2 -0
  21. package/src/advanced/ToggleButton/ToggleButton.stories.tsx +14 -0
  22. package/src/advanced/ToggleButton/ToggleButton.test.tsx +9 -0
  23. package/src/advanced/ToggleButton/ToggleButton.tsx +78 -0
  24. package/src/advanced/ToggleButton/index.ts +2 -0
  25. package/src/advanced/bulk-actions.tsx +46 -0
  26. package/src/advanced/command-bar.tsx +115 -0
  27. package/src/advanced/filters.tsx +103 -0
  28. package/src/advanced/gantt.tsx +824 -0
  29. package/src/advanced/kanban.tsx +95 -0
  30. package/src/advanced/rich-editor.tsx +700 -0
  31. package/src/advanced/toggle-button.tsx +78 -0
  32. package/src/advanced/utils/cn.ts +1 -0
  33. package/src/app-shell/AppShell.tsx +24 -0
  34. package/src/app-shell/BillingStatus.tsx +63 -0
  35. package/src/app-shell/Sidebar.tsx +172 -0
  36. package/src/app-shell/SidebarResizer.tsx +109 -0
  37. package/src/app-shell/SortableNav.tsx +122 -0
  38. package/src/app-shell/UserMenu.tsx +135 -0
  39. package/src/app-shell/WorkspacesMenu.tsx +114 -0
  40. package/src/app-shell/index.ts +18 -0
  41. package/src/backgrounds/AnimatedGradient.tsx +151 -0
  42. package/src/backgrounds/DottedBackground.tsx +64 -0
  43. package/src/backgrounds/GradientBackground.tsx +113 -0
  44. package/src/backgrounds/HeroShaderA.tsx +255 -0
  45. package/src/backgrounds/NoiseBackground.tsx +51 -0
  46. package/src/backgrounds/index.ts +5 -0
  47. package/src/blocks/ChatDetail/ChatDetail.stories.tsx +14 -0
  48. package/src/blocks/ChatDetail/ChatDetail.test.tsx +9 -0
  49. package/src/blocks/ChatDetail/ChatDetail.tsx +73 -0
  50. package/src/blocks/ChatDetail/index.ts +2 -0
  51. package/src/blocks/FeedbackModal/FeedbackModal.stories.tsx +14 -0
  52. package/src/blocks/FeedbackModal/FeedbackModal.test.tsx +9 -0
  53. package/src/blocks/FeedbackModal/FeedbackModal.tsx +68 -0
  54. package/src/blocks/FeedbackModal/index.ts +2 -0
  55. package/src/blocks/FileCards/FileCards.stories.tsx +14 -0
  56. package/src/blocks/FileCards/FileCards.test.tsx +9 -0
  57. package/src/blocks/FileCards/FileCards.tsx +56 -0
  58. package/src/blocks/FileCards/index.ts +2 -0
  59. package/src/blocks/FilesList/FilesList.stories.tsx +14 -0
  60. package/src/blocks/FilesList/FilesList.test.tsx +9 -0
  61. package/src/blocks/FilesList/FilesList.tsx +72 -0
  62. package/src/blocks/FilesList/index.ts +2 -0
  63. package/src/blocks/FloatingActionButton/FloatingActionButton.stories.tsx +223 -0
  64. package/src/blocks/FloatingActionButton/FloatingActionButton.test.tsx +47 -0
  65. package/src/blocks/FloatingActionButton/FloatingActionButton.tsx +253 -0
  66. package/src/blocks/FloatingActionButton/index.ts +1 -0
  67. package/src/blocks/IntegrationCard/IntegrationCard.stories.tsx +14 -0
  68. package/src/blocks/IntegrationCard/IntegrationCard.test.tsx +9 -0
  69. package/src/blocks/IntegrationCard/IntegrationCard.tsx +50 -0
  70. package/src/blocks/IntegrationCard/index.ts +2 -0
  71. package/src/blocks/InviteModal/InviteModal.stories.tsx +14 -0
  72. package/src/blocks/InviteModal/InviteModal.test.tsx +9 -0
  73. package/src/blocks/InviteModal/InviteModal.tsx +69 -0
  74. package/src/blocks/InviteModal/index.ts +2 -0
  75. package/src/blocks/ManageTagsModal/ManageTagsModal.stories.tsx +14 -0
  76. package/src/blocks/ManageTagsModal/ManageTagsModal.test.tsx +9 -0
  77. package/src/blocks/ManageTagsModal/ManageTagsModal.tsx +63 -0
  78. package/src/blocks/ManageTagsModal/index.ts +2 -0
  79. package/src/blocks/MessagesCard/MessagesCard.stories.tsx +14 -0
  80. package/src/blocks/MessagesCard/MessagesCard.test.tsx +9 -0
  81. package/src/blocks/MessagesCard/MessagesCard.tsx +59 -0
  82. package/src/blocks/MessagesCard/index.ts +2 -0
  83. package/src/blocks/MetricCard/MetricCard.stories.tsx +14 -0
  84. package/src/blocks/MetricCard/MetricCard.test.tsx +9 -0
  85. package/src/blocks/MetricCard/MetricCard.tsx +79 -0
  86. package/src/blocks/MetricCard/index.ts +2 -0
  87. package/src/blocks/NotificationSettings/NotificationSettings.stories.tsx +14 -0
  88. package/src/blocks/NotificationSettings/NotificationSettings.test.tsx +9 -0
  89. package/src/blocks/NotificationSettings/NotificationSettings.tsx +61 -0
  90. package/src/blocks/NotificationSettings/index.ts +2 -0
  91. package/src/blocks/OrganizationMenu/OrganizationMenu.stories.tsx +14 -0
  92. package/src/blocks/OrganizationMenu/OrganizationMenu.test.tsx +9 -0
  93. package/src/blocks/OrganizationMenu/OrganizationMenu.tsx +66 -0
  94. package/src/blocks/OrganizationMenu/index.ts +2 -0
  95. package/src/blocks/RolesMenu/RolesMenu.stories.tsx +14 -0
  96. package/src/blocks/RolesMenu/RolesMenu.test.tsx +9 -0
  97. package/src/blocks/RolesMenu/RolesMenu.tsx +61 -0
  98. package/src/blocks/RolesMenu/index.ts +2 -0
  99. package/src/blocks/SelectUsersModal/SelectUsersModal.stories.tsx +14 -0
  100. package/src/blocks/SelectUsersModal/SelectUsersModal.test.tsx +9 -0
  101. package/src/blocks/SelectUsersModal/SelectUsersModal.tsx +64 -0
  102. package/src/blocks/SelectUsersModal/index.ts +2 -0
  103. package/src/blocks/SidebarLayoutDashboard/SidebarLayoutDashboard.stories.tsx +14 -0
  104. package/src/blocks/SidebarLayoutDashboard/SidebarLayoutDashboard.test.tsx +9 -0
  105. package/src/blocks/SidebarLayoutDashboard/SidebarLayoutDashboard.tsx +97 -0
  106. package/src/blocks/SidebarLayoutDashboard/index.ts +2 -0
  107. package/src/blocks/SidebarLayoutGroups/SidebarLayoutGroups.stories.tsx +14 -0
  108. package/src/blocks/SidebarLayoutGroups/SidebarLayoutGroups.test.tsx +9 -0
  109. package/src/blocks/SidebarLayoutGroups/SidebarLayoutGroups.tsx +79 -0
  110. package/src/blocks/SidebarLayoutGroups/index.ts +2 -0
  111. package/src/blocks/SidebarLayoutMinimal/SidebarLayoutMinimal.stories.tsx +14 -0
  112. package/src/blocks/SidebarLayoutMinimal/SidebarLayoutMinimal.test.tsx +9 -0
  113. package/src/blocks/SidebarLayoutMinimal/SidebarLayoutMinimal.tsx +73 -0
  114. package/src/blocks/SidebarLayoutMinimal/index.ts +2 -0
  115. package/src/blocks/SidebarLayoutSearch/SidebarLayoutSearch.stories.tsx +14 -0
  116. package/src/blocks/SidebarLayoutSearch/SidebarLayoutSearch.test.tsx +9 -0
  117. package/src/blocks/SidebarLayoutSearch/SidebarLayoutSearch.tsx +79 -0
  118. package/src/blocks/SidebarLayoutSearch/index.ts +2 -0
  119. package/src/blocks/SidebarLayoutUser/SidebarLayoutUser.stories.tsx +14 -0
  120. package/src/blocks/SidebarLayoutUser/SidebarLayoutUser.test.tsx +9 -0
  121. package/src/blocks/SidebarLayoutUser/SidebarLayoutUser.tsx +82 -0
  122. package/src/blocks/SidebarLayoutUser/index.ts +2 -0
  123. package/src/blocks/SortableTaskList/SortableTaskList.stories.tsx +14 -0
  124. package/src/blocks/SortableTaskList/SortableTaskList.test.tsx +9 -0
  125. package/src/blocks/SortableTaskList/SortableTaskList.tsx +70 -0
  126. package/src/blocks/SortableTaskList/index.ts +2 -0
  127. package/src/blocks/StackedLayoutBranded/StackedLayoutBranded.stories.tsx +14 -0
  128. package/src/blocks/StackedLayoutBranded/StackedLayoutBranded.test.tsx +9 -0
  129. package/src/blocks/StackedLayoutBranded/StackedLayoutBranded.tsx +64 -0
  130. package/src/blocks/StackedLayoutBranded/index.ts +2 -0
  131. package/src/blocks/StackedLayoutTabs/StackedLayoutTabs.stories.tsx +14 -0
  132. package/src/blocks/StackedLayoutTabs/StackedLayoutTabs.test.tsx +9 -0
  133. package/src/blocks/StackedLayoutTabs/StackedLayoutTabs.tsx +80 -0
  134. package/src/blocks/StackedLayoutTabs/index.ts +2 -0
  135. package/src/blocks/TaskCard/TaskCard.stories.tsx +14 -0
  136. package/src/blocks/TaskCard/TaskCard.test.tsx +9 -0
  137. package/src/blocks/TaskCard/TaskCard.tsx +88 -0
  138. package/src/blocks/TaskCard/index.ts +2 -0
  139. package/src/blocks/UserMenu/UserMenu.stories.tsx +14 -0
  140. package/src/blocks/UserMenu/UserMenu.test.tsx +9 -0
  141. package/src/blocks/UserMenu/UserMenu.tsx +62 -0
  142. package/src/blocks/UserMenu/index.ts +2 -0
  143. package/src/blocks/WorkspaceMembers/WorkspaceMembers.stories.tsx +14 -0
  144. package/src/blocks/WorkspaceMembers/WorkspaceMembers.test.tsx +9 -0
  145. package/src/blocks/WorkspaceMembers/WorkspaceMembers.tsx +61 -0
  146. package/src/blocks/WorkspaceMembers/index.ts +2 -0
  147. package/src/blocks/activity-heatmap.tsx +122 -0
  148. package/src/blocks/bar-list.tsx +75 -0
  149. package/src/blocks/chat-detail.tsx +73 -0
  150. package/src/blocks/feedback-modal.tsx +68 -0
  151. package/src/blocks/file-cards.tsx +56 -0
  152. package/src/blocks/files-list.tsx +72 -0
  153. package/src/blocks/integration-card.tsx +50 -0
  154. package/src/blocks/invite-modal.tsx +69 -0
  155. package/src/blocks/manage-tags-modal.tsx +63 -0
  156. package/src/blocks/messages-card.tsx +59 -0
  157. package/src/blocks/metric-card.tsx +79 -0
  158. package/src/blocks/notification-settings.tsx +61 -0
  159. package/src/blocks/organization-menu.tsx +85 -0
  160. package/src/blocks/roles-menu.tsx +61 -0
  161. package/src/blocks/select-users-modal.tsx +64 -0
  162. package/src/blocks/sidebar-layout-dashboard.tsx +97 -0
  163. package/src/blocks/sidebar-layout-groups.tsx +79 -0
  164. package/src/blocks/sidebar-layout-minimal.tsx +73 -0
  165. package/src/blocks/sidebar-layout-search.tsx +79 -0
  166. package/src/blocks/sidebar-layout-user.tsx +82 -0
  167. package/src/blocks/sortable-task-list.tsx +70 -0
  168. package/src/blocks/stacked-layout-branded.tsx +64 -0
  169. package/src/blocks/stacked-layout-tabs.tsx +80 -0
  170. package/src/blocks/task-card.tsx +88 -0
  171. package/src/blocks/user-menu.tsx +62 -0
  172. package/src/blocks/utils/cn.ts +1 -0
  173. package/src/blocks/workspace-members.tsx +61 -0
  174. package/src/charts/area-chart.tsx +83 -0
  175. package/src/charts/bar-chart.tsx +146 -0
  176. package/src/charts/heatmap.tsx +185 -0
  177. package/src/charts/line-chart.tsx +89 -0
  178. package/src/charts/sparkline.tsx +62 -0
  179. package/src/charts/utils/cn.ts +1 -0
  180. package/src/components/Banner/Banner.stories.tsx +14 -0
  181. package/src/components/Banner/Banner.test.tsx +9 -0
  182. package/src/components/Banner/Banner.tsx +203 -0
  183. package/src/components/Banner/index.ts +2 -0
  184. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +14 -0
  185. package/src/components/Breadcrumb/Breadcrumb.test.tsx +9 -0
  186. package/src/components/Breadcrumb/Breadcrumb.tsx +58 -0
  187. package/src/components/Breadcrumb/index.ts +2 -0
  188. package/src/components/CommandItem/CommandItem.stories.tsx +14 -0
  189. package/src/components/CommandItem/CommandItem.test.tsx +9 -0
  190. package/src/components/CommandItem/CommandItem.tsx +36 -0
  191. package/src/components/CommandItem/index.ts +2 -0
  192. package/src/components/DataGrid/DataGrid.stories.tsx +14 -0
  193. package/src/components/DataGrid/DataGrid.test.tsx +9 -0
  194. package/src/components/DataGrid/DataGrid.tsx +125 -0
  195. package/src/components/DataGrid/index.ts +2 -0
  196. package/src/components/DataTable/DataTable.stories.tsx +14 -0
  197. package/src/components/DataTable/DataTable.test.tsx +9 -0
  198. package/src/components/DataTable/DataTable.tsx +139 -0
  199. package/src/components/DataTable/index.ts +2 -0
  200. package/src/components/EmptyState/EmptyState.stories.tsx +14 -0
  201. package/src/components/EmptyState/EmptyState.test.tsx +9 -0
  202. package/src/components/EmptyState/EmptyState.tsx +106 -0
  203. package/src/components/EmptyState/index.ts +2 -0
  204. package/src/components/Hotkeys/Hotkeys.stories.tsx +14 -0
  205. package/src/components/Hotkeys/Hotkeys.test.tsx +9 -0
  206. package/src/components/Hotkeys/Hotkeys.tsx +31 -0
  207. package/src/components/Hotkeys/index.ts +2 -0
  208. package/src/components/IconBadge/IconBadge.stories.tsx +14 -0
  209. package/src/components/IconBadge/IconBadge.test.tsx +9 -0
  210. package/src/components/IconBadge/IconBadge.tsx +35 -0
  211. package/src/components/IconBadge/index.ts +2 -0
  212. package/src/components/LoadingOverlay/LoadingOverlay.stories.tsx +14 -0
  213. package/src/components/LoadingOverlay/LoadingOverlay.test.tsx +9 -0
  214. package/src/components/LoadingOverlay/LoadingOverlay.tsx +38 -0
  215. package/src/components/LoadingOverlay/index.ts +2 -0
  216. package/src/components/Persona/Persona.stories.tsx +14 -0
  217. package/src/components/Persona/Persona.test.tsx +9 -0
  218. package/src/components/Persona/Persona.tsx +38 -0
  219. package/src/components/Persona/index.ts +2 -0
  220. package/src/components/PropertyList/PropertyList.stories.tsx +14 -0
  221. package/src/components/PropertyList/PropertyList.test.tsx +9 -0
  222. package/src/components/PropertyList/PropertyList.tsx +29 -0
  223. package/src/components/PropertyList/index.ts +2 -0
  224. package/src/components/Stat/Stat.stories.tsx +14 -0
  225. package/src/components/Stat/Stat.test.tsx +9 -0
  226. package/src/components/Stat/Stat.tsx +51 -0
  227. package/src/components/Stat/index.ts +2 -0
  228. package/src/components/Stepper/Stepper.stories.tsx +14 -0
  229. package/src/components/Stepper/Stepper.test.tsx +9 -0
  230. package/src/components/Stepper/Stepper.tsx +58 -0
  231. package/src/components/Stepper/index.ts +2 -0
  232. package/src/components/StructuredList/StructuredList.stories.tsx +14 -0
  233. package/src/components/StructuredList/StructuredList.test.tsx +9 -0
  234. package/src/components/StructuredList/StructuredList.tsx +51 -0
  235. package/src/components/StructuredList/index.ts +2 -0
  236. package/src/components/Timeline/Timeline.stories.tsx +14 -0
  237. package/src/components/Timeline/Timeline.test.tsx +9 -0
  238. package/src/components/Timeline/Timeline.tsx +69 -0
  239. package/src/components/Timeline/index.ts +2 -0
  240. package/src/components/Toaster/Toaster.stories.tsx +14 -0
  241. package/src/components/Toaster/Toaster.test.tsx +9 -0
  242. package/src/components/Toaster/Toaster.tsx +42 -0
  243. package/src/components/Toaster/index.ts +2 -0
  244. package/src/components/banner.tsx +203 -0
  245. package/src/components/breadcrumb.tsx +58 -0
  246. package/src/components/command-item.tsx +36 -0
  247. package/src/components/data-grid.tsx +125 -0
  248. package/src/components/data-table.tsx +139 -0
  249. package/src/components/empty-state.tsx +31 -0
  250. package/src/components/hotkeys.tsx +31 -0
  251. package/src/components/icon-badge.tsx +35 -0
  252. package/src/components/loading-overlay.tsx +38 -0
  253. package/src/components/persona.tsx +38 -0
  254. package/src/components/property-list.tsx +29 -0
  255. package/src/components/stat.tsx +51 -0
  256. package/src/components/stepper.tsx +69 -0
  257. package/src/components/structured-list.tsx +51 -0
  258. package/src/components/timeline.tsx +69 -0
  259. package/src/components/toaster.tsx +42 -0
  260. package/src/components/utils/cn.ts +1 -0
  261. package/src/data/ActionBar.tsx +115 -0
  262. package/src/data/DataGrid.tsx +453 -0
  263. package/src/data/DataList.tsx +79 -0
  264. package/src/data/EventCalendar.tsx +794 -0
  265. package/src/data/Filters.tsx +271 -0
  266. package/src/data/GridList.tsx +67 -0
  267. package/src/data/ImageCrop.tsx +198 -0
  268. package/src/data/SortableList.tsx +258 -0
  269. package/src/data/Tree.tsx +510 -0
  270. package/src/data/VideoPlayer.tsx +564 -0
  271. package/src/data/index.ts +6 -0
  272. package/src/engagement/Beacon/Beacon.stories.tsx +14 -0
  273. package/src/engagement/Beacon/Beacon.test.tsx +9 -0
  274. package/src/engagement/Beacon/Beacon.tsx +50 -0
  275. package/src/engagement/Beacon/index.ts +2 -0
  276. package/src/engagement/Tour/Tour.stories.tsx +14 -0
  277. package/src/engagement/Tour/Tour.test.tsx +9 -0
  278. package/src/engagement/Tour/Tour.tsx +106 -0
  279. package/src/engagement/Tour/index.ts +2 -0
  280. package/src/engagement/beacon.tsx +50 -0
  281. package/src/engagement/checklist.tsx +259 -0
  282. package/src/engagement/intro-disclosure.tsx +210 -0
  283. package/src/engagement/tour.tsx +106 -0
  284. package/src/engagement/utils/cn.ts +1 -0
  285. package/src/feedback/Toaster.tsx +141 -0
  286. package/src/feedback/index.ts +2 -0
  287. package/src/feedback/toast-emitter.ts +74 -0
  288. package/src/forms/ArrayField/ArrayField.stories.tsx +14 -0
  289. package/src/forms/ArrayField/ArrayField.test.tsx +9 -0
  290. package/src/forms/ArrayField/ArrayField.tsx +61 -0
  291. package/src/forms/ArrayField/index.ts +2 -0
  292. package/src/forms/AutoForm/AutoForm.stories.tsx +14 -0
  293. package/src/forms/AutoForm/AutoForm.test.tsx +9 -0
  294. package/src/forms/AutoForm/AutoForm.tsx +133 -0
  295. package/src/forms/AutoForm/index.ts +2 -0
  296. package/src/forms/DatePicker/DatePicker.stories.tsx +14 -0
  297. package/src/forms/DatePicker/DatePicker.test.tsx +9 -0
  298. package/src/forms/DatePicker/DatePicker.tsx +109 -0
  299. package/src/forms/DatePicker/index.ts +2 -0
  300. package/src/forms/Field/Field.stories.tsx +14 -0
  301. package/src/forms/Field/Field.test.tsx +9 -0
  302. package/src/forms/Field/Field.tsx +62 -0
  303. package/src/forms/Field/index.ts +2 -0
  304. package/src/forms/FileUpload/FileUpload.stories.tsx +14 -0
  305. package/src/forms/FileUpload/FileUpload.test.tsx +9 -0
  306. package/src/forms/FileUpload/FileUpload.tsx +101 -0
  307. package/src/forms/FileUpload/index.ts +2 -0
  308. package/src/forms/Form/Form.stories.tsx +14 -0
  309. package/src/forms/Form/Form.test.tsx +9 -0
  310. package/src/forms/Form/Form.tsx +57 -0
  311. package/src/forms/Form/index.ts +2 -0
  312. package/src/forms/ObjectField/ObjectField.stories.tsx +14 -0
  313. package/src/forms/ObjectField/ObjectField.test.tsx +9 -0
  314. package/src/forms/ObjectField/ObjectField.tsx +53 -0
  315. package/src/forms/ObjectField/index.ts +2 -0
  316. package/src/forms/PasswordInput/PasswordInput.stories.tsx +14 -0
  317. package/src/forms/PasswordInput/PasswordInput.test.tsx +9 -0
  318. package/src/forms/PasswordInput/PasswordInput.tsx +54 -0
  319. package/src/forms/PasswordInput/index.ts +2 -0
  320. package/src/forms/SearchInput/SearchInput.stories.tsx +14 -0
  321. package/src/forms/SearchInput/SearchInput.test.tsx +9 -0
  322. package/src/forms/SearchInput/SearchInput.tsx +64 -0
  323. package/src/forms/SearchInput/index.ts +2 -0
  324. package/src/forms/StepForm/StepForm.stories.tsx +14 -0
  325. package/src/forms/StepForm/StepForm.test.tsx +9 -0
  326. package/src/forms/StepForm/StepForm.tsx +113 -0
  327. package/src/forms/StepForm/index.ts +2 -0
  328. package/src/forms/array-field.tsx +61 -0
  329. package/src/forms/auto-form.tsx +133 -0
  330. package/src/forms/color-picker.tsx +258 -0
  331. package/src/forms/combobox.tsx +106 -0
  332. package/src/forms/date-picker.tsx +109 -0
  333. package/src/forms/field.tsx +62 -0
  334. package/src/forms/file-upload.tsx +101 -0
  335. package/src/forms/form.tsx +57 -0
  336. package/src/forms/object-field.tsx +53 -0
  337. package/src/forms/password-input.tsx +54 -0
  338. package/src/forms/search-input.tsx +64 -0
  339. package/src/forms/step-form.tsx +113 -0
  340. package/src/forms/tags.tsx +270 -0
  341. package/src/forms/utils/cn.ts +1 -0
  342. package/src/headers/ScrollHeader.tsx +110 -0
  343. package/src/headers/index.ts +1 -0
  344. package/src/index.ts +171 -0
  345. package/src/layout/PageContainer.tsx +40 -0
  346. package/src/layout/PageLayout.tsx +55 -0
  347. package/src/layout/index.ts +2 -0
  348. package/src/layouts/AppShell/AppShell.stories.tsx +14 -0
  349. package/src/layouts/AppShell/AppShell.test.tsx +9 -0
  350. package/src/layouts/AppShell/AppShell.tsx +129 -0
  351. package/src/layouts/AppShell/index.ts +2 -0
  352. package/src/layouts/Container/Container.stories.tsx +14 -0
  353. package/src/layouts/Container/Container.test.tsx +9 -0
  354. package/src/layouts/Container/Container.tsx +33 -0
  355. package/src/layouts/Container/index.ts +2 -0
  356. package/src/layouts/Navbar/Navbar.stories.tsx +14 -0
  357. package/src/layouts/Navbar/Navbar.test.tsx +9 -0
  358. package/src/layouts/Navbar/Navbar.tsx +60 -0
  359. package/src/layouts/Navbar/index.ts +2 -0
  360. package/src/layouts/Page/Page.stories.tsx +14 -0
  361. package/src/layouts/Page/Page.test.tsx +9 -0
  362. package/src/layouts/Page/Page.tsx +61 -0
  363. package/src/layouts/Page/index.ts +2 -0
  364. package/src/layouts/ResizeBox/ResizeBox.stories.tsx +14 -0
  365. package/src/layouts/ResizeBox/ResizeBox.test.tsx +9 -0
  366. package/src/layouts/ResizeBox/ResizeBox.tsx +45 -0
  367. package/src/layouts/ResizeBox/index.ts +2 -0
  368. package/src/layouts/Sidebar/Sidebar.stories.tsx +14 -0
  369. package/src/layouts/Sidebar/Sidebar.test.tsx +9 -0
  370. package/src/layouts/Sidebar/Sidebar.tsx +99 -0
  371. package/src/layouts/Sidebar/index.ts +2 -0
  372. package/src/layouts/SplitPage/SplitPage.stories.tsx +14 -0
  373. package/src/layouts/SplitPage/SplitPage.test.tsx +9 -0
  374. package/src/layouts/SplitPage/SplitPage.tsx +32 -0
  375. package/src/layouts/SplitPage/index.ts +2 -0
  376. package/src/layouts/Stack/Stack.stories.tsx +14 -0
  377. package/src/layouts/Stack/Stack.test.tsx +9 -0
  378. package/src/layouts/Stack/Stack.tsx +56 -0
  379. package/src/layouts/Stack/index.ts +2 -0
  380. package/src/layouts/app-shell.tsx +129 -0
  381. package/src/layouts/container.tsx +33 -0
  382. package/src/layouts/navbar.tsx +60 -0
  383. package/src/layouts/page.tsx +61 -0
  384. package/src/layouts/resize-box.tsx +45 -0
  385. package/src/layouts/sidebar.tsx +99 -0
  386. package/src/layouts/split-page.tsx +32 -0
  387. package/src/layouts/stack.tsx +56 -0
  388. package/src/layouts/utils/cn.ts +1 -0
  389. package/src/motion/FadeIn.tsx +33 -0
  390. package/src/motion/Morph.tsx +17 -0
  391. package/src/motion/Parallax.tsx +37 -0
  392. package/src/motion/Reveal.tsx +32 -0
  393. package/src/motion/Ripple.tsx +78 -0
  394. package/src/motion/ScaleIn.tsx +33 -0
  395. package/src/motion/SlideIn.tsx +42 -0
  396. package/src/motion/Stagger.tsx +48 -0
  397. package/src/motion/Transition.tsx +13 -0
  398. package/src/motion/index.ts +13 -0
  399. package/src/motion/presets.ts +33 -0
  400. package/src/motion/useLayoutId.ts +6 -0
  401. package/src/nav/CommandPalette.tsx +197 -0
  402. package/src/nav/HotkeysProvider.tsx +223 -0
  403. package/src/nav/index.ts +2 -0
  404. package/src/primitives/Accordion/Accordion.stories.tsx +14 -0
  405. package/src/primitives/Accordion/Accordion.test.tsx +9 -0
  406. package/src/primitives/Accordion/Accordion.tsx +56 -0
  407. package/src/primitives/Accordion/index.ts +2 -0
  408. package/src/primitives/Alert/Alert.stories.tsx +14 -0
  409. package/src/primitives/Alert/Alert.test.tsx +9 -0
  410. package/src/primitives/Alert/Alert.tsx +60 -0
  411. package/src/primitives/Alert/index.ts +2 -0
  412. package/src/primitives/AlertDialog/AlertDialog.stories.tsx +14 -0
  413. package/src/primitives/AlertDialog/AlertDialog.test.tsx +9 -0
  414. package/src/primitives/AlertDialog/AlertDialog.tsx +140 -0
  415. package/src/primitives/AlertDialog/index.ts +2 -0
  416. package/src/primitives/AspectRatio/AspectRatio.stories.tsx +14 -0
  417. package/src/primitives/AspectRatio/AspectRatio.test.tsx +9 -0
  418. package/src/primitives/AspectRatio/AspectRatio.tsx +6 -0
  419. package/src/primitives/AspectRatio/index.ts +2 -0
  420. package/src/primitives/Avatar/Avatar.stories.tsx +14 -0
  421. package/src/primitives/Avatar/Avatar.test.tsx +9 -0
  422. package/src/primitives/Avatar/Avatar.tsx +35 -0
  423. package/src/primitives/Avatar/index.ts +2 -0
  424. package/src/primitives/Badge/Badge.stories.tsx +14 -0
  425. package/src/primitives/Badge/Badge.test.tsx +9 -0
  426. package/src/primitives/Badge/Badge.tsx +28 -0
  427. package/src/primitives/Badge/index.ts +2 -0
  428. package/src/primitives/Button/Button.stories.tsx +14 -0
  429. package/src/primitives/Button/Button.test.tsx +9 -0
  430. package/src/primitives/Button/Button.tsx +113 -0
  431. package/src/primitives/Button/index.ts +2 -0
  432. package/src/primitives/Calendar/Calendar.stories.tsx +14 -0
  433. package/src/primitives/Calendar/Calendar.test.tsx +9 -0
  434. package/src/primitives/Calendar/Calendar.tsx +214 -0
  435. package/src/primitives/Calendar/index.ts +2 -0
  436. package/src/primitives/Card/Card.stories.tsx +14 -0
  437. package/src/primitives/Card/Card.test.tsx +9 -0
  438. package/src/primitives/Card/Card.tsx +48 -0
  439. package/src/primitives/Card/TextureCard.tsx +93 -0
  440. package/src/primitives/Card/index.ts +3 -0
  441. package/src/primitives/Carousel/Carousel.stories.tsx +14 -0
  442. package/src/primitives/Carousel/Carousel.test.tsx +9 -0
  443. package/src/primitives/Carousel/Carousel.tsx +261 -0
  444. package/src/primitives/Carousel/index.ts +2 -0
  445. package/src/primitives/Chart/Chart.stories.tsx +14 -0
  446. package/src/primitives/Chart/Chart.test.tsx +9 -0
  447. package/src/primitives/Chart/Chart.tsx +368 -0
  448. package/src/primitives/Chart/index.ts +2 -0
  449. package/src/primitives/Checkbox/Checkbox.stories.tsx +14 -0
  450. package/src/primitives/Checkbox/Checkbox.test.tsx +9 -0
  451. package/src/primitives/Checkbox/Checkbox.tsx +27 -0
  452. package/src/primitives/Checkbox/index.ts +2 -0
  453. package/src/primitives/Collapsible/Collapsible.stories.tsx +14 -0
  454. package/src/primitives/Collapsible/Collapsible.test.tsx +9 -0
  455. package/src/primitives/Collapsible/Collapsible.tsx +12 -0
  456. package/src/primitives/Collapsible/index.ts +2 -0
  457. package/src/primitives/Command/Command.stories.tsx +14 -0
  458. package/src/primitives/Command/Command.test.tsx +9 -0
  459. package/src/primitives/Command/Command.tsx +154 -0
  460. package/src/primitives/Command/index.ts +2 -0
  461. package/src/primitives/ContextMenu/ContextMenu.stories.tsx +14 -0
  462. package/src/primitives/ContextMenu/ContextMenu.test.tsx +9 -0
  463. package/src/primitives/ContextMenu/ContextMenu.tsx +101 -0
  464. package/src/primitives/ContextMenu/index.ts +2 -0
  465. package/src/primitives/Dialog/Dialog.stories.tsx +14 -0
  466. package/src/primitives/Dialog/Dialog.test.tsx +9 -0
  467. package/src/primitives/Dialog/Dialog.tsx +88 -0
  468. package/src/primitives/Dialog/DialogProvider.tsx +130 -0
  469. package/src/primitives/Dialog/index.ts +3 -0
  470. package/src/primitives/Drawer/Drawer.stories.tsx +14 -0
  471. package/src/primitives/Drawer/Drawer.test.tsx +9 -0
  472. package/src/primitives/Drawer/Drawer.tsx +123 -0
  473. package/src/primitives/Drawer/index.ts +2 -0
  474. package/src/primitives/DropdownMenu/DropdownMenu.stories.tsx +14 -0
  475. package/src/primitives/DropdownMenu/DropdownMenu.test.tsx +9 -0
  476. package/src/primitives/DropdownMenu/DropdownMenu.tsx +111 -0
  477. package/src/primitives/DropdownMenu/index.ts +2 -0
  478. package/src/primitives/Form/Form.stories.tsx +14 -0
  479. package/src/primitives/Form/Form.test.tsx +9 -0
  480. package/src/primitives/Form/Form.tsx +179 -0
  481. package/src/primitives/Form/index.ts +2 -0
  482. package/src/primitives/HoverCard/HoverCard.stories.tsx +14 -0
  483. package/src/primitives/HoverCard/HoverCard.test.tsx +9 -0
  484. package/src/primitives/HoverCard/HoverCard.tsx +31 -0
  485. package/src/primitives/HoverCard/index.ts +2 -0
  486. package/src/primitives/Input/Input.stories.tsx +14 -0
  487. package/src/primitives/Input/Input.test.tsx +9 -0
  488. package/src/primitives/Input/Input.tsx +110 -0
  489. package/src/primitives/Input/index.ts +2 -0
  490. package/src/primitives/InputOtp/InputOtp.stories.tsx +14 -0
  491. package/src/primitives/InputOtp/InputOtp.test.tsx +9 -0
  492. package/src/primitives/InputOtp/InputOtp.tsx +70 -0
  493. package/src/primitives/InputOtp/index.ts +2 -0
  494. package/src/primitives/Label/Label.stories.tsx +14 -0
  495. package/src/primitives/Label/Label.test.tsx +9 -0
  496. package/src/primitives/Label/Label.tsx +27 -0
  497. package/src/primitives/Label/index.ts +2 -0
  498. package/src/primitives/Menubar/Menubar.stories.tsx +14 -0
  499. package/src/primitives/Menubar/Menubar.test.tsx +9 -0
  500. package/src/primitives/Menubar/Menubar.tsx +255 -0
  501. package/src/primitives/Menubar/index.ts +2 -0
  502. package/src/primitives/NavigationMenu/NavigationMenu.stories.tsx +14 -0
  503. package/src/primitives/NavigationMenu/NavigationMenu.test.tsx +9 -0
  504. package/src/primitives/NavigationMenu/NavigationMenu.tsx +129 -0
  505. package/src/primitives/NavigationMenu/index.ts +2 -0
  506. package/src/primitives/Pagination/Pagination.stories.tsx +14 -0
  507. package/src/primitives/Pagination/Pagination.test.tsx +9 -0
  508. package/src/primitives/Pagination/Pagination.tsx +118 -0
  509. package/src/primitives/Pagination/index.ts +2 -0
  510. package/src/primitives/Popover/Popover.stories.tsx +14 -0
  511. package/src/primitives/Popover/Popover.test.tsx +9 -0
  512. package/src/primitives/Popover/Popover.tsx +30 -0
  513. package/src/primitives/Popover/index.ts +2 -0
  514. package/src/primitives/Progress/Progress.stories.tsx +14 -0
  515. package/src/primitives/Progress/Progress.test.tsx +9 -0
  516. package/src/primitives/Progress/Progress.tsx +20 -0
  517. package/src/primitives/Progress/index.ts +2 -0
  518. package/src/primitives/Radio/Radio.stories.tsx +14 -0
  519. package/src/primitives/Radio/Radio.test.tsx +9 -0
  520. package/src/primitives/Radio/Radio.tsx +33 -0
  521. package/src/primitives/Radio/index.ts +2 -0
  522. package/src/primitives/Resizable/Resizable.stories.tsx +14 -0
  523. package/src/primitives/Resizable/Resizable.test.tsx +9 -0
  524. package/src/primitives/Resizable/Resizable.tsx +44 -0
  525. package/src/primitives/Resizable/index.ts +2 -0
  526. package/src/primitives/ScrollArea/ScrollArea.stories.tsx +14 -0
  527. package/src/primitives/ScrollArea/ScrollArea.test.tsx +9 -0
  528. package/src/primitives/ScrollArea/ScrollArea.tsx +49 -0
  529. package/src/primitives/ScrollArea/index.ts +2 -0
  530. package/src/primitives/Select/Select.stories.tsx +14 -0
  531. package/src/primitives/Select/Select.test.tsx +9 -0
  532. package/src/primitives/Select/Select.tsx +140 -0
  533. package/src/primitives/Select/index.ts +2 -0
  534. package/src/primitives/Separator/Separator.stories.tsx +14 -0
  535. package/src/primitives/Separator/Separator.test.tsx +9 -0
  536. package/src/primitives/Separator/Separator.tsx +21 -0
  537. package/src/primitives/Separator/index.ts +2 -0
  538. package/src/primitives/Sheet/Sheet.stories.tsx +14 -0
  539. package/src/primitives/Sheet/Sheet.test.tsx +9 -0
  540. package/src/primitives/Sheet/Sheet.tsx +88 -0
  541. package/src/primitives/Sheet/index.ts +2 -0
  542. package/src/primitives/Skeleton/Skeleton.stories.tsx +14 -0
  543. package/src/primitives/Skeleton/Skeleton.test.tsx +9 -0
  544. package/src/primitives/Skeleton/Skeleton.tsx +71 -0
  545. package/src/primitives/Skeleton/index.ts +2 -0
  546. package/src/primitives/Slider/Slider.stories.tsx +14 -0
  547. package/src/primitives/Slider/Slider.test.tsx +9 -0
  548. package/src/primitives/Slider/Slider.tsx +20 -0
  549. package/src/primitives/Slider/index.ts +2 -0
  550. package/src/primitives/Sonner/Sonner.stories.tsx +14 -0
  551. package/src/primitives/Sonner/Sonner.test.tsx +9 -0
  552. package/src/primitives/Sonner/Sonner.tsx +30 -0
  553. package/src/primitives/Sonner/index.ts +2 -0
  554. package/src/primitives/Spinner/Spinner.stories.tsx +14 -0
  555. package/src/primitives/Spinner/Spinner.test.tsx +9 -0
  556. package/src/primitives/Spinner/Spinner.tsx +17 -0
  557. package/src/primitives/Spinner/index.ts +2 -0
  558. package/src/primitives/Switch/Switch.stories.tsx +14 -0
  559. package/src/primitives/Switch/Switch.test.tsx +9 -0
  560. package/src/primitives/Switch/Switch.tsx +31 -0
  561. package/src/primitives/Switch/index.ts +2 -0
  562. package/src/primitives/Table/Table.stories.tsx +14 -0
  563. package/src/primitives/Table/Table.test.tsx +9 -0
  564. package/src/primitives/Table/Table.tsx +121 -0
  565. package/src/primitives/Table/index.ts +2 -0
  566. package/src/primitives/Tabs/Tabs.stories.tsx +14 -0
  567. package/src/primitives/Tabs/Tabs.test.tsx +9 -0
  568. package/src/primitives/Tabs/Tabs.tsx +53 -0
  569. package/src/primitives/Tabs/index.ts +2 -0
  570. package/src/primitives/Textarea/Textarea.stories.tsx +14 -0
  571. package/src/primitives/Textarea/Textarea.test.tsx +9 -0
  572. package/src/primitives/Textarea/Textarea.tsx +22 -0
  573. package/src/primitives/Textarea/index.ts +2 -0
  574. package/src/primitives/Toggle/Toggle.stories.tsx +14 -0
  575. package/src/primitives/Toggle/Toggle.test.tsx +9 -0
  576. package/src/primitives/Toggle/Toggle.tsx +44 -0
  577. package/src/primitives/Toggle/index.ts +2 -0
  578. package/src/primitives/ToggleGroup/ToggleGroup.stories.tsx +14 -0
  579. package/src/primitives/ToggleGroup/ToggleGroup.test.tsx +9 -0
  580. package/src/primitives/ToggleGroup/ToggleGroup.tsx +62 -0
  581. package/src/primitives/ToggleGroup/index.ts +2 -0
  582. package/src/primitives/Tooltip/Tooltip.stories.tsx +14 -0
  583. package/src/primitives/Tooltip/Tooltip.test.tsx +9 -0
  584. package/src/primitives/Tooltip/Tooltip.tsx +29 -0
  585. package/src/primitives/Tooltip/index.ts +2 -0
  586. package/src/primitives/accordion.tsx +56 -0
  587. package/src/primitives/alert-dialog.tsx +140 -0
  588. package/src/primitives/alert.tsx +60 -0
  589. package/src/primitives/aspect-ratio.tsx +6 -0
  590. package/src/primitives/avatar.tsx +100 -0
  591. package/src/primitives/badge.tsx +28 -0
  592. package/src/primitives/button.tsx +43 -0
  593. package/src/primitives/calendar.tsx +214 -0
  594. package/src/primitives/card.tsx +48 -0
  595. package/src/primitives/carousel.tsx +261 -0
  596. package/src/primitives/chart.tsx +368 -0
  597. package/src/primitives/checkbox.tsx +26 -0
  598. package/src/primitives/code-block.tsx +173 -0
  599. package/src/primitives/collapsible.tsx +12 -0
  600. package/src/primitives/command.tsx +154 -0
  601. package/src/primitives/comparison.tsx +184 -0
  602. package/src/primitives/context-menu.tsx +101 -0
  603. package/src/primitives/dialog.tsx +88 -0
  604. package/src/primitives/drawer.tsx +117 -0
  605. package/src/primitives/dropdown-menu.tsx +111 -0
  606. package/src/primitives/form.tsx +179 -0
  607. package/src/primitives/hover-card.tsx +30 -0
  608. package/src/primitives/input-otp.tsx +70 -0
  609. package/src/primitives/input.tsx +23 -0
  610. package/src/primitives/label.tsx +27 -0
  611. package/src/primitives/logo-carousel.tsx +110 -0
  612. package/src/primitives/marquee.tsx +84 -0
  613. package/src/primitives/menubar.tsx +255 -0
  614. package/src/primitives/navigation-menu.tsx +129 -0
  615. package/src/primitives/pagination.tsx +118 -0
  616. package/src/primitives/popover.tsx +29 -0
  617. package/src/primitives/progress.tsx +20 -0
  618. package/src/primitives/qr-code.tsx +89 -0
  619. package/src/primitives/radio.tsx +33 -0
  620. package/src/primitives/rating.tsx +157 -0
  621. package/src/primitives/resizable.tsx +43 -0
  622. package/src/primitives/scroll-area.tsx +49 -0
  623. package/src/primitives/select.tsx +137 -0
  624. package/src/primitives/separator.tsx +21 -0
  625. package/src/primitives/sheet.tsx +87 -0
  626. package/src/primitives/skeleton.tsx +11 -0
  627. package/src/primitives/slider.tsx +20 -0
  628. package/src/primitives/sonner.tsx +27 -0
  629. package/src/primitives/spinner.tsx +17 -0
  630. package/src/primitives/switch.tsx +30 -0
  631. package/src/primitives/table.tsx +121 -0
  632. package/src/primitives/tabs.tsx +53 -0
  633. package/src/primitives/textarea.tsx +22 -0
  634. package/src/primitives/texture-card.tsx +52 -0
  635. package/src/primitives/toggle-group.tsx +62 -0
  636. package/src/primitives/toggle.tsx +44 -0
  637. package/src/primitives/tooltip.tsx +28 -0
  638. package/src/primitives/utils/cn.ts +1 -0
  639. package/src/provider/otf-ui-provider.tsx +66 -0
  640. package/src/styles.css +6 -0
  641. package/src/text/AnimatedNumber.tsx +157 -0
  642. package/src/text/Body.tsx +47 -0
  643. package/src/text/Caption.tsx +32 -0
  644. package/src/text/Code.tsx +43 -0
  645. package/src/text/GradientHeading.tsx +90 -0
  646. package/src/text/Heading.tsx +44 -0
  647. package/src/text/TextReveal.tsx +96 -0
  648. package/src/text/Typewriter.tsx +107 -0
  649. package/src/text/index.ts +8 -0
  650. package/src/theme/ColorSchemeSelect.tsx +74 -0
  651. package/src/theme/ThemeSwitch.tsx +116 -0
  652. package/src/theme/index.ts +2 -0
  653. package/src/themes/base.css +25 -0
  654. package/src/themes/glass.css +142 -0
  655. package/src/themes/linear.css +123 -0
  656. package/src/themes/midnight.css +131 -0
  657. package/src/themes/minimal.css +121 -0
  658. package/src/utils/cn.ts +6 -0
@@ -0,0 +1,101 @@
1
+ import React from 'react'
2
+ import * as ContextMenuPrimitive from '@radix-ui/react-context-menu'
3
+ import { Check, ChevronRight, Circle } from 'lucide-react'
4
+ import { cn } from '../utils/cn'
5
+
6
+ export const ContextMenu = ContextMenuPrimitive.Root
7
+ export const ContextMenuTrigger = ContextMenuPrimitive.Trigger
8
+ export const ContextMenuGroup = ContextMenuPrimitive.Group
9
+ export const ContextMenuPortal = ContextMenuPrimitive.Portal
10
+ export const ContextMenuSub = ContextMenuPrimitive.Sub
11
+ export const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
12
+
13
+ const contentStyle = 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-1 text-[hsl(var(--popover-foreground))] shadow-md animate-in fade-in-80'
14
+ const itemStyle = 'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-[hsl(var(--accent))] focus:text-[hsl(var(--accent-foreground))] data-[disabled]:pointer-events-none data-[disabled]:opacity-50'
15
+
16
+ export const ContextMenuContent = React.forwardRef<
17
+ React.ElementRef<typeof ContextMenuPrimitive.Content>,
18
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
19
+ >(({ className, ...props }, ref) => (
20
+ <ContextMenuPrimitive.Portal>
21
+ <ContextMenuPrimitive.Content ref={ref} className={cn(contentStyle, className)} {...props} />
22
+ </ContextMenuPrimitive.Portal>
23
+ ))
24
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
25
+
26
+ export const ContextMenuItem = React.forwardRef<
27
+ React.ElementRef<typeof ContextMenuPrimitive.Item>,
28
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & { inset?: boolean }
29
+ >(({ className, inset, ...props }, ref) => (
30
+ <ContextMenuPrimitive.Item ref={ref} className={cn(itemStyle, inset && 'pl-8', className)} {...props} />
31
+ ))
32
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
33
+
34
+ export const ContextMenuCheckboxItem = React.forwardRef<
35
+ React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
36
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
37
+ >(({ className, children, checked, ...props }, ref) => (
38
+ <ContextMenuPrimitive.CheckboxItem ref={ref} className={cn(itemStyle, 'pl-8', className)} checked={checked} {...props}>
39
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
40
+ <ContextMenuPrimitive.ItemIndicator>
41
+ <Check className="h-4 w-4" />
42
+ </ContextMenuPrimitive.ItemIndicator>
43
+ </span>
44
+ {children}
45
+ </ContextMenuPrimitive.CheckboxItem>
46
+ ))
47
+ ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName
48
+
49
+ export const ContextMenuRadioItem = React.forwardRef<
50
+ React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
51
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
52
+ >(({ className, children, ...props }, ref) => (
53
+ <ContextMenuPrimitive.RadioItem ref={ref} className={cn(itemStyle, 'pl-8', className)} {...props}>
54
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
55
+ <ContextMenuPrimitive.ItemIndicator>
56
+ <Circle className="h-2 w-2 fill-current" />
57
+ </ContextMenuPrimitive.ItemIndicator>
58
+ </span>
59
+ {children}
60
+ </ContextMenuPrimitive.RadioItem>
61
+ ))
62
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
63
+
64
+ export const ContextMenuLabel = React.forwardRef<
65
+ React.ElementRef<typeof ContextMenuPrimitive.Label>,
66
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & { inset?: boolean }
67
+ >(({ className, inset, ...props }, ref) => (
68
+ <ContextMenuPrimitive.Label ref={ref} className={cn('px-2 py-1.5 text-xs font-semibold text-[hsl(var(--muted-foreground))]', inset && 'pl-8', className)} {...props} />
69
+ ))
70
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
71
+
72
+ export const ContextMenuSeparator = React.forwardRef<
73
+ React.ElementRef<typeof ContextMenuPrimitive.Separator>,
74
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
75
+ >(({ className, ...props }, ref) => (
76
+ <ContextMenuPrimitive.Separator ref={ref} className={cn('-mx-1 my-1 h-px bg-[hsl(var(--muted))]', className)} {...props} />
77
+ ))
78
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
79
+
80
+ export const ContextMenuSubTrigger = React.forwardRef<
81
+ React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
82
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & { inset?: boolean }
83
+ >(({ className, inset, children, ...props }, ref) => (
84
+ <ContextMenuPrimitive.SubTrigger ref={ref} className={cn(itemStyle, inset && 'pl-8', className)} {...props}>
85
+ {children}
86
+ <ChevronRight className="ml-auto h-4 w-4" />
87
+ </ContextMenuPrimitive.SubTrigger>
88
+ ))
89
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
90
+
91
+ export const ContextMenuSubContent = React.forwardRef<
92
+ React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
93
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
94
+ >(({ className, ...props }, ref) => (
95
+ <ContextMenuPrimitive.SubContent ref={ref} className={cn(contentStyle, className)} {...props} />
96
+ ))
97
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
98
+
99
+ export const ContextMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => (
100
+ <span className={cn('ml-auto text-xs tracking-widest opacity-60', className)} {...props} />
101
+ )
@@ -0,0 +1,2 @@
1
+ // @tier: stub — full checklist in Phase 3
2
+ export * from './ContextMenu'
@@ -0,0 +1,14 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { Dialog } from './Dialog'
3
+
4
+ // TODO: add all variants
5
+ const meta: Meta<typeof Dialog> = {
6
+ title: 'Primitives/Dialog',
7
+ component: Dialog,
8
+ tags: ['autodocs'],
9
+ }
10
+
11
+ export default meta
12
+ type Story = StoryObj<typeof Dialog>
13
+
14
+ export const Default: Story = {}
@@ -0,0 +1,9 @@
1
+ import { render } from '@testing-library/react'
2
+ import { Dialog } from './Dialog'
3
+
4
+ // TODO: add full a11y + variant tests
5
+ describe('Dialog', () => {
6
+ it('renders without throwing', () => {
7
+ expect(() => render(<Dialog />)).not.toThrow()
8
+ })
9
+ })
@@ -0,0 +1,88 @@
1
+ import React from 'react'
2
+ import * as DialogPrimitive from '@radix-ui/react-dialog'
3
+ import { X } from 'lucide-react'
4
+ import { cn } from '../utils/cn'
5
+
6
+ export const Dialog = DialogPrimitive.Root
7
+ export const DialogTrigger = DialogPrimitive.Trigger
8
+ export const DialogPortal = DialogPrimitive.Portal
9
+ export const DialogClose = DialogPrimitive.Close
10
+
11
+ export const DialogOverlay = React.forwardRef<
12
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
13
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
14
+ >(({ className, ...props }, ref) => (
15
+ <DialogPrimitive.Overlay
16
+ ref={ref}
17
+ className={cn(
18
+ 'fixed inset-0 z-50 bg-black/80',
19
+ 'data-[state=open]:animate-in data-[state=open]:fade-in-0',
20
+ 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0',
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ ))
26
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
27
+
28
+ export const DialogContent = React.forwardRef<
29
+ React.ElementRef<typeof DialogPrimitive.Content>,
30
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
31
+ >(({ className, children, ...props }, ref) => (
32
+ <DialogPortal>
33
+ <DialogOverlay />
34
+ <DialogPrimitive.Content
35
+ ref={ref}
36
+ className={cn(
37
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4',
38
+ 'bg-[hsl(var(--background))] p-6 shadow-lg duration-200 rounded-md',
39
+ 'border border-[hsl(var(--border))]',
40
+ 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]',
41
+ 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]',
42
+ className
43
+ )}
44
+ {...props}
45
+ >
46
+ {children}
47
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-[hsl(var(--background))] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[hsl(var(--ring))] focus:ring-offset-2 disabled:pointer-events-none">
48
+ <X className="h-4 w-4" />
49
+ <span className="sr-only">Close</span>
50
+ </DialogPrimitive.Close>
51
+ </DialogPrimitive.Content>
52
+ </DialogPortal>
53
+ ))
54
+ DialogContent.displayName = DialogPrimitive.Content.displayName
55
+
56
+ export const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
57
+ <div className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)} {...props} />
58
+ )
59
+ DialogHeader.displayName = 'DialogHeader'
60
+
61
+ export const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
62
+ <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)} {...props} />
63
+ )
64
+ DialogFooter.displayName = 'DialogFooter'
65
+
66
+ export const DialogTitle = React.forwardRef<
67
+ React.ElementRef<typeof DialogPrimitive.Title>,
68
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
69
+ >(({ className, ...props }, ref) => (
70
+ <DialogPrimitive.Title
71
+ ref={ref}
72
+ className={cn('text-lg font-semibold leading-none tracking-tight', className)}
73
+ {...props}
74
+ />
75
+ ))
76
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
77
+
78
+ export const DialogDescription = React.forwardRef<
79
+ React.ElementRef<typeof DialogPrimitive.Description>,
80
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
81
+ >(({ className, ...props }, ref) => (
82
+ <DialogPrimitive.Description
83
+ ref={ref}
84
+ className={cn('text-sm text-[hsl(var(--muted-foreground))]', className)}
85
+ {...props}
86
+ />
87
+ ))
88
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
@@ -0,0 +1,130 @@
1
+ 'use client'
2
+
3
+ import React, { useCallback, useEffect, useRef, useState } from 'react'
4
+ import {
5
+ Dialog,
6
+ DialogContent,
7
+ DialogDescription,
8
+ DialogFooter,
9
+ DialogHeader,
10
+ DialogTitle,
11
+ } from './Dialog'
12
+ import { cn } from '../utils/cn'
13
+
14
+ export type DialogType = 'confirm' | 'alert' | 'custom'
15
+
16
+ export interface DialogOptions {
17
+ type?: DialogType
18
+ title: string
19
+ description?: string
20
+ confirmLabel?: string
21
+ cancelLabel?: string
22
+ /** Danger mode — confirm button uses destructive variant */
23
+ destructive?: boolean
24
+ /** Custom content overrides description */
25
+ content?: React.ReactNode
26
+ /** Callback resolve — imperative API sets this internally */
27
+ resolve?: (value: boolean) => void
28
+ }
29
+
30
+ export interface DialogState extends DialogOptions {
31
+ open: boolean
32
+ id: string
33
+ }
34
+
35
+ /* ── Imperative singleton ─────────────────────────────────────── */
36
+ let _showDialog: (opts: DialogOptions) => Promise<boolean> = () =>
37
+ Promise.resolve(false)
38
+
39
+ export function showDialog(opts: DialogOptions): Promise<boolean> {
40
+ return _showDialog(opts)
41
+ }
42
+
43
+ /* ── Provider ────────────────────────────────────────────────── */
44
+ export function DialogProvider({ children }: { children: React.ReactNode }) {
45
+ const [state, setState] = useState<DialogState | null>(null)
46
+ const resolveRef = useRef<((v: boolean) => void) | null>(null)
47
+
48
+ useEffect(() => {
49
+ _showDialog = (opts: DialogOptions) => {
50
+ return new Promise<boolean>((resolve) => {
51
+ resolveRef.current = resolve
52
+ setState({
53
+ ...opts,
54
+ open: true,
55
+ type: opts.type ?? 'confirm',
56
+ id: String(Date.now()),
57
+ })
58
+ })
59
+ }
60
+ return () => {
61
+ _showDialog = () => Promise.resolve(false)
62
+ }
63
+ }, [])
64
+
65
+ const handleClose = useCallback((value: boolean) => {
66
+ setState((prev) => (prev ? { ...prev, open: false } : null))
67
+ resolveRef.current?.(value)
68
+ resolveRef.current = null
69
+ }, [])
70
+
71
+ const isAlert = state?.type === 'alert'
72
+
73
+ return (
74
+ <>
75
+ {children}
76
+ {state && (
77
+ <Dialog
78
+ open={state.open}
79
+ onOpenChange={(open) => {
80
+ if (!open) handleClose(false)
81
+ }}
82
+ >
83
+ <DialogContent className="max-w-sm">
84
+ <DialogHeader>
85
+ <DialogTitle>{state.title}</DialogTitle>
86
+ {state.description && (
87
+ <DialogDescription>{state.description}</DialogDescription>
88
+ )}
89
+ </DialogHeader>
90
+ {state.content && (
91
+ <div className="py-2">{state.content}</div>
92
+ )}
93
+ <DialogFooter className="gap-2 sm:gap-0">
94
+ {!isAlert && (
95
+ <button
96
+ type="button"
97
+ onClick={() => handleClose(false)}
98
+ className={cn(
99
+ 'inline-flex items-center justify-center rounded-md text-sm font-medium',
100
+ 'h-9 px-4 py-2 border border-border bg-transparent',
101
+ 'hover:bg-accent hover:text-accent-foreground',
102
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
103
+ 'transition-colors'
104
+ )}
105
+ >
106
+ {state.cancelLabel ?? 'Cancel'}
107
+ </button>
108
+ )}
109
+ <button
110
+ type="button"
111
+ onClick={() => handleClose(true)}
112
+ className={cn(
113
+ 'inline-flex items-center justify-center rounded-md text-sm font-medium',
114
+ 'h-9 px-4 py-2',
115
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
116
+ 'transition-colors',
117
+ state.destructive
118
+ ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90'
119
+ : 'bg-primary text-primary-foreground hover:bg-primary/90'
120
+ )}
121
+ >
122
+ {state.confirmLabel ?? (isAlert ? 'OK' : 'Confirm')}
123
+ </button>
124
+ </DialogFooter>
125
+ </DialogContent>
126
+ </Dialog>
127
+ )}
128
+ </>
129
+ )
130
+ }
@@ -0,0 +1,3 @@
1
+ // @tier: stub — full checklist in Phase 3
2
+ export * from './Dialog'
3
+ export * from './DialogProvider'
@@ -0,0 +1,14 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { Drawer } from './Drawer'
3
+
4
+ // TODO: add all variants
5
+ const meta: Meta<typeof Drawer> = {
6
+ title: 'Primitives/Drawer',
7
+ component: Drawer,
8
+ tags: ['autodocs'],
9
+ }
10
+
11
+ export default meta
12
+ type Story = StoryObj<typeof Drawer>
13
+
14
+ export const Default: Story = {}
@@ -0,0 +1,9 @@
1
+ import { render } from '@testing-library/react'
2
+ import { Drawer } from './Drawer'
3
+
4
+ // TODO: add full a11y + variant tests
5
+ describe('Drawer', () => {
6
+ it('renders without throwing', () => {
7
+ expect(() => render(<Drawer />)).not.toThrow()
8
+ })
9
+ })
@@ -0,0 +1,123 @@
1
+ // @ts-nocheck
2
+ import * as React from "react"
3
+ import { Drawer as DrawerPrimitive } from "vaul"
4
+
5
+ import { cn } from "../utils/cn"
6
+
7
+ const Drawer = ({
8
+ shouldScaleBackground = true,
9
+ ...props
10
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
11
+ <DrawerPrimitive.Root
12
+ shouldScaleBackground={shouldScaleBackground}
13
+ {...props}
14
+ />
15
+ )
16
+ Drawer.displayName = "Drawer"
17
+
18
+ const DrawerTrigger = DrawerPrimitive.Trigger
19
+
20
+ const DrawerPortal = DrawerPrimitive.Portal
21
+
22
+ const DrawerClose = DrawerPrimitive.Close
23
+
24
+ const DrawerOverlay = React.forwardRef<
25
+ React.ElementRef<typeof DrawerPrimitive.Overlay>,
26
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
27
+ >(({ className, ...props }, ref) => (
28
+ <DrawerPrimitive.Overlay
29
+ ref={ref}
30
+ data-slot="drawer-overlay"
31
+ className={cn("fixed inset-0 z-50 bg-black/80", className)}
32
+ {...props}
33
+ />
34
+ ))
35
+ DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
36
+
37
+ const DrawerContent = React.forwardRef<
38
+ React.ElementRef<typeof DrawerPrimitive.Content>,
39
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
40
+ >(({ className, children, ...props }, ref) => (
41
+ <DrawerPortal>
42
+ <DrawerOverlay />
43
+ <DrawerPrimitive.Content
44
+ ref={ref}
45
+ data-slot="drawer"
46
+ className={cn(
47
+ "fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
48
+ className
49
+ )}
50
+ {...props}
51
+ >
52
+ <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
53
+ {children}
54
+ </DrawerPrimitive.Content>
55
+ </DrawerPortal>
56
+ ))
57
+ DrawerContent.displayName = "DrawerContent"
58
+
59
+ const DrawerHeader = ({
60
+ className,
61
+ ...props
62
+ }: React.HTMLAttributes<HTMLDivElement>) => (
63
+ <div
64
+ data-slot="drawer-header"
65
+ className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
66
+ {...props}
67
+ />
68
+ )
69
+ DrawerHeader.displayName = "DrawerHeader"
70
+
71
+ const DrawerFooter = ({
72
+ className,
73
+ ...props
74
+ }: React.HTMLAttributes<HTMLDivElement>) => (
75
+ <div
76
+ data-slot="drawer-footer"
77
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
78
+ {...props}
79
+ />
80
+ )
81
+ DrawerFooter.displayName = "DrawerFooter"
82
+
83
+ const DrawerTitle = React.forwardRef<
84
+ React.ElementRef<typeof DrawerPrimitive.Title>,
85
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
86
+ >(({ className, ...props }, ref) => (
87
+ <DrawerPrimitive.Title
88
+ ref={ref}
89
+ data-slot="drawer-title"
90
+ className={cn(
91
+ "text-lg font-semibold leading-none tracking-tight",
92
+ className
93
+ )}
94
+ {...props}
95
+ />
96
+ ))
97
+ DrawerTitle.displayName = DrawerPrimitive.Title.displayName
98
+
99
+ const DrawerDescription = React.forwardRef<
100
+ React.ElementRef<typeof DrawerPrimitive.Description>,
101
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
102
+ >(({ className, ...props }, ref) => (
103
+ <DrawerPrimitive.Description
104
+ ref={ref}
105
+ data-slot="drawer-description"
106
+ className={cn("text-sm text-muted-foreground", className)}
107
+ {...props}
108
+ />
109
+ ))
110
+ DrawerDescription.displayName = DrawerPrimitive.Description.displayName
111
+
112
+ export {
113
+ Drawer,
114
+ DrawerPortal,
115
+ DrawerOverlay,
116
+ DrawerTrigger,
117
+ DrawerClose,
118
+ DrawerContent,
119
+ DrawerHeader,
120
+ DrawerFooter,
121
+ DrawerTitle,
122
+ DrawerDescription,
123
+ }
@@ -0,0 +1,2 @@
1
+ // @tier: stub — full checklist in Phase 3
2
+ export * from './Drawer'
@@ -0,0 +1,14 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { DropdownMenu } from './DropdownMenu'
3
+
4
+ // TODO: add all variants
5
+ const meta: Meta<typeof DropdownMenu> = {
6
+ title: 'Primitives/DropdownMenu',
7
+ component: DropdownMenu,
8
+ tags: ['autodocs'],
9
+ }
10
+
11
+ export default meta
12
+ type Story = StoryObj<typeof DropdownMenu>
13
+
14
+ export const Default: Story = {}
@@ -0,0 +1,9 @@
1
+ import { render } from '@testing-library/react'
2
+ import { DropdownMenu } from './DropdownMenu'
3
+
4
+ // TODO: add full a11y + variant tests
5
+ describe('DropdownMenu', () => {
6
+ it('renders without throwing', () => {
7
+ expect(() => render(<DropdownMenu />)).not.toThrow()
8
+ })
9
+ })
@@ -0,0 +1,111 @@
1
+ import React from 'react'
2
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
3
+ import { Check, ChevronRight, Circle } from 'lucide-react'
4
+ import { cn } from '../utils/cn'
5
+
6
+ export const DropdownMenu = DropdownMenuPrimitive.Root
7
+ export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
8
+ export const DropdownMenuGroup = DropdownMenuPrimitive.Group
9
+ export const DropdownMenuPortal = DropdownMenuPrimitive.Portal
10
+ export const DropdownMenuSub = DropdownMenuPrimitive.Sub
11
+ export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
12
+
13
+ const contentStyle = cn(
14
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--popover))] p-1 text-[hsl(var(--popover-foreground))] shadow-md',
15
+ 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
16
+ 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95'
17
+ )
18
+
19
+ const itemStyle = cn(
20
+ 'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors',
21
+ 'focus:bg-[hsl(var(--accent))] focus:text-[hsl(var(--accent-foreground))]',
22
+ 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50'
23
+ )
24
+
25
+ export const DropdownMenuContent = React.forwardRef<
26
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
27
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
28
+ >(({ className, sideOffset = 4, ...props }, ref) => (
29
+ <DropdownMenuPrimitive.Portal>
30
+ <DropdownMenuPrimitive.Content ref={ref} sideOffset={sideOffset} className={cn(contentStyle, className)} {...props} />
31
+ </DropdownMenuPrimitive.Portal>
32
+ ))
33
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
34
+
35
+ export const DropdownMenuItem = React.forwardRef<
36
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
37
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }
38
+ >(({ className, inset, ...props }, ref) => (
39
+ <DropdownMenuPrimitive.Item ref={ref} className={cn(itemStyle, inset && 'pl-8', className)} {...props} />
40
+ ))
41
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
42
+
43
+ export const DropdownMenuCheckboxItem = React.forwardRef<
44
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
45
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
46
+ >(({ className, children, checked, ...props }, ref) => (
47
+ <DropdownMenuPrimitive.CheckboxItem ref={ref} className={cn(itemStyle, 'pl-8', className)} checked={checked} {...props}>
48
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
49
+ <DropdownMenuPrimitive.ItemIndicator>
50
+ <Check className="h-4 w-4" />
51
+ </DropdownMenuPrimitive.ItemIndicator>
52
+ </span>
53
+ {children}
54
+ </DropdownMenuPrimitive.CheckboxItem>
55
+ ))
56
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName
57
+
58
+ export const DropdownMenuRadioItem = React.forwardRef<
59
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
60
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
61
+ >(({ className, children, ...props }, ref) => (
62
+ <DropdownMenuPrimitive.RadioItem ref={ref} className={cn(itemStyle, 'pl-8', className)} {...props}>
63
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
64
+ <DropdownMenuPrimitive.ItemIndicator>
65
+ <Circle className="h-2 w-2 fill-current" />
66
+ </DropdownMenuPrimitive.ItemIndicator>
67
+ </span>
68
+ {children}
69
+ </DropdownMenuPrimitive.RadioItem>
70
+ ))
71
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
72
+
73
+ export const DropdownMenuLabel = React.forwardRef<
74
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
75
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }
76
+ >(({ className, inset, ...props }, ref) => (
77
+ <DropdownMenuPrimitive.Label ref={ref} className={cn('px-2 py-1.5 text-xs font-semibold text-[hsl(var(--muted-foreground))]', inset && 'pl-8', className)} {...props} />
78
+ ))
79
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
80
+
81
+ export const DropdownMenuSeparator = React.forwardRef<
82
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
83
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
84
+ >(({ className, ...props }, ref) => (
85
+ <DropdownMenuPrimitive.Separator ref={ref} className={cn('-mx-1 my-1 h-px bg-[hsl(var(--muted))]', className)} {...props} />
86
+ ))
87
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
88
+
89
+ export const DropdownMenuSubTrigger = React.forwardRef<
90
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
91
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }
92
+ >(({ className, inset, children, ...props }, ref) => (
93
+ <DropdownMenuPrimitive.SubTrigger ref={ref} className={cn(itemStyle, inset && 'pl-8', 'data-[state=open]:bg-[hsl(var(--accent))]', className)} {...props}>
94
+ {children}
95
+ <ChevronRight className="ml-auto h-4 w-4" />
96
+ </DropdownMenuPrimitive.SubTrigger>
97
+ ))
98
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName
99
+
100
+ export const DropdownMenuSubContent = React.forwardRef<
101
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
102
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
103
+ >(({ className, ...props }, ref) => (
104
+ <DropdownMenuPrimitive.SubContent ref={ref} className={cn(contentStyle, className)} {...props} />
105
+ ))
106
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName
107
+
108
+ export const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => (
109
+ <span className={cn('ml-auto text-xs tracking-widest opacity-60', className)} {...props} />
110
+ )
111
+ DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
@@ -0,0 +1,2 @@
1
+ // @tier: stub — full checklist in Phase 3
2
+ export * from './DropdownMenu'
@@ -0,0 +1,14 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { Form } from './Form'
3
+
4
+ // TODO: add all variants
5
+ const meta: Meta<typeof Form> = {
6
+ title: 'Primitives/Form',
7
+ component: Form,
8
+ tags: ['autodocs'],
9
+ }
10
+
11
+ export default meta
12
+ type Story = StoryObj<typeof Form>
13
+
14
+ export const Default: Story = {}
@@ -0,0 +1,9 @@
1
+ import { render } from '@testing-library/react'
2
+ import { Form } from './Form'
3
+
4
+ // TODO: add full a11y + variant tests
5
+ describe('Form', () => {
6
+ it('renders without throwing', () => {
7
+ expect(() => render(<Form />)).not.toThrow()
8
+ })
9
+ })