@neynar/ui 0.1.1

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 (364) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/components/ui/accordion.d.ts +229 -0
  4. package/dist/components/ui/accordion.d.ts.map +1 -0
  5. package/dist/components/ui/alert-dialog.d.ts +247 -0
  6. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  7. package/dist/components/ui/alert.d.ts +187 -0
  8. package/dist/components/ui/alert.d.ts.map +1 -0
  9. package/dist/components/ui/aspect-ratio.d.ts +94 -0
  10. package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
  11. package/dist/components/ui/avatar.d.ts +244 -0
  12. package/dist/components/ui/avatar.d.ts.map +1 -0
  13. package/dist/components/ui/badge.d.ts +163 -0
  14. package/dist/components/ui/badge.d.ts.map +1 -0
  15. package/dist/components/ui/breadcrumb.d.ts +281 -0
  16. package/dist/components/ui/breadcrumb.d.ts.map +1 -0
  17. package/dist/components/ui/button.d.ts +129 -0
  18. package/dist/components/ui/button.d.ts.map +1 -0
  19. package/dist/components/ui/calendar.d.ts +169 -0
  20. package/dist/components/ui/calendar.d.ts.map +1 -0
  21. package/dist/components/ui/card.d.ts +365 -0
  22. package/dist/components/ui/card.d.ts.map +1 -0
  23. package/dist/components/ui/carousel.d.ts +369 -0
  24. package/dist/components/ui/carousel.d.ts.map +1 -0
  25. package/dist/components/ui/chart.d.ts +442 -0
  26. package/dist/components/ui/chart.d.ts.map +1 -0
  27. package/dist/components/ui/checkbox.d.ts +88 -0
  28. package/dist/components/ui/checkbox.d.ts.map +1 -0
  29. package/dist/components/ui/collapsible.d.ts +182 -0
  30. package/dist/components/ui/collapsible.d.ts.map +1 -0
  31. package/dist/components/ui/combobox.d.ts +270 -0
  32. package/dist/components/ui/combobox.d.ts.map +1 -0
  33. package/dist/components/ui/command.d.ts +355 -0
  34. package/dist/components/ui/command.d.ts.map +1 -0
  35. package/dist/components/ui/container.d.ts +102 -0
  36. package/dist/components/ui/container.d.ts.map +1 -0
  37. package/dist/components/ui/context-menu.d.ts +339 -0
  38. package/dist/components/ui/context-menu.d.ts.map +1 -0
  39. package/dist/components/ui/date-picker.d.ts +145 -0
  40. package/dist/components/ui/date-picker.d.ts.map +1 -0
  41. package/dist/components/ui/dialog.d.ts +322 -0
  42. package/dist/components/ui/dialog.d.ts.map +1 -0
  43. package/dist/components/ui/drawer.d.ts +154 -0
  44. package/dist/components/ui/drawer.d.ts.map +1 -0
  45. package/dist/components/ui/dropdown-menu.d.ts +349 -0
  46. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  47. package/dist/components/ui/empty-state.d.ts +133 -0
  48. package/dist/components/ui/empty-state.d.ts.map +1 -0
  49. package/dist/components/ui/hover-card.d.ts +109 -0
  50. package/dist/components/ui/hover-card.d.ts.map +1 -0
  51. package/dist/components/ui/input.d.ts +89 -0
  52. package/dist/components/ui/input.d.ts.map +1 -0
  53. package/dist/components/ui/label.d.ts +93 -0
  54. package/dist/components/ui/label.d.ts.map +1 -0
  55. package/dist/components/ui/menubar.d.ts +306 -0
  56. package/dist/components/ui/menubar.d.ts.map +1 -0
  57. package/dist/components/ui/navigation-menu.d.ts +318 -0
  58. package/dist/components/ui/navigation-menu.d.ts.map +1 -0
  59. package/dist/components/ui/pagination.d.ts +343 -0
  60. package/dist/components/ui/pagination.d.ts.map +1 -0
  61. package/dist/components/ui/popover.d.ts +178 -0
  62. package/dist/components/ui/popover.d.ts.map +1 -0
  63. package/dist/components/ui/progress.d.ts +64 -0
  64. package/dist/components/ui/progress.d.ts.map +1 -0
  65. package/dist/components/ui/radio-group.d.ts +144 -0
  66. package/dist/components/ui/radio-group.d.ts.map +1 -0
  67. package/dist/components/ui/resizable.d.ts +164 -0
  68. package/dist/components/ui/resizable.d.ts.map +1 -0
  69. package/dist/components/ui/scroll-area.d.ts +82 -0
  70. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  71. package/dist/components/ui/select.d.ts +316 -0
  72. package/dist/components/ui/select.d.ts.map +1 -0
  73. package/dist/components/ui/separator.d.ts +80 -0
  74. package/dist/components/ui/separator.d.ts.map +1 -0
  75. package/dist/components/ui/sheet.d.ts +346 -0
  76. package/dist/components/ui/sheet.d.ts.map +1 -0
  77. package/dist/components/ui/sidebar.d.ts +1561 -0
  78. package/dist/components/ui/sidebar.d.ts.map +1 -0
  79. package/dist/components/ui/skeleton.d.ts +66 -0
  80. package/dist/components/ui/skeleton.d.ts.map +1 -0
  81. package/dist/components/ui/slider.d.ts +95 -0
  82. package/dist/components/ui/slider.d.ts.map +1 -0
  83. package/dist/components/ui/sonner.d.ts +101 -0
  84. package/dist/components/ui/sonner.d.ts.map +1 -0
  85. package/dist/components/ui/stack.d.ts +192 -0
  86. package/dist/components/ui/stack.d.ts.map +1 -0
  87. package/dist/components/ui/stories/accordion.stories.d.ts +71 -0
  88. package/dist/components/ui/stories/accordion.stories.d.ts.map +1 -0
  89. package/dist/components/ui/stories/alert-dialog.stories.d.ts +39 -0
  90. package/dist/components/ui/stories/alert-dialog.stories.d.ts.map +1 -0
  91. package/dist/components/ui/stories/alert.stories.d.ts +48 -0
  92. package/dist/components/ui/stories/alert.stories.d.ts.map +1 -0
  93. package/dist/components/ui/stories/aspect-ratio.stories.d.ts +53 -0
  94. package/dist/components/ui/stories/aspect-ratio.stories.d.ts.map +1 -0
  95. package/dist/components/ui/stories/avatar.stories.d.ts +49 -0
  96. package/dist/components/ui/stories/avatar.stories.d.ts.map +1 -0
  97. package/dist/components/ui/stories/badge.stories.d.ts +64 -0
  98. package/dist/components/ui/stories/badge.stories.d.ts.map +1 -0
  99. package/dist/components/ui/stories/breadcrumb.stories.d.ts +27 -0
  100. package/dist/components/ui/stories/breadcrumb.stories.d.ts.map +1 -0
  101. package/dist/components/ui/stories/button.stories.d.ts +92 -0
  102. package/dist/components/ui/stories/button.stories.d.ts.map +1 -0
  103. package/dist/components/ui/stories/calendar.stories.d.ts +94 -0
  104. package/dist/components/ui/stories/calendar.stories.d.ts.map +1 -0
  105. package/dist/components/ui/stories/card.stories.d.ts +29 -0
  106. package/dist/components/ui/stories/card.stories.d.ts.map +1 -0
  107. package/dist/components/ui/stories/carousel.stories.d.ts +42 -0
  108. package/dist/components/ui/stories/carousel.stories.d.ts.map +1 -0
  109. package/dist/components/ui/stories/chart.stories.d.ts +51 -0
  110. package/dist/components/ui/stories/chart.stories.d.ts.map +1 -0
  111. package/dist/components/ui/stories/checkbox.stories.d.ts +72 -0
  112. package/dist/components/ui/stories/checkbox.stories.d.ts.map +1 -0
  113. package/dist/components/ui/stories/cn.stories.d.ts +19 -0
  114. package/dist/components/ui/stories/cn.stories.d.ts.map +1 -0
  115. package/dist/components/ui/stories/collapsible.stories.d.ts +51 -0
  116. package/dist/components/ui/stories/collapsible.stories.d.ts.map +1 -0
  117. package/dist/components/ui/stories/colors.stories.d.ts +31 -0
  118. package/dist/components/ui/stories/colors.stories.d.ts.map +1 -0
  119. package/dist/components/ui/stories/combobox.stories.d.ts +89 -0
  120. package/dist/components/ui/stories/combobox.stories.d.ts.map +1 -0
  121. package/dist/components/ui/stories/command.stories.d.ts +69 -0
  122. package/dist/components/ui/stories/command.stories.d.ts.map +1 -0
  123. package/dist/components/ui/stories/container.stories.d.ts +42 -0
  124. package/dist/components/ui/stories/container.stories.d.ts.map +1 -0
  125. package/dist/components/ui/stories/context-menu.stories.d.ts +32 -0
  126. package/dist/components/ui/stories/context-menu.stories.d.ts.map +1 -0
  127. package/dist/components/ui/stories/date-picker.stories.d.ts +67 -0
  128. package/dist/components/ui/stories/date-picker.stories.d.ts.map +1 -0
  129. package/dist/components/ui/stories/dialog.stories.d.ts +48 -0
  130. package/dist/components/ui/stories/dialog.stories.d.ts.map +1 -0
  131. package/dist/components/ui/stories/drawer.stories.d.ts +33 -0
  132. package/dist/components/ui/stories/drawer.stories.d.ts.map +1 -0
  133. package/dist/components/ui/stories/dropdown-menu.stories.d.ts +31 -0
  134. package/dist/components/ui/stories/dropdown-menu.stories.d.ts.map +1 -0
  135. package/dist/components/ui/stories/empty-state.stories.d.ts +74 -0
  136. package/dist/components/ui/stories/empty-state.stories.d.ts.map +1 -0
  137. package/dist/components/ui/stories/hover-card.stories.d.ts +35 -0
  138. package/dist/components/ui/stories/hover-card.stories.d.ts.map +1 -0
  139. package/dist/components/ui/stories/input.stories.d.ts +69 -0
  140. package/dist/components/ui/stories/input.stories.d.ts.map +1 -0
  141. package/dist/components/ui/stories/label.stories.d.ts +47 -0
  142. package/dist/components/ui/stories/label.stories.d.ts.map +1 -0
  143. package/dist/components/ui/stories/menubar.stories.d.ts +39 -0
  144. package/dist/components/ui/stories/menubar.stories.d.ts.map +1 -0
  145. package/dist/components/ui/stories/navigation-menu.stories.d.ts +44 -0
  146. package/dist/components/ui/stories/navigation-menu.stories.d.ts.map +1 -0
  147. package/dist/components/ui/stories/pagination.stories.d.ts +33 -0
  148. package/dist/components/ui/stories/pagination.stories.d.ts.map +1 -0
  149. package/dist/components/ui/stories/popover.stories.d.ts +36 -0
  150. package/dist/components/ui/stories/popover.stories.d.ts.map +1 -0
  151. package/dist/components/ui/stories/progress.stories.d.ts +38 -0
  152. package/dist/components/ui/stories/progress.stories.d.ts.map +1 -0
  153. package/dist/components/ui/stories/radio-group.stories.d.ts +76 -0
  154. package/dist/components/ui/stories/radio-group.stories.d.ts.map +1 -0
  155. package/dist/components/ui/stories/resizable.stories.d.ts +49 -0
  156. package/dist/components/ui/stories/resizable.stories.d.ts.map +1 -0
  157. package/dist/components/ui/stories/scroll-area.stories.d.ts +35 -0
  158. package/dist/components/ui/stories/scroll-area.stories.d.ts.map +1 -0
  159. package/dist/components/ui/stories/select.stories.d.ts +51 -0
  160. package/dist/components/ui/stories/select.stories.d.ts.map +1 -0
  161. package/dist/components/ui/stories/separator.stories.d.ts +58 -0
  162. package/dist/components/ui/stories/separator.stories.d.ts.map +1 -0
  163. package/dist/components/ui/stories/sheet.stories.d.ts +43 -0
  164. package/dist/components/ui/stories/sheet.stories.d.ts.map +1 -0
  165. package/dist/components/ui/stories/sidebar.stories.d.ts +60 -0
  166. package/dist/components/ui/stories/sidebar.stories.d.ts.map +1 -0
  167. package/dist/components/ui/stories/skeleton.stories.d.ts +42 -0
  168. package/dist/components/ui/stories/skeleton.stories.d.ts.map +1 -0
  169. package/dist/components/ui/stories/slider.stories.d.ts +99 -0
  170. package/dist/components/ui/stories/slider.stories.d.ts.map +1 -0
  171. package/dist/components/ui/stories/sonner.stories.d.ts +9 -0
  172. package/dist/components/ui/stories/sonner.stories.d.ts.map +1 -0
  173. package/dist/components/ui/stories/stack.stories.d.ts +39 -0
  174. package/dist/components/ui/stories/stack.stories.d.ts.map +1 -0
  175. package/dist/components/ui/stories/switch.stories.d.ts +71 -0
  176. package/dist/components/ui/stories/switch.stories.d.ts.map +1 -0
  177. package/dist/components/ui/stories/table.stories.d.ts +40 -0
  178. package/dist/components/ui/stories/table.stories.d.ts.map +1 -0
  179. package/dist/components/ui/stories/tabs.stories.d.ts +62 -0
  180. package/dist/components/ui/stories/tabs.stories.d.ts.map +1 -0
  181. package/dist/components/ui/stories/text-field.stories.d.ts +78 -0
  182. package/dist/components/ui/stories/text-field.stories.d.ts.map +1 -0
  183. package/dist/components/ui/stories/textarea.stories.d.ts +57 -0
  184. package/dist/components/ui/stories/textarea.stories.d.ts.map +1 -0
  185. package/dist/components/ui/stories/theme-toggle.stories.d.ts +71 -0
  186. package/dist/components/ui/stories/theme-toggle.stories.d.ts.map +1 -0
  187. package/dist/components/ui/stories/theme.stories.d.ts +51 -0
  188. package/dist/components/ui/stories/theme.stories.d.ts.map +1 -0
  189. package/dist/components/ui/stories/toggle-group.stories.d.ts +71 -0
  190. package/dist/components/ui/stories/toggle-group.stories.d.ts.map +1 -0
  191. package/dist/components/ui/stories/toggle.stories.d.ts +78 -0
  192. package/dist/components/ui/stories/toggle.stories.d.ts.map +1 -0
  193. package/dist/components/ui/stories/tooltip.stories.d.ts +37 -0
  194. package/dist/components/ui/stories/tooltip.stories.d.ts.map +1 -0
  195. package/dist/components/ui/stories/typography.stories.d.ts +137 -0
  196. package/dist/components/ui/stories/typography.stories.d.ts.map +1 -0
  197. package/dist/components/ui/stories/use-mobile.stories.d.ts +20 -0
  198. package/dist/components/ui/stories/use-mobile.stories.d.ts.map +1 -0
  199. package/dist/components/ui/stories/use-theme.stories.d.ts +23 -0
  200. package/dist/components/ui/stories/use-theme.stories.d.ts.map +1 -0
  201. package/dist/components/ui/switch.d.ts +84 -0
  202. package/dist/components/ui/switch.d.ts.map +1 -0
  203. package/dist/components/ui/table.d.ts +321 -0
  204. package/dist/components/ui/table.d.ts.map +1 -0
  205. package/dist/components/ui/tabs.d.ts +260 -0
  206. package/dist/components/ui/tabs.d.ts.map +1 -0
  207. package/dist/components/ui/text-field.d.ts +157 -0
  208. package/dist/components/ui/text-field.d.ts.map +1 -0
  209. package/dist/components/ui/textarea.d.ts +84 -0
  210. package/dist/components/ui/textarea.d.ts.map +1 -0
  211. package/dist/components/ui/theme-toggle.d.ts +105 -0
  212. package/dist/components/ui/theme-toggle.d.ts.map +1 -0
  213. package/dist/components/ui/theme.d.ts +110 -0
  214. package/dist/components/ui/theme.d.ts.map +1 -0
  215. package/dist/components/ui/toggle-group.d.ts +133 -0
  216. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  217. package/dist/components/ui/toggle.d.ts +84 -0
  218. package/dist/components/ui/toggle.d.ts.map +1 -0
  219. package/dist/components/ui/tooltip.d.ts +202 -0
  220. package/dist/components/ui/tooltip.d.ts.map +1 -0
  221. package/dist/components/ui/typography.d.ts +287 -0
  222. package/dist/components/ui/typography.d.ts.map +1 -0
  223. package/dist/hooks/use-mobile.d.ts +74 -0
  224. package/dist/hooks/use-mobile.d.ts.map +1 -0
  225. package/dist/hooks/use-theme.d.ts +142 -0
  226. package/dist/hooks/use-theme.d.ts.map +1 -0
  227. package/dist/index.d.ts +57 -0
  228. package/dist/index.d.ts.map +1 -0
  229. package/dist/index.js +27498 -0
  230. package/dist/index.js.map +1 -0
  231. package/dist/lib/utils.d.ts +43 -0
  232. package/dist/lib/utils.d.ts.map +1 -0
  233. package/dist/tsconfig.tsbuildinfo +1 -0
  234. package/docs/llm/colors.md +273 -0
  235. package/docs/llm/components/buttons.md +68 -0
  236. package/docs/llm/components/cards.md +53 -0
  237. package/docs/llm/components/display.md +134 -0
  238. package/docs/llm/components/feedback.md +96 -0
  239. package/docs/llm/components/forms.md +90 -0
  240. package/docs/llm/components/layout.md +59 -0
  241. package/docs/llm/components/menus.md +70 -0
  242. package/docs/llm/components/navigation.md +80 -0
  243. package/docs/llm/components/overlays.md +83 -0
  244. package/docs/llm/components/tables.md +73 -0
  245. package/docs/llm/components/typography.md +199 -0
  246. package/docs/llm/components/utilities.md +114 -0
  247. package/docs/llm/guide.md +165 -0
  248. package/llms.txt +122 -0
  249. package/package.json +104 -0
  250. package/src/components/ui/accordion.tsx +285 -0
  251. package/src/components/ui/alert-dialog.tsx +387 -0
  252. package/src/components/ui/alert.tsx +243 -0
  253. package/src/components/ui/aspect-ratio.tsx +99 -0
  254. package/src/components/ui/avatar.tsx +288 -0
  255. package/src/components/ui/badge.tsx +205 -0
  256. package/src/components/ui/breadcrumb.tsx +378 -0
  257. package/src/components/ui/button.tsx +195 -0
  258. package/src/components/ui/calendar.tsx +371 -0
  259. package/src/components/ui/card.tsx +447 -0
  260. package/src/components/ui/carousel.tsx +624 -0
  261. package/src/components/ui/chart.tsx +802 -0
  262. package/src/components/ui/checkbox.tsx +113 -0
  263. package/src/components/ui/collapsible.tsx +207 -0
  264. package/src/components/ui/combobox.tsx +373 -0
  265. package/src/components/ui/command.tsx +518 -0
  266. package/src/components/ui/container.tsx +114 -0
  267. package/src/components/ui/context-menu.tsx +563 -0
  268. package/src/components/ui/date-picker.tsx +213 -0
  269. package/src/components/ui/dialog.tsx +447 -0
  270. package/src/components/ui/drawer.tsx +273 -0
  271. package/src/components/ui/dropdown-menu.tsx +578 -0
  272. package/src/components/ui/empty-state.tsx +145 -0
  273. package/src/components/ui/hover-card.tsx +144 -0
  274. package/src/components/ui/input.tsx +106 -0
  275. package/src/components/ui/label.tsx +110 -0
  276. package/src/components/ui/menubar.tsx +553 -0
  277. package/src/components/ui/navigation-menu.tsx +471 -0
  278. package/src/components/ui/pagination.tsx +456 -0
  279. package/src/components/ui/popover.tsx +216 -0
  280. package/src/components/ui/progress.tsx +88 -0
  281. package/src/components/ui/radio-group.tsx +183 -0
  282. package/src/components/ui/resizable.tsx +209 -0
  283. package/src/components/ui/scroll-area.tsx +132 -0
  284. package/src/components/ui/select.tsx +485 -0
  285. package/src/components/ui/separator.tsx +101 -0
  286. package/src/components/ui/sheet.tsx +495 -0
  287. package/src/components/ui/sidebar.tsx +2211 -0
  288. package/src/components/ui/skeleton.tsx +76 -0
  289. package/src/components/ui/slider.tsx +147 -0
  290. package/src/components/ui/sonner.tsx +120 -0
  291. package/src/components/ui/stack.tsx +180 -0
  292. package/src/components/ui/stories/accordion.stories.tsx +429 -0
  293. package/src/components/ui/stories/alert-dialog.stories.tsx +519 -0
  294. package/src/components/ui/stories/alert.stories.tsx +228 -0
  295. package/src/components/ui/stories/aspect-ratio.stories.tsx +200 -0
  296. package/src/components/ui/stories/avatar.stories.tsx +317 -0
  297. package/src/components/ui/stories/badge.stories.tsx +260 -0
  298. package/src/components/ui/stories/breadcrumb.stories.tsx +482 -0
  299. package/src/components/ui/stories/button.stories.tsx +266 -0
  300. package/src/components/ui/stories/calendar.stories.tsx +375 -0
  301. package/src/components/ui/stories/card.stories.tsx +308 -0
  302. package/src/components/ui/stories/carousel.stories.tsx +328 -0
  303. package/src/components/ui/stories/chart.stories.tsx +430 -0
  304. package/src/components/ui/stories/checkbox.stories.tsx +297 -0
  305. package/src/components/ui/stories/cn.stories.tsx +433 -0
  306. package/src/components/ui/stories/collapsible.stories.tsx +256 -0
  307. package/src/components/ui/stories/colors.stories.tsx +502 -0
  308. package/src/components/ui/stories/combobox.stories.tsx +301 -0
  309. package/src/components/ui/stories/command.stories.tsx +632 -0
  310. package/src/components/ui/stories/container.stories.tsx +250 -0
  311. package/src/components/ui/stories/context-menu.stories.tsx +446 -0
  312. package/src/components/ui/stories/date-picker.stories.tsx +378 -0
  313. package/src/components/ui/stories/dialog.stories.tsx +535 -0
  314. package/src/components/ui/stories/drawer.stories.tsx +364 -0
  315. package/src/components/ui/stories/dropdown-menu.stories.tsx +374 -0
  316. package/src/components/ui/stories/empty-state.stories.tsx +244 -0
  317. package/src/components/ui/stories/hover-card.stories.tsx +355 -0
  318. package/src/components/ui/stories/input.stories.tsx +289 -0
  319. package/src/components/ui/stories/label.stories.tsx +294 -0
  320. package/src/components/ui/stories/menubar.stories.tsx +764 -0
  321. package/src/components/ui/stories/navigation-menu.stories.tsx +539 -0
  322. package/src/components/ui/stories/pagination.stories.tsx +604 -0
  323. package/src/components/ui/stories/popover.stories.tsx +392 -0
  324. package/src/components/ui/stories/progress.stories.tsx +218 -0
  325. package/src/components/ui/stories/radio-group.stories.tsx +400 -0
  326. package/src/components/ui/stories/resizable.stories.tsx +417 -0
  327. package/src/components/ui/stories/scroll-area.stories.tsx +180 -0
  328. package/src/components/ui/stories/select.stories.tsx +389 -0
  329. package/src/components/ui/stories/separator.stories.tsx +192 -0
  330. package/src/components/ui/stories/sheet.stories.tsx +468 -0
  331. package/src/components/ui/stories/sidebar.stories.tsx +731 -0
  332. package/src/components/ui/stories/skeleton.stories.tsx +216 -0
  333. package/src/components/ui/stories/slider.stories.tsx +321 -0
  334. package/src/components/ui/stories/sonner.stories.tsx +373 -0
  335. package/src/components/ui/stories/stack.stories.tsx +222 -0
  336. package/src/components/ui/stories/switch.stories.tsx +202 -0
  337. package/src/components/ui/stories/table.stories.tsx +541 -0
  338. package/src/components/ui/stories/tabs.stories.tsx +544 -0
  339. package/src/components/ui/stories/text-field.stories.tsx +280 -0
  340. package/src/components/ui/stories/textarea.stories.tsx +245 -0
  341. package/src/components/ui/stories/theme-toggle.stories.tsx +275 -0
  342. package/src/components/ui/stories/theme.stories.tsx +412 -0
  343. package/src/components/ui/stories/toggle-group.stories.tsx +337 -0
  344. package/src/components/ui/stories/toggle.stories.tsx +325 -0
  345. package/src/components/ui/stories/tooltip.stories.tsx +444 -0
  346. package/src/components/ui/stories/typography.stories.tsx +1586 -0
  347. package/src/components/ui/stories/use-mobile.stories.tsx +420 -0
  348. package/src/components/ui/stories/use-theme.stories.tsx +531 -0
  349. package/src/components/ui/switch.tsx +106 -0
  350. package/src/components/ui/table.tsx +424 -0
  351. package/src/components/ui/tabs.tsx +316 -0
  352. package/src/components/ui/text-field.tsx +206 -0
  353. package/src/components/ui/textarea.tsx +98 -0
  354. package/src/components/ui/theme-toggle.tsx +185 -0
  355. package/src/components/ui/theme.tsx +148 -0
  356. package/src/components/ui/toggle-group.tsx +196 -0
  357. package/src/components/ui/toggle.tsx +115 -0
  358. package/src/components/ui/tooltip.tsx +253 -0
  359. package/src/components/ui/typography.tsx +468 -0
  360. package/src/hooks/use-mobile.ts +91 -0
  361. package/src/hooks/use-theme.ts +319 -0
  362. package/src/index.ts +77 -0
  363. package/src/lib/utils.ts +57 -0
  364. package/src/styles/globals.css +160 -0
@@ -0,0 +1,2211 @@
1
+ import * as React from "react";
2
+ import { useCallback } from "react";
3
+ import { Slot } from "@radix-ui/react-slot";
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+ import { PanelLeftIcon } from "lucide-react";
6
+
7
+ import { useIsMobile } from "@/hooks/use-mobile";
8
+ import { cn } from "@/lib/utils";
9
+ import { Button } from "@/components/ui/button";
10
+ import { Input } from "@/components/ui/input";
11
+ import { Separator } from "@/components/ui/separator";
12
+ import {
13
+ Sheet,
14
+ SheetContent,
15
+ SheetDescription,
16
+ SheetHeader,
17
+ SheetTitle,
18
+ } from "@/components/ui/sheet";
19
+ import { Skeleton } from "@/components/ui/skeleton";
20
+ import {
21
+ Tooltip,
22
+ TooltipContent,
23
+ TooltipProvider,
24
+ TooltipTrigger,
25
+ } from "@/components/ui/tooltip";
26
+
27
+ const SIDEBAR_COOKIE_NAME = "sidebar_state";
28
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
29
+ const SIDEBAR_WIDTH = "16rem";
30
+ const SIDEBAR_WIDTH_MOBILE = "18rem";
31
+ const SIDEBAR_WIDTH_ICON = "3rem";
32
+ const SIDEBAR_KEYBOARD_SHORTCUT = "b";
33
+
34
+ type SidebarContextProps = {
35
+ state: "expanded" | "collapsed";
36
+ open: boolean;
37
+ setOpen: (open: boolean) => void;
38
+ openMobile: boolean;
39
+ setOpenMobile: (open: boolean) => void;
40
+ isMobile: boolean;
41
+ toggleSidebar: () => void;
42
+ };
43
+
44
+ const SidebarContext = React.createContext<SidebarContextProps | null>(null);
45
+
46
+ /**
47
+ * Hook to access sidebar state and control functions
48
+ *
49
+ * Provides access to the sidebar's state management including expanded/collapsed states,
50
+ * mobile-specific behavior, and toggle functions. This hook must be used within a
51
+ * SidebarProvider component tree to function properly.
52
+ *
53
+ * @returns {SidebarContextProps} Object containing sidebar state and control functions:
54
+ * - `state`: "expanded" | "collapsed" - Current sidebar state
55
+ * - `open`: boolean - Whether sidebar is open (desktop)
56
+ * - `setOpen`: (open: boolean) => void - Function to control sidebar open state
57
+ * - `openMobile`: boolean - Whether sidebar is open on mobile
58
+ * - `setOpenMobile`: (open: boolean) => void - Function to control mobile sidebar state
59
+ * - `isMobile`: boolean - Whether current viewport is considered mobile
60
+ * - `toggleSidebar`: () => void - Function to toggle sidebar state
61
+ *
62
+ * @throws {Error} When used outside of SidebarProvider context
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * // Basic usage for toggle button
67
+ * function ToggleButton() {
68
+ * const { state, toggleSidebar } = useSidebar()
69
+ * return (
70
+ * <button onClick={toggleSidebar}>
71
+ * {state === "expanded" ? "Collapse" : "Expand"}
72
+ * </button>
73
+ * )
74
+ * }
75
+ * ```
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * // Conditional rendering based on state
80
+ * function ConditionalContent() {
81
+ * const { state, isMobile } = useSidebar()
82
+ * if (isMobile) return <MobileOnlyContent />
83
+ * return state === "expanded" ? <FullContent /> : <CompactContent />
84
+ * }
85
+ * ```
86
+ *
87
+ * @see {@link SidebarProvider} - Required context provider
88
+ * @since 1.0.0
89
+ */
90
+ function useSidebar() {
91
+ const context = React.useContext(SidebarContext);
92
+ if (!context) {
93
+ throw new Error("useSidebar must be used within a SidebarProvider.");
94
+ }
95
+
96
+ return context;
97
+ }
98
+
99
+ /**
100
+ * Context provider for comprehensive sidebar state management
101
+ *
102
+ * The SidebarProvider is the foundational component that manages all sidebar behavior
103
+ * including state persistence, responsive design, keyboard shortcuts, and mobile handling.
104
+ * It provides context to all sidebar-related components and should wrap your entire
105
+ * application or the section containing the sidebar.
106
+ *
107
+ * @component
108
+ *
109
+ * @param {boolean} [defaultOpen=true] - Initial open state when uncontrolled
110
+ * @param {boolean} [open] - Controlled open state (makes component controlled)
111
+ * @param {(open: boolean) => void} [onOpenChange] - Callback for open state changes
112
+ * @param {string} [className] - Additional CSS classes for wrapper
113
+ * @param {React.CSSProperties} [style] - Inline styles including CSS variables
114
+ * @param {React.ReactNode} children - Child components
115
+ *
116
+ * @example
117
+ * ```tsx
118
+ * // Basic uncontrolled usage
119
+ * <SidebarProvider>
120
+ * <Sidebar />
121
+ * <SidebarInset>
122
+ * <main>Your content</main>
123
+ * </SidebarInset>
124
+ * </SidebarProvider>
125
+ * ```
126
+ *
127
+ * @example
128
+ * ```tsx
129
+ * // Controlled usage with custom state
130
+ * function App() {
131
+ * const [sidebarOpen, setSidebarOpen] = useState(false)
132
+ * return (
133
+ * <SidebarProvider open={sidebarOpen} onOpenChange={setSidebarOpen}>
134
+ * <Sidebar />
135
+ * <SidebarInset>Content</SidebarInset>
136
+ * </SidebarProvider>
137
+ * )
138
+ * }
139
+ * ```
140
+ *
141
+ * @example
142
+ * ```tsx
143
+ * // Custom width with CSS variables
144
+ * <SidebarProvider
145
+ * style={{
146
+ * "--sidebar-width": "20rem",
147
+ * "--sidebar-width-mobile": "18rem"
148
+ * }}
149
+ * >
150
+ * <Sidebar />
151
+ * </SidebarProvider>
152
+ * ```
153
+ *
154
+ * @features
155
+ * - State persistence via cookies
156
+ * - Keyboard shortcut (Cmd/Ctrl+B) support
157
+ * - Responsive mobile behavior
158
+ * - CSS variable-based theming
159
+ * - Tooltip provider integration
160
+ *
161
+ * @accessibility
162
+ * - Keyboard shortcuts for power users
163
+ * - Mobile-optimized touch interactions
164
+ * - Focus management for modal-like mobile behavior
165
+ *
166
+ * @see {@link useSidebar} - Hook to access provided context
167
+ * @see {@link Sidebar} - Main sidebar component
168
+ * @since 1.0.0
169
+ */
170
+ function SidebarProvider({
171
+ defaultOpen = true,
172
+ open: openProp,
173
+ onOpenChange: setOpenProp,
174
+ className,
175
+ style,
176
+ children,
177
+ ...props
178
+ }: React.ComponentProps<"div"> & {
179
+ defaultOpen?: boolean;
180
+ open?: boolean;
181
+ onOpenChange?: (open: boolean) => void;
182
+ }) {
183
+ const isMobile = useIsMobile();
184
+ const [openMobile, setOpenMobile] = React.useState(false);
185
+
186
+ // This is the internal state of the sidebar.
187
+ // We use openProp and setOpenProp for control from outside the component.
188
+ const [_open, _setOpen] = React.useState(defaultOpen);
189
+ const open = openProp ?? _open;
190
+ const setOpen = useCallback(
191
+ (value: boolean | ((value: boolean) => boolean)) => {
192
+ const openState = typeof value === "function" ? value(open) : value;
193
+ if (setOpenProp) {
194
+ setOpenProp(openState);
195
+ } else {
196
+ _setOpen(openState);
197
+ }
198
+
199
+ // This sets the cookie to keep the sidebar state.
200
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
201
+ },
202
+ [setOpenProp, _setOpen, open],
203
+ );
204
+
205
+ // Helper to toggle the sidebar.
206
+ const toggleSidebar = useCallback(() => {
207
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
208
+ }, [isMobile, setOpenMobile, setOpen]);
209
+
210
+ // Adds a keyboard shortcut to toggle the sidebar.
211
+ React.useEffect(() => {
212
+ const handleKeyDown = (event: KeyboardEvent) => {
213
+ if (
214
+ event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
215
+ (event.metaKey || event.ctrlKey)
216
+ ) {
217
+ event.preventDefault();
218
+ toggleSidebar();
219
+ }
220
+ };
221
+
222
+ window.addEventListener("keydown", handleKeyDown);
223
+ return () => window.removeEventListener("keydown", handleKeyDown);
224
+ }, [toggleSidebar]);
225
+
226
+ // We add a state so that we can do data-state="expanded" or "collapsed".
227
+ // This makes it easier to style the sidebar with Tailwind classes.
228
+ const state = open ? "expanded" : "collapsed";
229
+
230
+ const contextValue: SidebarContextProps = {
231
+ state,
232
+ open,
233
+ setOpen,
234
+ isMobile,
235
+ openMobile,
236
+ setOpenMobile,
237
+ toggleSidebar,
238
+ };
239
+
240
+ return (
241
+ <SidebarContext.Provider value={contextValue}>
242
+ <TooltipProvider delayDuration={0}>
243
+ <div
244
+ data-slot="sidebar-wrapper"
245
+ style={
246
+ {
247
+ "--sidebar-width": SIDEBAR_WIDTH,
248
+ "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
249
+ ...style,
250
+ } as React.CSSProperties
251
+ }
252
+ className={cn(
253
+ "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
254
+ className,
255
+ )}
256
+ {...props}
257
+ >
258
+ {children}
259
+ </div>
260
+ </TooltipProvider>
261
+ </SidebarContext.Provider>
262
+ );
263
+ }
264
+
265
+ /**
266
+ * Flexible and responsive navigation sidebar component
267
+ *
268
+ * The Sidebar component is the main container for navigation content, supporting multiple
269
+ * visual variants, collapsible behaviors, and responsive design patterns. It automatically
270
+ * adapts between desktop layouts and mobile sheet overlays based on viewport size.
271
+ *
272
+ * @component
273
+ *
274
+ * @param {"left" | "right"} [side="left"] - Which side of the screen the sidebar appears on
275
+ * @param {"sidebar" | "floating" | "inset"} [variant="sidebar"] - Visual variant:
276
+ * - `sidebar`: Standard full-height sidebar
277
+ * - `floating`: Sidebar with padding, rounded corners, and shadow
278
+ * - `inset`: Sidebar with margin that affects main content layout
279
+ * @param {"offcanvas" | "icon" | "none"} [collapsible="offcanvas"] - Collapse behavior:
280
+ * - `offcanvas`: Slides completely off-screen when collapsed
281
+ * - `icon`: Collapses to icon-only width, hiding text labels
282
+ * - `none`: Cannot be collapsed, always visible
283
+ * @param {string} [className] - Additional CSS classes
284
+ * @param {React.ReactNode} children - Sidebar content (Header, Content, Footer)
285
+ *
286
+ * @example
287
+ * ```tsx
288
+ * // Standard navigation sidebar
289
+ * <SidebarProvider>
290
+ * <Sidebar>
291
+ * <SidebarHeader>
292
+ * <h2>My Application</h2>
293
+ * </SidebarHeader>
294
+ * <SidebarContent>
295
+ * <SidebarGroup>
296
+ * <SidebarGroupLabel>Main</SidebarGroupLabel>
297
+ * <SidebarGroupContent>
298
+ * <SidebarMenu>
299
+ * <SidebarMenuItem>
300
+ * <SidebarMenuButton asChild>
301
+ * <Link href="/dashboard">
302
+ * <Home />
303
+ * <span>Dashboard</span>
304
+ * </Link>
305
+ * </SidebarMenuButton>
306
+ * </SidebarMenuItem>
307
+ * </SidebarMenu>
308
+ * </SidebarGroupContent>
309
+ * </SidebarGroup>
310
+ * </SidebarContent>
311
+ * <SidebarFooter>
312
+ * <SidebarMenu>
313
+ * <SidebarMenuItem>
314
+ * <SidebarMenuButton>
315
+ * <Settings />
316
+ * <span>Settings</span>
317
+ * </SidebarMenuButton>
318
+ * </SidebarMenuItem>
319
+ * </SidebarMenu>
320
+ * </SidebarFooter>
321
+ * </Sidebar>
322
+ * <SidebarInset>
323
+ * <main>Main content area</main>
324
+ * </SidebarInset>
325
+ * </SidebarProvider>
326
+ * ```
327
+ *
328
+ * @example
329
+ * ```tsx
330
+ * // Icon-collapsible sidebar with tooltips
331
+ * <SidebarProvider>
332
+ * <Sidebar collapsible="icon">
333
+ * <SidebarContent>
334
+ * <SidebarGroup>
335
+ * <SidebarGroupLabel>Navigation</SidebarGroupLabel>
336
+ * <SidebarGroupContent>
337
+ * <SidebarMenu>
338
+ * <SidebarMenuItem>
339
+ * <SidebarMenuButton tooltip="Go to Dashboard">
340
+ * <Home />
341
+ * <span>Dashboard</span>
342
+ * </SidebarMenuButton>
343
+ * </SidebarMenuItem>
344
+ * </SidebarMenu>
345
+ * </SidebarGroupContent>
346
+ * </SidebarGroup>
347
+ * </SidebarContent>
348
+ * </Sidebar>
349
+ * </SidebarProvider>
350
+ * ```
351
+ *
352
+ * @example
353
+ * ```tsx
354
+ * // Floating variant with custom styling
355
+ * <SidebarProvider>
356
+ * <Sidebar variant="floating">
357
+ * <SidebarHeader>
358
+ * <SidebarTrigger />
359
+ * <h2>Floating Sidebar</h2>
360
+ * </SidebarHeader>
361
+ * <SidebarContent>
362
+ * // Navigation content
363
+ * </SidebarContent>
364
+ * </Sidebar>
365
+ * </SidebarProvider>
366
+ * ```
367
+ *
368
+ * @accessibility
369
+ * - Keyboard shortcut: Cmd/Ctrl+B to toggle visibility
370
+ * - Full keyboard navigation support within sidebar
371
+ * - ARIA attributes indicate current state (expanded/collapsed)
372
+ * - Screen reader announcements for state changes
373
+ * - Mobile: Sheet overlay with proper focus management
374
+ * - Desktop: Seamless keyboard navigation between sidebar and main content
375
+ *
376
+ * @responsive
377
+ * - **Desktop**: Fixed-position sidebar with smooth width transitions
378
+ * - **Mobile**: Sheet overlay that slides in from the side
379
+ * - **Tablet**: Responsive breakpoints adapt behavior automatically
380
+ *
381
+ * @see {@link SidebarProvider} - Required context provider
382
+ * @see {@link SidebarHeader} - Header section component
383
+ * @see {@link SidebarContent} - Scrollable content area
384
+ * @see {@link SidebarFooter} - Footer section component
385
+ * @see {@link SidebarTrigger} - Toggle button component
386
+ * @see {@link SidebarRail} - Interactive resize handle
387
+ * @see {@link https://ui.shadcn.com/docs/components/sidebar} - shadcn/ui Sidebar documentation
388
+ * @since 1.0.0
389
+ */
390
+ function Sidebar({
391
+ side = "left",
392
+ variant = "sidebar",
393
+ collapsible = "offcanvas",
394
+ className,
395
+ children,
396
+ ...props
397
+ }: React.ComponentProps<"div"> & {
398
+ side?: "left" | "right";
399
+ variant?: "sidebar" | "floating" | "inset";
400
+ collapsible?: "offcanvas" | "icon" | "none";
401
+ }) {
402
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
403
+
404
+ if (collapsible === "none") {
405
+ return (
406
+ <div
407
+ data-slot="sidebar"
408
+ className={cn(
409
+ "bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
410
+ className,
411
+ )}
412
+ {...props}
413
+ >
414
+ {children}
415
+ </div>
416
+ );
417
+ }
418
+
419
+ if (isMobile) {
420
+ return (
421
+ <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
422
+ <SheetContent
423
+ data-sidebar="sidebar"
424
+ data-slot="sidebar"
425
+ data-mobile="true"
426
+ className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
427
+ style={
428
+ {
429
+ "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
430
+ } as React.CSSProperties
431
+ }
432
+ side={side}
433
+ >
434
+ <SheetHeader className="sr-only">
435
+ <SheetTitle>Sidebar</SheetTitle>
436
+ <SheetDescription>Displays the mobile sidebar.</SheetDescription>
437
+ </SheetHeader>
438
+ <div className="flex h-full w-full flex-col">{children}</div>
439
+ </SheetContent>
440
+ </Sheet>
441
+ );
442
+ }
443
+
444
+ return (
445
+ <div
446
+ className="group peer text-sidebar-foreground hidden md:block"
447
+ data-state={state}
448
+ data-collapsible={state === "collapsed" ? collapsible : ""}
449
+ data-variant={variant}
450
+ data-side={side}
451
+ data-slot="sidebar"
452
+ >
453
+ {/* This is what handles the sidebar gap on desktop */}
454
+ <div
455
+ data-slot="sidebar-gap"
456
+ className={cn(
457
+ "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
458
+ "group-data-[collapsible=offcanvas]:w-0",
459
+ "group-data-[side=right]:rotate-180",
460
+ variant === "floating" || variant === "inset"
461
+ ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
462
+ : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
463
+ )}
464
+ />
465
+ <div
466
+ data-slot="sidebar-container"
467
+ className={cn(
468
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
469
+ side === "left"
470
+ ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
471
+ : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
472
+ // Adjust the padding for floating and inset variants.
473
+ variant === "floating" || variant === "inset"
474
+ ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
475
+ : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
476
+ className,
477
+ )}
478
+ {...props}
479
+ >
480
+ <div
481
+ data-sidebar="sidebar"
482
+ data-slot="sidebar-inner"
483
+ className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
484
+ >
485
+ {children}
486
+ </div>
487
+ </div>
488
+ </div>
489
+ );
490
+ }
491
+
492
+ /**
493
+ * Interactive button component for toggling sidebar visibility
494
+ *
495
+ * A pre-styled button that toggles the sidebar between expanded and collapsed states
496
+ * on desktop, or opens/closes the mobile sheet overlay on smaller screens. Features
497
+ * a panel icon and proper accessibility attributes.
498
+ *
499
+ * @component
500
+ *
501
+ * @param {string} [className] - Additional CSS classes
502
+ * @param {(event: React.MouseEvent) => void} [onClick] - Additional click handler
503
+ * @param {...React.ComponentProps<typeof Button>} props - All Button component props
504
+ *
505
+ * @example
506
+ * ```tsx
507
+ * // Basic usage in header
508
+ * <header className="flex items-center gap-2 p-4">
509
+ * <SidebarTrigger />
510
+ * <h1>My Application</h1>
511
+ * </header>
512
+ * ```
513
+ *
514
+ * @example
515
+ * ```tsx
516
+ * // With custom click handler
517
+ * <SidebarTrigger
518
+ * onClick={(e) => {
519
+ * console.log('Sidebar toggled')
520
+ * // Additional logic here
521
+ * }}
522
+ * />
523
+ * ```
524
+ *
525
+ * @accessibility
526
+ * - Screen reader label: "Toggle Sidebar"
527
+ * - Keyboard accessible (Enter and Space keys)
528
+ * - Focus visible indicator for keyboard navigation
529
+ * - ARIA attributes for assistive technology
530
+ *
531
+ * @see {@link useSidebar} - Hook for custom toggle implementations
532
+ * @see {@link SidebarProvider} - Required context provider
533
+ * @since 1.0.0
534
+ */
535
+ function SidebarTrigger({
536
+ className,
537
+ onClick,
538
+ ...props
539
+ }: React.ComponentProps<typeof Button>) {
540
+ const { toggleSidebar } = useSidebar();
541
+
542
+ return (
543
+ <Button
544
+ data-sidebar="trigger"
545
+ data-slot="sidebar-trigger"
546
+ variant="ghost"
547
+ size="icon"
548
+ className={cn("size-7", className)}
549
+ onClick={(event) => {
550
+ onClick?.(event);
551
+ toggleSidebar();
552
+ }}
553
+ {...props}
554
+ >
555
+ <PanelLeftIcon />
556
+ <span className="sr-only">Toggle Sidebar</span>
557
+ </Button>
558
+ );
559
+ }
560
+
561
+ /**
562
+ * Interactive rail component for sidebar edge interaction
563
+ *
564
+ * Provides a subtle interactive area along the sidebar edge that users can click
565
+ * to toggle the sidebar state. The rail is positioned at the sidebar boundary and
566
+ * includes hover states for discoverability. Only visible on desktop viewports.
567
+ *
568
+ * @component
569
+ *
570
+ * @param {string} [className] - Additional CSS classes
571
+ * @param {...React.ComponentProps<"button">} props - All button element props
572
+ *
573
+ * @example
574
+ * ```tsx
575
+ * // Basic usage (typically placed at end of Sidebar)
576
+ * <Sidebar>
577
+ * <SidebarHeader>Header content</SidebarHeader>
578
+ * <SidebarContent>Navigation content</SidebarContent>
579
+ * <SidebarFooter>Footer content</SidebarFooter>
580
+ * <SidebarRail />
581
+ * </Sidebar>
582
+ * ```
583
+ *
584
+ * @accessibility
585
+ * - ARIA label: "Toggle Sidebar"
586
+ * - Keyboard accessible but with tabIndex={-1} to avoid tab trap
587
+ * - Hover and focus states for discoverability
588
+ * - Cursor changes based on sidebar state and side
589
+ *
590
+ * @see {@link SidebarTrigger} - Alternative toggle button
591
+ * @since 1.0.0
592
+ */
593
+ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
594
+ const { toggleSidebar } = useSidebar();
595
+
596
+ return (
597
+ <button
598
+ data-sidebar="rail"
599
+ data-slot="sidebar-rail"
600
+ aria-label="Toggle Sidebar"
601
+ tabIndex={-1}
602
+ onClick={toggleSidebar}
603
+ title="Toggle Sidebar"
604
+ className={cn(
605
+ "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
606
+ "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
607
+ "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
608
+ "hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
609
+ "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
610
+ "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
611
+ className,
612
+ )}
613
+ {...props}
614
+ />
615
+ );
616
+ }
617
+
618
+ /**
619
+ * Main content container that adapts to sidebar layout
620
+ *
621
+ * The SidebarInset component serves as the primary content area that automatically
622
+ * adjusts its layout and spacing based on the sidebar's state and variant. It provides
623
+ * proper margins, responsive behavior, and styling coordination with the sidebar.
624
+ *
625
+ * @component
626
+ *
627
+ * @param {string} [className] - Additional CSS classes
628
+ * @param {...React.ComponentProps<"main">} props - All main element props
629
+ *
630
+ * @example
631
+ * ```tsx
632
+ * // Standard layout with header and content
633
+ * <SidebarProvider>
634
+ * <Sidebar>Sidebar content</Sidebar>
635
+ * <SidebarInset>
636
+ * <header className="flex h-16 items-center gap-2 px-4">
637
+ * <SidebarTrigger />
638
+ * <h1>Page Title</h1>
639
+ * </header>
640
+ * <main className="flex-1 p-4">
641
+ * <p>Your main content goes here</p>
642
+ * </main>
643
+ * </SidebarInset>
644
+ * </SidebarProvider>
645
+ * ```
646
+ *
647
+ * @example
648
+ * ```tsx
649
+ * // With inset variant coordination
650
+ * <SidebarProvider>
651
+ * <Sidebar variant="inset">Sidebar</Sidebar>
652
+ * <SidebarInset>
653
+ * // Content automatically gets proper spacing
654
+ * <div>Content with proper inset margins</div>
655
+ * </SidebarInset>
656
+ * </SidebarProvider>
657
+ * ```
658
+ *
659
+ * @features
660
+ * - Automatic layout adjustment based on sidebar state
661
+ * - Responsive margin and padding coordination
662
+ * - Proper spacing for different sidebar variants
663
+ * - Smooth transitions when sidebar state changes
664
+ *
665
+ * @see {@link Sidebar} - Main sidebar component
666
+ * @see {@link SidebarProvider} - Required context provider
667
+ * @since 1.0.0
668
+ */
669
+ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
670
+ return (
671
+ <main
672
+ data-slot="sidebar-inset"
673
+ className={cn(
674
+ "bg-background relative flex w-full flex-1 flex-col",
675
+ "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
676
+ className,
677
+ )}
678
+ {...props}
679
+ />
680
+ );
681
+ }
682
+
683
+ /**
684
+ * Input component optimized for sidebar usage
685
+ *
686
+ * A pre-styled input field designed to integrate seamlessly within sidebar layouts.
687
+ * Commonly used for search functionality, filters, or other input needs within
688
+ * the sidebar context. Features appropriate sizing and styling for sidebar use.
689
+ *
690
+ * @component
691
+ *
692
+ * @param {string} [className] - Additional CSS classes
693
+ * @param {...React.ComponentProps<typeof Input>} props - All Input component props
694
+ *
695
+ * @example
696
+ * ```tsx
697
+ * // Search input in sidebar header
698
+ * <SidebarHeader>
699
+ * <h2>Navigation</h2>
700
+ * <SidebarInput
701
+ * placeholder="Search..."
702
+ * onChange={(e) => handleSearch(e.target.value)}
703
+ * />
704
+ * </SidebarHeader>
705
+ * ```
706
+ *
707
+ * @example
708
+ * ```tsx
709
+ * // Filter input with icon
710
+ * <SidebarGroup>
711
+ * <SidebarGroupLabel>Filter Options</SidebarGroupLabel>
712
+ * <SidebarGroupContent>
713
+ * <SidebarInput
714
+ * type="search"
715
+ * placeholder="Filter items"
716
+ * className="mb-2"
717
+ * />
718
+ * </SidebarGroupContent>
719
+ * </SidebarGroup>
720
+ * ```
721
+ *
722
+ * @see {@link Input} - Base input component
723
+ * @since 1.0.0
724
+ */
725
+ function SidebarInput({
726
+ className,
727
+ ...props
728
+ }: React.ComponentProps<typeof Input>) {
729
+ return (
730
+ <Input
731
+ data-slot="sidebar-input"
732
+ data-sidebar="input"
733
+ className={cn("bg-background h-8 w-full shadow-none", className)}
734
+ {...props}
735
+ />
736
+ );
737
+ }
738
+
739
+ /**
740
+ * Header section container for sidebar content
741
+ *
742
+ * A flexible container for sidebar header content such as logos, application titles,
743
+ * user information, or action buttons. The header remains visible even when the sidebar
744
+ * is collapsed to icon mode, making it ideal for persistent branding or key actions.
745
+ *
746
+ * @component
747
+ *
748
+ * @param {string} [className] - Additional CSS classes
749
+ * @param {...React.ComponentProps<"div">} props - All div element props
750
+ *
751
+ * @example
752
+ * ```tsx
753
+ * // Simple header with title
754
+ * <SidebarHeader>
755
+ * <h2 className="text-lg font-semibold">My Application</h2>
756
+ * </SidebarHeader>
757
+ * ```
758
+ *
759
+ * @example
760
+ * ```tsx
761
+ * // Header with trigger and search
762
+ * <SidebarHeader>
763
+ * <div className="flex items-center justify-between">
764
+ * <h2>Navigation</h2>
765
+ * <SidebarTrigger />
766
+ * </div>
767
+ * <SidebarInput placeholder="Search..." className="mt-2" />
768
+ * </SidebarHeader>
769
+ * ```
770
+ *
771
+ * @example
772
+ * ```tsx
773
+ * // Header with user menu
774
+ * <SidebarHeader>
775
+ * <SidebarMenu>
776
+ * <SidebarMenuItem>
777
+ * <DropdownMenu>
778
+ * <DropdownMenuTrigger asChild>
779
+ * <SidebarMenuButton>
780
+ * <Avatar />
781
+ * <span>John Doe</span>
782
+ * <ChevronDown className="ml-auto" />
783
+ * </SidebarMenuButton>
784
+ * </DropdownMenuTrigger>
785
+ * <DropdownMenuContent>
786
+ * <DropdownMenuItem>Profile</DropdownMenuItem>
787
+ * <DropdownMenuItem>Settings</DropdownMenuItem>
788
+ * <DropdownMenuItem>Logout</DropdownMenuItem>
789
+ * </DropdownMenuContent>
790
+ * </DropdownMenu>
791
+ * </SidebarMenuItem>
792
+ * </SidebarMenu>
793
+ * </SidebarHeader>
794
+ * ```
795
+ *
796
+ * @see {@link SidebarFooter} - Footer section component
797
+ * @see {@link SidebarContent} - Main scrollable content area
798
+ * @since 1.0.0
799
+ */
800
+ function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
801
+ return (
802
+ <div
803
+ data-slot="sidebar-header"
804
+ data-sidebar="header"
805
+ className={cn("flex flex-col gap-2 p-2", className)}
806
+ {...props}
807
+ />
808
+ );
809
+ }
810
+
811
+ /**
812
+ * Footer section container for sidebar content
813
+ *
814
+ * A container positioned at the bottom of the sidebar for footer content such as
815
+ * user profiles, settings links, logout buttons, or help resources. The footer
816
+ * remains anchored to the bottom regardless of content height.
817
+ *
818
+ * @component
819
+ *
820
+ * @param {string} [className] - Additional CSS classes
821
+ * @param {...React.ComponentProps<"div">} props - All div element props
822
+ *
823
+ * @example
824
+ * ```tsx
825
+ * // Simple footer with settings link
826
+ * <SidebarFooter>
827
+ * <SidebarMenu>
828
+ * <SidebarMenuItem>
829
+ * <SidebarMenuButton>
830
+ * <Settings />
831
+ * <span>Settings</span>
832
+ * </SidebarMenuButton>
833
+ * </SidebarMenuItem>
834
+ * </SidebarMenu>
835
+ * </SidebarFooter>
836
+ * ```
837
+ *
838
+ * @example
839
+ * ```tsx
840
+ * // Footer with user profile and actions
841
+ * <SidebarFooter>
842
+ * <SidebarMenu>
843
+ * <SidebarMenuItem>
844
+ * <SidebarMenuButton>
845
+ * <Avatar className="h-6 w-6" />
846
+ * <div className="flex flex-col text-left">
847
+ * <span className="text-sm">John Doe</span>
848
+ * <span className="text-xs text-muted-foreground">john@example.com</span>
849
+ * </div>
850
+ * </SidebarMenuButton>
851
+ * <SidebarMenuAction>
852
+ * <LogOut />
853
+ * </SidebarMenuAction>
854
+ * </SidebarMenuItem>
855
+ * </SidebarMenu>
856
+ * </SidebarFooter>
857
+ * ```
858
+ *
859
+ * @see {@link SidebarHeader} - Header section component
860
+ * @see {@link SidebarContent} - Main content area
861
+ * @since 1.0.0
862
+ */
863
+ function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
864
+ return (
865
+ <div
866
+ data-slot="sidebar-footer"
867
+ data-sidebar="footer"
868
+ className={cn("flex flex-col gap-2 p-2", className)}
869
+ {...props}
870
+ />
871
+ );
872
+ }
873
+
874
+ /**
875
+ * Visual separator for organizing sidebar sections
876
+ *
877
+ * A horizontal divider component used to visually separate different sections
878
+ * within the sidebar content. Helps organize navigation groups and improve
879
+ * visual hierarchy and readability.
880
+ *
881
+ * @component
882
+ *
883
+ * @param {string} [className] - Additional CSS classes
884
+ * @param {...React.ComponentProps<typeof Separator>} props - All Separator component props
885
+ *
886
+ * @example
887
+ * ```tsx
888
+ * // Separating navigation groups
889
+ * <SidebarContent>
890
+ * <SidebarGroup>
891
+ * <SidebarGroupLabel>Main Navigation</SidebarGroupLabel>
892
+ * <SidebarGroupContent>
893
+ * // Main nav items
894
+ * </SidebarGroupContent>
895
+ * </SidebarGroup>
896
+ *
897
+ * <SidebarSeparator />
898
+ *
899
+ * <SidebarGroup>
900
+ * <SidebarGroupLabel>Settings</SidebarGroupLabel>
901
+ * <SidebarGroupContent>
902
+ * // Settings items
903
+ * </SidebarGroupContent>
904
+ * </SidebarGroup>
905
+ * </SidebarContent>
906
+ * ```
907
+ *
908
+ * @example
909
+ * ```tsx
910
+ * // Between header and content
911
+ * <Sidebar>
912
+ * <SidebarHeader>
913
+ * <h2>Application</h2>
914
+ * </SidebarHeader>
915
+ * <SidebarSeparator />
916
+ * <SidebarContent>
917
+ * // Navigation content
918
+ * </SidebarContent>
919
+ * </Sidebar>
920
+ * ```
921
+ *
922
+ * @see {@link Separator} - Base separator component
923
+ * @since 1.0.0
924
+ */
925
+ function SidebarSeparator({
926
+ className,
927
+ ...props
928
+ }: React.ComponentProps<typeof Separator>) {
929
+ return (
930
+ <Separator
931
+ data-slot="sidebar-separator"
932
+ data-sidebar="separator"
933
+ className={cn("bg-sidebar-border mx-2 w-auto", className)}
934
+ {...props}
935
+ />
936
+ );
937
+ }
938
+
939
+ /**
940
+ * Scrollable main content area of the sidebar
941
+ *
942
+ * The primary content container that houses navigation groups, menus, and other
943
+ * sidebar content. Provides automatic scrolling when content exceeds available
944
+ * height and handles overflow behavior when the sidebar is collapsed.
945
+ *
946
+ * @component
947
+ *
948
+ * @param {string} [className] - Additional CSS classes
949
+ * @param {...React.ComponentProps<"div">} props - All div element props
950
+ *
951
+ * @example
952
+ * ```tsx
953
+ * // Basic content with navigation groups
954
+ * <SidebarContent>
955
+ * <SidebarGroup>
956
+ * <SidebarGroupLabel>Main</SidebarGroupLabel>
957
+ * <SidebarGroupContent>
958
+ * <SidebarMenu>
959
+ * <SidebarMenuItem>
960
+ * <SidebarMenuButton>
961
+ * <Home />
962
+ * <span>Dashboard</span>
963
+ * </SidebarMenuButton>
964
+ * </SidebarMenuItem>
965
+ * </SidebarMenu>
966
+ * </SidebarGroupContent>
967
+ * </SidebarGroup>
968
+ * </SidebarContent>
969
+ * ```
970
+ *
971
+ * @example
972
+ * ```tsx
973
+ * // Multiple groups with separators
974
+ * <SidebarContent>
975
+ * <SidebarGroup>
976
+ * <SidebarGroupLabel>Navigation</SidebarGroupLabel>
977
+ * <SidebarGroupContent>
978
+ * // Navigation items
979
+ * </SidebarGroupContent>
980
+ * </SidebarGroup>
981
+ *
982
+ * <SidebarSeparator />
983
+ *
984
+ * <SidebarGroup>
985
+ * <SidebarGroupLabel>Projects</SidebarGroupLabel>
986
+ * <SidebarGroupContent>
987
+ * // Project items
988
+ * </SidebarGroupContent>
989
+ * </SidebarGroup>
990
+ * </SidebarContent>
991
+ * ```
992
+ *
993
+ * @features
994
+ * - Automatic scrolling for overflow content
995
+ * - Responsive to sidebar collapse states
996
+ * - Flexible gap spacing between child elements
997
+ * - Overflow hidden when collapsed to icon mode
998
+ *
999
+ * @see {@link SidebarGroup} - Content organization component
1000
+ * @see {@link SidebarMenu} - Menu container component
1001
+ * @since 1.0.0
1002
+ */
1003
+ function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
1004
+ return (
1005
+ <div
1006
+ data-slot="sidebar-content"
1007
+ data-sidebar="content"
1008
+ className={cn(
1009
+ "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
1010
+ className,
1011
+ )}
1012
+ {...props}
1013
+ />
1014
+ );
1015
+ }
1016
+
1017
+ /**
1018
+ * Container for organizing related sidebar navigation items
1019
+ *
1020
+ * Groups related navigation items together with optional labels and actions,
1021
+ * providing visual organization and hierarchy for complex navigation structures.
1022
+ * Groups can include labels, action buttons, and any combination of menu items.
1023
+ *
1024
+ * @component
1025
+ *
1026
+ * @param {string} [className] - Additional CSS classes
1027
+ * @param {...React.ComponentProps<"div">} props - All div element props
1028
+ *
1029
+ * @example
1030
+ * ```tsx
1031
+ * // Basic group with label and menu
1032
+ * <SidebarGroup>
1033
+ * <SidebarGroupLabel>Navigation</SidebarGroupLabel>
1034
+ * <SidebarGroupContent>
1035
+ * <SidebarMenu>
1036
+ * <SidebarMenuItem>
1037
+ * <SidebarMenuButton>
1038
+ * <Home />
1039
+ * <span>Dashboard</span>
1040
+ * </SidebarMenuButton>
1041
+ * </SidebarMenuItem>
1042
+ * </SidebarMenu>
1043
+ * </SidebarGroupContent>
1044
+ * </SidebarGroup>
1045
+ * ```
1046
+ *
1047
+ * @example
1048
+ * ```tsx
1049
+ * // Group with action button
1050
+ * <SidebarGroup>
1051
+ * <SidebarGroupLabel>Projects</SidebarGroupLabel>
1052
+ * <SidebarGroupAction>
1053
+ * <Plus className="h-4 w-4" />
1054
+ * <span className="sr-only">Add Project</span>
1055
+ * </SidebarGroupAction>
1056
+ * <SidebarGroupContent>
1057
+ * // Project items
1058
+ * </SidebarGroupContent>
1059
+ * </SidebarGroup>
1060
+ * ```
1061
+ *
1062
+ * @see {@link SidebarGroupLabel} - Group label component
1063
+ * @see {@link SidebarGroupAction} - Group action button
1064
+ * @see {@link SidebarGroupContent} - Group content container
1065
+ * @since 1.0.0
1066
+ */
1067
+ function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
1068
+ return (
1069
+ <div
1070
+ data-slot="sidebar-group"
1071
+ data-sidebar="group"
1072
+ className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
1073
+ {...props}
1074
+ />
1075
+ );
1076
+ }
1077
+
1078
+ /**
1079
+ * Label component for sidebar groups
1080
+ *
1081
+ * Displays a descriptive label for a group of sidebar items, providing clear
1082
+ * categorization and hierarchy. The label automatically hides when the sidebar
1083
+ * is collapsed to icon mode to maintain clean visual presentation.
1084
+ *
1085
+ * @component
1086
+ *
1087
+ * @param {string} [className] - Additional CSS classes
1088
+ * @param {boolean} [asChild=false] - Render as child element (using Slot)
1089
+ * @param {...React.ComponentProps<"div">} props - All div element props
1090
+ *
1091
+ * @example
1092
+ * ```tsx
1093
+ * // Standard text label
1094
+ * <SidebarGroup>
1095
+ * <SidebarGroupLabel>Main Navigation</SidebarGroupLabel>
1096
+ * <SidebarGroupContent>
1097
+ * // Menu items
1098
+ * </SidebarGroupContent>
1099
+ * </SidebarGroup>
1100
+ * ```
1101
+ *
1102
+ * @example
1103
+ * ```tsx
1104
+ * // Custom element using asChild
1105
+ * <SidebarGroup>
1106
+ * <SidebarGroupLabel asChild>
1107
+ * <h3 className="custom-heading">Projects</h3>
1108
+ * </SidebarGroupLabel>
1109
+ * <SidebarGroupContent>
1110
+ * // Project items
1111
+ * </SidebarGroupContent>
1112
+ * </SidebarGroup>
1113
+ * ```
1114
+ *
1115
+ * @features
1116
+ * - Automatic hide/show based on sidebar collapse state
1117
+ * - Smooth opacity and margin transitions
1118
+ * - Focus management for keyboard navigation
1119
+ * - Support for custom elements via asChild prop
1120
+ *
1121
+ * @see {@link SidebarGroup} - Parent group container
1122
+ * @see {@link SidebarGroupAction} - Associated action button
1123
+ * @since 1.0.0
1124
+ */
1125
+ function SidebarGroupLabel({
1126
+ className,
1127
+ asChild = false,
1128
+ ...props
1129
+ }: React.ComponentProps<"div"> & { asChild?: boolean }) {
1130
+ const Comp = asChild ? Slot : "div";
1131
+
1132
+ return (
1133
+ <Comp
1134
+ data-slot="sidebar-group-label"
1135
+ data-sidebar="group-label"
1136
+ className={cn(
1137
+ "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
1138
+ "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
1139
+ className,
1140
+ )}
1141
+ {...props}
1142
+ />
1143
+ );
1144
+ }
1145
+
1146
+ /**
1147
+ * Action button positioned within sidebar groups
1148
+ *
1149
+ * A compact action button positioned at the top-right of a sidebar group,
1150
+ * typically used for group-specific actions such as adding new items, editing
1151
+ * group settings, or accessing group options. Automatically hidden when collapsed.
1152
+ *
1153
+ * @component
1154
+ *
1155
+ * @param {string} [className] - Additional CSS classes
1156
+ * @param {boolean} [asChild=false] - Render as child element (using Slot)
1157
+ * @param {...React.ComponentProps<"button">} props - All button element props
1158
+ *
1159
+ * @example
1160
+ * ```tsx
1161
+ * // Add button for projects group
1162
+ * <SidebarGroup>
1163
+ * <SidebarGroupLabel>Projects</SidebarGroupLabel>
1164
+ * <SidebarGroupAction>
1165
+ * <Plus className="h-4 w-4" />
1166
+ * <span className="sr-only">Add Project</span>
1167
+ * </SidebarGroupAction>
1168
+ * <SidebarGroupContent>
1169
+ * // Project items
1170
+ * </SidebarGroupContent>
1171
+ * </SidebarGroup>
1172
+ * ```
1173
+ *
1174
+ * @example
1175
+ * ```tsx
1176
+ * // Custom action with asChild
1177
+ * <SidebarGroup>
1178
+ * <SidebarGroupLabel>Settings</SidebarGroupLabel>
1179
+ * <SidebarGroupAction asChild>
1180
+ * <Button variant="ghost" size="sm">
1181
+ * <MoreHorizontal className="h-4 w-4" />
1182
+ * </Button>
1183
+ * </SidebarGroupAction>
1184
+ * <SidebarGroupContent>
1185
+ * // Settings items
1186
+ * </SidebarGroupContent>
1187
+ * </SidebarGroup>
1188
+ * ```
1189
+ *
1190
+ * @accessibility
1191
+ * - Increased touch target on mobile devices
1192
+ * - Keyboard accessible with focus management
1193
+ * - Screen reader support with descriptive labels
1194
+ *
1195
+ * @see {@link SidebarGroup} - Parent group container
1196
+ * @see {@link SidebarGroupLabel} - Associated group label
1197
+ * @since 1.0.0
1198
+ */
1199
+ function SidebarGroupAction({
1200
+ className,
1201
+ asChild = false,
1202
+ ...props
1203
+ }: React.ComponentProps<"button"> & { asChild?: boolean }) {
1204
+ const Comp = asChild ? Slot : "button";
1205
+
1206
+ return (
1207
+ <Comp
1208
+ data-slot="sidebar-group-action"
1209
+ data-sidebar="group-action"
1210
+ className={cn(
1211
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
1212
+ // Increases the hit area of the button on mobile.
1213
+ "after:absolute after:-inset-2 md:after:hidden",
1214
+ "group-data-[collapsible=icon]:hidden",
1215
+ className,
1216
+ )}
1217
+ {...props}
1218
+ />
1219
+ );
1220
+ }
1221
+
1222
+ /**
1223
+ * Content container for sidebar group items
1224
+ *
1225
+ * Houses the actual navigation items, menus, and content within a sidebar group.
1226
+ * Provides consistent spacing and organization for group content while maintaining
1227
+ * proper typography and layout coordination.
1228
+ *
1229
+ * @component
1230
+ *
1231
+ * @param {string} [className] - Additional CSS classes
1232
+ * @param {...React.ComponentProps<"div">} props - All div element props
1233
+ *
1234
+ * @example
1235
+ * ```tsx
1236
+ * // Basic content with menu items
1237
+ * <SidebarGroup>
1238
+ * <SidebarGroupLabel>Navigation</SidebarGroupLabel>
1239
+ * <SidebarGroupContent>
1240
+ * <SidebarMenu>
1241
+ * <SidebarMenuItem>
1242
+ * <SidebarMenuButton>
1243
+ * <Home />
1244
+ * <span>Dashboard</span>
1245
+ * </SidebarMenuButton>
1246
+ * </SidebarMenuItem>
1247
+ * <SidebarMenuItem>
1248
+ * <SidebarMenuButton>
1249
+ * <Settings />
1250
+ * <span>Settings</span>
1251
+ * </SidebarMenuButton>
1252
+ * </SidebarMenuItem>
1253
+ * </SidebarMenu>
1254
+ * </SidebarGroupContent>
1255
+ * </SidebarGroup>
1256
+ * ```
1257
+ *
1258
+ * @example
1259
+ * ```tsx
1260
+ * // Multiple menus in group content
1261
+ * <SidebarGroup>
1262
+ * <SidebarGroupLabel>Projects</SidebarGroupLabel>
1263
+ * <SidebarGroupContent>
1264
+ * <SidebarMenu>
1265
+ * // Recent projects
1266
+ * </SidebarMenu>
1267
+ * <SidebarSeparator />
1268
+ * <SidebarMenu>
1269
+ * // Archived projects
1270
+ * </SidebarMenu>
1271
+ * </SidebarGroupContent>
1272
+ * </SidebarGroup>
1273
+ * ```
1274
+ *
1275
+ * @see {@link SidebarGroup} - Parent group container
1276
+ * @see {@link SidebarMenu} - Menu container component
1277
+ * @since 1.0.0
1278
+ */
1279
+ function SidebarGroupContent({
1280
+ className,
1281
+ ...props
1282
+ }: React.ComponentProps<"div">) {
1283
+ return (
1284
+ <div
1285
+ data-slot="sidebar-group-content"
1286
+ data-sidebar="group-content"
1287
+ className={cn("w-full text-sm", className)}
1288
+ {...props}
1289
+ />
1290
+ );
1291
+ }
1292
+
1293
+ /**
1294
+ * Navigation menu container for organizing sidebar items
1295
+ *
1296
+ * An unordered list container that holds and organizes SidebarMenuItem components.
1297
+ * Provides consistent spacing, layout, and semantic structure for navigation items
1298
+ * within sidebar groups or sections.
1299
+ *
1300
+ * @component
1301
+ *
1302
+ * @param {string} [className] - Additional CSS classes
1303
+ * @param {...React.ComponentProps<"ul">} props - All ul element props
1304
+ *
1305
+ * @example
1306
+ * ```tsx
1307
+ * // Basic navigation menu
1308
+ * <SidebarMenu>
1309
+ * <SidebarMenuItem>
1310
+ * <SidebarMenuButton>
1311
+ * <Home />
1312
+ * <span>Dashboard</span>
1313
+ * </SidebarMenuButton>
1314
+ * </SidebarMenuItem>
1315
+ * <SidebarMenuItem>
1316
+ * <SidebarMenuButton>
1317
+ * <Settings />
1318
+ * <span>Settings</span>
1319
+ * </SidebarMenuButton>
1320
+ * </SidebarMenuItem>
1321
+ * </SidebarMenu>
1322
+ * ```
1323
+ *
1324
+ * @example
1325
+ * ```tsx
1326
+ * // Menu with badges and actions
1327
+ * <SidebarMenu>
1328
+ * <SidebarMenuItem>
1329
+ * <SidebarMenuButton>
1330
+ * <Inbox />
1331
+ * <span>Messages</span>
1332
+ * </SidebarMenuButton>
1333
+ * <SidebarMenuBadge>3</SidebarMenuBadge>
1334
+ * </SidebarMenuItem>
1335
+ * <SidebarMenuItem>
1336
+ * <SidebarMenuButton>
1337
+ * <Archive />
1338
+ * <span>Archive</span>
1339
+ * </SidebarMenuButton>
1340
+ * <SidebarMenuAction>
1341
+ * <MoreHorizontal />
1342
+ * </SidebarMenuAction>
1343
+ * </SidebarMenuItem>
1344
+ * </SidebarMenu>
1345
+ * ```
1346
+ *
1347
+ * @accessibility
1348
+ * - Semantic ul/li structure for screen readers
1349
+ * - Proper navigation landmarks
1350
+ * - Keyboard navigation support
1351
+ *
1352
+ * @see {@link SidebarMenuItem} - Individual menu item component
1353
+ * @see {@link SidebarMenuButton} - Interactive menu button
1354
+ * @since 1.0.0
1355
+ */
1356
+ function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
1357
+ return (
1358
+ <ul
1359
+ data-slot="sidebar-menu"
1360
+ data-sidebar="menu"
1361
+ className={cn("flex w-full min-w-0 flex-col gap-1", className)}
1362
+ {...props}
1363
+ />
1364
+ );
1365
+ }
1366
+
1367
+ /**
1368
+ * Individual menu item container for sidebar navigation
1369
+ *
1370
+ * A list item container that wraps a single navigation item, typically containing
1371
+ * a SidebarMenuButton along with optional components like SidebarMenuAction,
1372
+ * SidebarMenuBadge, or SidebarMenuSub for hierarchical navigation.
1373
+ *
1374
+ * @component
1375
+ *
1376
+ * @param {string} [className] - Additional CSS classes
1377
+ * @param {...React.ComponentProps<"li">} props - All li element props
1378
+ *
1379
+ * @example
1380
+ * ```tsx
1381
+ * // Simple menu item with button
1382
+ * <SidebarMenuItem>
1383
+ * <SidebarMenuButton>
1384
+ * <Home />
1385
+ * <span>Dashboard</span>
1386
+ * </SidebarMenuButton>
1387
+ * </SidebarMenuItem>
1388
+ * ```
1389
+ *
1390
+ * @example
1391
+ * ```tsx
1392
+ * // Menu item with badge
1393
+ * <SidebarMenuItem>
1394
+ * <SidebarMenuButton>
1395
+ * <Inbox />
1396
+ * <span>Messages</span>
1397
+ * </SidebarMenuButton>
1398
+ * <SidebarMenuBadge>5</SidebarMenuBadge>
1399
+ * </SidebarMenuItem>
1400
+ * ```
1401
+ *
1402
+ * @example
1403
+ * ```tsx
1404
+ * // Menu item with action button
1405
+ * <SidebarMenuItem>
1406
+ * <SidebarMenuButton>
1407
+ * <Folder />
1408
+ * <span>Projects</span>
1409
+ * </SidebarMenuButton>
1410
+ * <SidebarMenuAction showOnHover>
1411
+ * <Plus />
1412
+ * </SidebarMenuAction>
1413
+ * </SidebarMenuItem>
1414
+ * ```
1415
+ *
1416
+ * @example
1417
+ * ```tsx
1418
+ * // Menu item with submenu
1419
+ * <SidebarMenuItem>
1420
+ * <SidebarMenuButton>
1421
+ * <Folder />
1422
+ * <span>Projects</span>
1423
+ * <ChevronRight className="ml-auto" />
1424
+ * </SidebarMenuButton>
1425
+ * <SidebarMenuSub>
1426
+ * <SidebarMenuSubItem>
1427
+ * <SidebarMenuSubButton>Web App</SidebarMenuSubButton>
1428
+ * </SidebarMenuSubItem>
1429
+ * </SidebarMenuSub>
1430
+ * </SidebarMenuItem>
1431
+ * ```
1432
+ *
1433
+ * @see {@link SidebarMenu} - Parent menu container
1434
+ * @see {@link SidebarMenuButton} - Interactive button component
1435
+ * @see {@link SidebarMenuAction} - Action button component
1436
+ * @see {@link SidebarMenuBadge} - Badge indicator component
1437
+ * @since 1.0.0
1438
+ */
1439
+ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
1440
+ return (
1441
+ <li
1442
+ data-slot="sidebar-menu-item"
1443
+ data-sidebar="menu-item"
1444
+ className={cn("group/menu-item relative", className)}
1445
+ {...props}
1446
+ />
1447
+ );
1448
+ }
1449
+
1450
+ const sidebarMenuButtonVariants = cva(
1451
+ "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
1452
+ {
1453
+ variants: {
1454
+ variant: {
1455
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
1456
+ outline:
1457
+ "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
1458
+ },
1459
+ size: {
1460
+ default: "h-8 text-sm",
1461
+ sm: "h-7 text-xs",
1462
+ lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
1463
+ },
1464
+ },
1465
+ defaultVariants: {
1466
+ variant: "default",
1467
+ size: "default",
1468
+ },
1469
+ },
1470
+ );
1471
+
1472
+ /**
1473
+ * Interactive navigation button for sidebar menu items
1474
+ *
1475
+ * The primary interactive element for sidebar navigation, offering a flexible button
1476
+ * component that supports active states, multiple visual variants, tooltip integration
1477
+ * for collapsed modes, and composition patterns through the asChild prop. Automatically
1478
+ * adapts its appearance based on sidebar state and provides smooth hover/focus transitions.
1479
+ *
1480
+ * @component
1481
+ *
1482
+ * @param {boolean} [asChild=false] - Render as child element using Slot composition
1483
+ * @param {boolean} [isActive=false] - Whether this menu item is currently active
1484
+ * @param {"default" | "outline"} [variant="default"] - Visual variant:
1485
+ * - `default`: Standard button appearance with hover states
1486
+ * - `outline`: Button with border and background on hover
1487
+ * @param {"default" | "sm" | "lg"} [size="default"] - Button size variant:
1488
+ * - `default`: Standard height (h-8)
1489
+ * - `sm`: Small height (h-7)
1490
+ * - `lg`: Large height (h-12)
1491
+ * @param {string | React.ComponentProps<typeof TooltipContent>} [tooltip] - Tooltip content shown when sidebar is collapsed
1492
+ * @param {string} [className] - Additional CSS classes
1493
+ * @param {...React.ComponentProps<"button">} props - All button element props
1494
+ *
1495
+ * @example
1496
+ * ```tsx
1497
+ * // Basic navigation button
1498
+ * <SidebarMenuButton>
1499
+ * <Home className="h-4 w-4" />
1500
+ * <span>Dashboard</span>
1501
+ * </SidebarMenuButton>
1502
+ * ```
1503
+ *
1504
+ * @example
1505
+ * ```tsx
1506
+ * // Active state with Link composition
1507
+ * <SidebarMenuButton asChild isActive={pathname === '/dashboard'}>
1508
+ * <Link href="/dashboard">
1509
+ * <Home className="h-4 w-4" />
1510
+ * <span>Dashboard</span>
1511
+ * </Link>
1512
+ * </SidebarMenuButton>
1513
+ * ```
1514
+ *
1515
+ * @example
1516
+ * ```tsx
1517
+ * // With tooltip for collapsed mode
1518
+ * <SidebarMenuButton tooltip="Go to Dashboard">
1519
+ * <Home className="h-4 w-4" />
1520
+ * <span>Dashboard</span>
1521
+ * </SidebarMenuButton>
1522
+ * ```
1523
+ *
1524
+ * @example
1525
+ * ```tsx
1526
+ * // Different variants and sizes
1527
+ * <SidebarMenuButton variant="outline" size="lg">
1528
+ * <Settings className="h-4 w-4" />
1529
+ * <span>Settings</span>
1530
+ * </SidebarMenuButton>
1531
+ * ```
1532
+ *
1533
+ * @example
1534
+ * ```tsx
1535
+ * // Custom tooltip with props
1536
+ * <SidebarMenuButton
1537
+ * tooltip={{
1538
+ * children: "Dashboard Overview",
1539
+ * side: "right",
1540
+ * sideOffset: 10
1541
+ * }}
1542
+ * >
1543
+ * <Home className="h-4 w-4" />
1544
+ * <span>Dashboard</span>
1545
+ * </SidebarMenuButton>
1546
+ * ```
1547
+ *
1548
+ * @accessibility
1549
+ * - Full keyboard navigation support (Enter, Space)
1550
+ * - Focus visible ring for keyboard users
1551
+ * - Active state indication for screen readers
1552
+ * - Tooltip automatically shown/hidden based on sidebar state
1553
+ * - Proper contrast ratios for all states
1554
+ * - Support for screen reader announcements
1555
+ *
1556
+ * @responsive
1557
+ * - Automatically adapts to collapsed sidebar (icon-only mode)
1558
+ * - Tooltip integration for collapsed state
1559
+ * - Touch-friendly sizing on mobile devices
1560
+ * - Smooth transitions between states
1561
+ *
1562
+ * @see {@link SidebarMenuItem} - Parent menu item container
1563
+ * @see {@link SidebarMenuAction} - Secondary action button
1564
+ * @see {@link SidebarMenuBadge} - Badge component for notifications
1565
+ * @see {@link useSidebar} - Hook for sidebar state
1566
+ * @since 1.0.0
1567
+ */
1568
+ function SidebarMenuButton({
1569
+ asChild = false,
1570
+ isActive = false,
1571
+ variant = "default",
1572
+ size = "default",
1573
+ tooltip,
1574
+ className,
1575
+ ...props
1576
+ }: React.ComponentProps<"button"> & {
1577
+ asChild?: boolean;
1578
+ isActive?: boolean;
1579
+ tooltip?: string | React.ComponentProps<typeof TooltipContent>;
1580
+ } & VariantProps<typeof sidebarMenuButtonVariants>) {
1581
+ const Comp = asChild ? Slot : "button";
1582
+ const { isMobile, state } = useSidebar();
1583
+
1584
+ const button = (
1585
+ <Comp
1586
+ data-slot="sidebar-menu-button"
1587
+ data-sidebar="menu-button"
1588
+ data-size={size}
1589
+ data-active={isActive}
1590
+ className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
1591
+ {...props}
1592
+ />
1593
+ );
1594
+
1595
+ if (!tooltip) {
1596
+ return button;
1597
+ }
1598
+
1599
+ if (typeof tooltip === "string") {
1600
+ tooltip = {
1601
+ children: tooltip,
1602
+ };
1603
+ }
1604
+
1605
+ return (
1606
+ <Tooltip>
1607
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
1608
+ <TooltipContent
1609
+ side="right"
1610
+ align="center"
1611
+ hidden={state !== "collapsed" || isMobile}
1612
+ {...tooltip}
1613
+ />
1614
+ </Tooltip>
1615
+ );
1616
+ }
1617
+
1618
+ /**
1619
+ * Secondary action button for sidebar menu items
1620
+ *
1621
+ * A compact action button positioned on the right side of menu items, providing
1622
+ * secondary actions like edit, delete, or more options. Can be configured to show
1623
+ * only on hover for cleaner interfaces or remain always visible for important actions.
1624
+ *
1625
+ * @component
1626
+ *
1627
+ * @param {string} [className] - Additional CSS classes
1628
+ * @param {boolean} [asChild=false] - Render as child element using Slot composition
1629
+ * @param {boolean} [showOnHover=false] - Only show button on menu item hover
1630
+ * @param {...React.ComponentProps<"button">} props - All button element props
1631
+ *
1632
+ * @example
1633
+ * ```tsx
1634
+ * // Always visible action button
1635
+ * <SidebarMenuItem>
1636
+ * <SidebarMenuButton>
1637
+ * <Folder />
1638
+ * <span>Projects</span>
1639
+ * </SidebarMenuButton>
1640
+ * <SidebarMenuAction>
1641
+ * <MoreHorizontal className="h-4 w-4" />
1642
+ * </SidebarMenuAction>
1643
+ * </SidebarMenuItem>
1644
+ * ```
1645
+ *
1646
+ * @example
1647
+ * ```tsx
1648
+ * // Show only on hover
1649
+ * <SidebarMenuItem>
1650
+ * <SidebarMenuButton>
1651
+ * <File />
1652
+ * <span>Document</span>
1653
+ * </SidebarMenuButton>
1654
+ * <SidebarMenuAction showOnHover>
1655
+ * <Trash2 className="h-4 w-4" />
1656
+ * </SidebarMenuAction>
1657
+ * </SidebarMenuItem>
1658
+ * ```
1659
+ *
1660
+ * @example
1661
+ * ```tsx
1662
+ * // Custom action with asChild
1663
+ * <SidebarMenuItem>
1664
+ * <SidebarMenuButton>
1665
+ * <Star />
1666
+ * <span>Favorites</span>
1667
+ * </SidebarMenuButton>
1668
+ * <SidebarMenuAction asChild>
1669
+ * <DropdownMenu>
1670
+ * <DropdownMenuTrigger>
1671
+ * <MoreVertical className="h-4 w-4" />
1672
+ * </DropdownMenuTrigger>
1673
+ * <DropdownMenuContent>
1674
+ * <DropdownMenuItem>Edit</DropdownMenuItem>
1675
+ * <DropdownMenuItem>Delete</DropdownMenuItem>
1676
+ * </DropdownMenuContent>
1677
+ * </DropdownMenu>
1678
+ * </SidebarMenuAction>
1679
+ * </SidebarMenuItem>
1680
+ * ```
1681
+ *
1682
+ * @accessibility
1683
+ * - Increased touch target area on mobile devices
1684
+ * - Keyboard accessible with proper focus management
1685
+ * - Hidden from screen readers when showOnHover and not focused
1686
+ * - Proper contrast ratios for visibility
1687
+ *
1688
+ * @see {@link SidebarMenuItem} - Parent menu item
1689
+ * @see {@link SidebarMenuButton} - Primary menu button
1690
+ * @since 1.0.0
1691
+ */
1692
+ function SidebarMenuAction({
1693
+ className,
1694
+ asChild = false,
1695
+ showOnHover = false,
1696
+ ...props
1697
+ }: React.ComponentProps<"button"> & {
1698
+ asChild?: boolean;
1699
+ showOnHover?: boolean;
1700
+ }) {
1701
+ const Comp = asChild ? Slot : "button";
1702
+
1703
+ return (
1704
+ <Comp
1705
+ data-slot="sidebar-menu-action"
1706
+ data-sidebar="menu-action"
1707
+ className={cn(
1708
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
1709
+ // Increases the hit area of the button on mobile.
1710
+ "after:absolute after:-inset-2 md:after:hidden",
1711
+ "peer-data-[size=sm]/menu-button:top-1",
1712
+ "peer-data-[size=default]/menu-button:top-1.5",
1713
+ "peer-data-[size=lg]/menu-button:top-2.5",
1714
+ "group-data-[collapsible=icon]:hidden",
1715
+ showOnHover &&
1716
+ "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
1717
+ className,
1718
+ )}
1719
+ {...props}
1720
+ />
1721
+ );
1722
+ }
1723
+
1724
+ /**
1725
+ * Badge indicator component for menu items
1726
+ *
1727
+ * Displays count indicators, status badges, or notification markers on menu items.
1728
+ * Positioned on the right side of menu items and automatically coordinates with
1729
+ * menu button states and sidebar collapse behavior.
1730
+ *
1731
+ * @component
1732
+ *
1733
+ * @param {string} [className] - Additional CSS classes
1734
+ * @param {...React.ComponentProps<"div">} props - All div element props
1735
+ *
1736
+ * @example
1737
+ * ```tsx
1738
+ * // Unread count badge
1739
+ * <SidebarMenuItem>
1740
+ * <SidebarMenuButton>
1741
+ * <Inbox />
1742
+ * <span>Messages</span>
1743
+ * </SidebarMenuButton>
1744
+ * <SidebarMenuBadge>12</SidebarMenuBadge>
1745
+ * </SidebarMenuItem>
1746
+ * ```
1747
+ *
1748
+ * @example
1749
+ * ```tsx
1750
+ * // Status indicator
1751
+ * <SidebarMenuItem>
1752
+ * <SidebarMenuButton>
1753
+ * <Activity />
1754
+ * <span>System Status</span>
1755
+ * </SidebarMenuButton>
1756
+ * <SidebarMenuBadge className="bg-green-500">●</SidebarMenuBadge>
1757
+ * </SidebarMenuItem>
1758
+ * ```
1759
+ *
1760
+ * @example
1761
+ * ```tsx
1762
+ * // Dynamic badge with state
1763
+ * <SidebarMenuItem>
1764
+ * <SidebarMenuButton>
1765
+ * <Bell />
1766
+ * <span>Notifications</span>
1767
+ * </SidebarMenuButton>
1768
+ * {notificationCount > 0 && (
1769
+ * <SidebarMenuBadge>{notificationCount}</SidebarMenuBadge>
1770
+ * )}
1771
+ * </SidebarMenuItem>
1772
+ * ```
1773
+ *
1774
+ * @features
1775
+ * - Automatic positioning relative to menu button size
1776
+ * - Hidden when sidebar is collapsed to icon mode
1777
+ * - Tabular numbers for consistent numeric display
1778
+ * - Pointer events disabled to prevent interference
1779
+ *
1780
+ * @accessibility
1781
+ * - Non-interactive (pointer-events-none)
1782
+ * - Proper color contrast for readability
1783
+ * - Screen reader friendly with appropriate text
1784
+ *
1785
+ * @see {@link SidebarMenuItem} - Parent menu item
1786
+ * @see {@link SidebarMenuButton} - Associated menu button
1787
+ * @since 1.0.0
1788
+ */
1789
+ function SidebarMenuBadge({
1790
+ className,
1791
+ ...props
1792
+ }: React.ComponentProps<"div">) {
1793
+ return (
1794
+ <div
1795
+ data-slot="sidebar-menu-badge"
1796
+ data-sidebar="menu-badge"
1797
+ className={cn(
1798
+ "text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
1799
+ "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
1800
+ "peer-data-[size=sm]/menu-button:top-1",
1801
+ "peer-data-[size=default]/menu-button:top-1.5",
1802
+ "peer-data-[size=lg]/menu-button:top-2.5",
1803
+ "group-data-[collapsible=icon]:hidden",
1804
+ className,
1805
+ )}
1806
+ {...props}
1807
+ />
1808
+ );
1809
+ }
1810
+
1811
+ /**
1812
+ * Loading skeleton placeholder for menu items
1813
+ *
1814
+ * Displays an animated loading placeholder while menu items are being fetched
1815
+ * or loaded. Features random width variation to simulate realistic content
1816
+ * and optional icon placeholder for more accurate representation.
1817
+ *
1818
+ * @component
1819
+ *
1820
+ * @param {string} [className] - Additional CSS classes
1821
+ * @param {boolean} [showIcon=false] - Whether to show icon placeholder
1822
+ * @param {...React.ComponentProps<"div">} props - All div element props
1823
+ *
1824
+ * @example
1825
+ * ```tsx
1826
+ * // Basic skeleton without icon
1827
+ * <SidebarMenu>
1828
+ * <SidebarMenuItem>
1829
+ * <SidebarMenuSkeleton />
1830
+ * </SidebarMenuItem>
1831
+ * <SidebarMenuItem>
1832
+ * <SidebarMenuSkeleton />
1833
+ * </SidebarMenuItem>
1834
+ * </SidebarMenu>
1835
+ * ```
1836
+ *
1837
+ * @example
1838
+ * ```tsx
1839
+ * // Skeleton with icon placeholder
1840
+ * <SidebarMenu>
1841
+ * {Array.from({ length: 5 }).map((_, index) => (
1842
+ * <SidebarMenuItem key={index}>
1843
+ * <SidebarMenuSkeleton showIcon />
1844
+ * </SidebarMenuItem>
1845
+ * ))}
1846
+ * </SidebarMenu>
1847
+ * ```
1848
+ *
1849
+ * @example
1850
+ * ```tsx
1851
+ * // Loading state with React Suspense
1852
+ * <SidebarGroup>
1853
+ * <SidebarGroupLabel>Projects</SidebarGroupLabel>
1854
+ * <SidebarGroupContent>
1855
+ * <SidebarMenu>
1856
+ * <React.Suspense
1857
+ * fallback={
1858
+ * <>
1859
+ * <SidebarMenuItem><SidebarMenuSkeleton showIcon /></SidebarMenuItem>
1860
+ * <SidebarMenuItem><SidebarMenuSkeleton showIcon /></SidebarMenuItem>
1861
+ * <SidebarMenuItem><SidebarMenuSkeleton showIcon /></SidebarMenuItem>
1862
+ * </>
1863
+ * }
1864
+ * >
1865
+ * <ProjectsList />
1866
+ * </React.Suspense>
1867
+ * </SidebarMenu>
1868
+ * </SidebarGroupContent>
1869
+ * </SidebarGroup>
1870
+ * ```
1871
+ *
1872
+ * @features
1873
+ * - Random width variation (50-90%) for realistic appearance
1874
+ * - Optional icon skeleton placeholder
1875
+ * - Smooth loading animation
1876
+ * - Proper sizing to match actual menu items
1877
+ *
1878
+ * @see {@link SidebarMenuItem} - Container for skeleton
1879
+ * @see {@link SidebarMenu} - Parent menu container
1880
+ * @see {@link Skeleton} - Base skeleton component
1881
+ * @since 1.0.0
1882
+ */
1883
+ function SidebarMenuSkeleton({
1884
+ className,
1885
+ showIcon = false,
1886
+ ...props
1887
+ }: React.ComponentProps<"div"> & {
1888
+ showIcon?: boolean;
1889
+ }) {
1890
+ // Random width between 50 to 90%.
1891
+ const width = `${Math.floor(Math.random() * 40) + 50}%`;
1892
+
1893
+ return (
1894
+ <div
1895
+ data-slot="sidebar-menu-skeleton"
1896
+ data-sidebar="menu-skeleton"
1897
+ className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
1898
+ {...props}
1899
+ >
1900
+ {showIcon && (
1901
+ <Skeleton
1902
+ className="size-4 rounded-md"
1903
+ data-sidebar="menu-skeleton-icon"
1904
+ />
1905
+ )}
1906
+ <Skeleton
1907
+ className="h-4 max-w-(--skeleton-width) flex-1"
1908
+ data-sidebar="menu-skeleton-text"
1909
+ style={
1910
+ {
1911
+ "--skeleton-width": width,
1912
+ } as React.CSSProperties
1913
+ }
1914
+ />
1915
+ </div>
1916
+ );
1917
+ }
1918
+
1919
+ /**
1920
+ * Submenu container for hierarchical navigation
1921
+ *
1922
+ * A specialized container for nested navigation items that provides visual hierarchy
1923
+ * through indentation and connecting border lines. Perfect for organizing complex
1924
+ * navigation structures with parent-child relationships.
1925
+ *
1926
+ * @component
1927
+ *
1928
+ * @param {string} [className] - Additional CSS classes
1929
+ * @param {...React.ComponentProps<"ul">} props - All ul element props
1930
+ *
1931
+ * @example
1932
+ * ```tsx
1933
+ * // Collapsible submenu with parent item
1934
+ * <SidebarMenuItem>
1935
+ * <Collapsible>
1936
+ * <CollapsibleTrigger asChild>
1937
+ * <SidebarMenuButton>
1938
+ * <Folder />
1939
+ * <span>Projects</span>
1940
+ * <ChevronRight className="ml-auto transition-transform group-data-[state=open]:rotate-90" />
1941
+ * </SidebarMenuButton>
1942
+ * </CollapsibleTrigger>
1943
+ * <CollapsibleContent>
1944
+ * <SidebarMenuSub>
1945
+ * <SidebarMenuSubItem>
1946
+ * <SidebarMenuSubButton>Web Application</SidebarMenuSubButton>
1947
+ * </SidebarMenuSubItem>
1948
+ * <SidebarMenuSubItem>
1949
+ * <SidebarMenuSubButton>Mobile App</SidebarMenuSubButton>
1950
+ * </SidebarMenuSubItem>
1951
+ * <SidebarMenuSubItem>
1952
+ * <SidebarMenuSubButton>Documentation</SidebarMenuSubButton>
1953
+ * </SidebarMenuSubItem>
1954
+ * </SidebarMenuSub>
1955
+ * </CollapsibleContent>
1956
+ * </Collapsible>
1957
+ * </SidebarMenuItem>
1958
+ * ```
1959
+ *
1960
+ * @example
1961
+ * ```tsx
1962
+ * // Always expanded submenu
1963
+ * <SidebarMenuItem>
1964
+ * <SidebarMenuButton>
1965
+ * <Settings />
1966
+ * <span>Settings</span>
1967
+ * </SidebarMenuButton>
1968
+ * <SidebarMenuSub>
1969
+ * <SidebarMenuSubItem>
1970
+ * <SidebarMenuSubButton>General</SidebarMenuSubButton>
1971
+ * </SidebarMenuSubItem>
1972
+ * <SidebarMenuSubItem>
1973
+ * <SidebarMenuSubButton>Privacy</SidebarMenuSubButton>
1974
+ * </SidebarMenuSubItem>
1975
+ * <SidebarMenuSubItem>
1976
+ * <SidebarMenuSubButton>Security</SidebarMenuSubButton>
1977
+ * </SidebarMenuSubItem>
1978
+ * </SidebarMenuSub>
1979
+ * </SidebarMenuItem>
1980
+ * ```
1981
+ *
1982
+ * @features
1983
+ * - Visual hierarchy with left border and indentation
1984
+ * - Automatic hiding when sidebar is collapsed
1985
+ * - Proper spacing and alignment with parent items
1986
+ * - Seamless integration with collapsible components
1987
+ *
1988
+ * @accessibility
1989
+ * - Semantic ul/li structure for screen readers
1990
+ * - Proper nesting hierarchy for navigation
1991
+ * - Keyboard navigation support
1992
+ *
1993
+ * @see {@link SidebarMenuSubItem} - Individual submenu item
1994
+ * @see {@link SidebarMenuSubButton} - Submenu button component
1995
+ * @see {@link SidebarMenuItem} - Parent menu item
1996
+ * @since 1.0.0
1997
+ */
1998
+ function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
1999
+ return (
2000
+ <ul
2001
+ data-slot="sidebar-menu-sub"
2002
+ data-sidebar="menu-sub"
2003
+ className={cn(
2004
+ "border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5",
2005
+ "group-data-[collapsible=icon]:hidden",
2006
+ className,
2007
+ )}
2008
+ {...props}
2009
+ />
2010
+ );
2011
+ }
2012
+
2013
+ /**
2014
+ * Individual item container within submenu navigation
2015
+ *
2016
+ * A list item container for single nested navigation items within a submenu,
2017
+ * providing the structural foundation for hierarchical navigation elements.
2018
+ *
2019
+ * @component
2020
+ *
2021
+ * @param {string} [className] - Additional CSS classes
2022
+ * @param {...React.ComponentProps<"li">} props - All li element props
2023
+ *
2024
+ * @example
2025
+ * ```tsx
2026
+ * // Basic submenu item
2027
+ * <SidebarMenuSub>
2028
+ * <SidebarMenuSubItem>
2029
+ * <SidebarMenuSubButton asChild>
2030
+ * <Link href="/projects/web-app">
2031
+ * <span>Web Application</span>
2032
+ * </Link>
2033
+ * </SidebarMenuSubButton>
2034
+ * </SidebarMenuSubItem>
2035
+ * </SidebarMenuSub>
2036
+ * ```
2037
+ *
2038
+ * @example
2039
+ * ```tsx
2040
+ * // Submenu item with active state
2041
+ * <SidebarMenuSub>
2042
+ * <SidebarMenuSubItem>
2043
+ * <SidebarMenuSubButton
2044
+ * isActive={pathname === '/settings/general'}
2045
+ * asChild
2046
+ * >
2047
+ * <Link href="/settings/general">
2048
+ * <span>General Settings</span>
2049
+ * </Link>
2050
+ * </SidebarMenuSubButton>
2051
+ * </SidebarMenuSubItem>
2052
+ * </SidebarMenuSub>
2053
+ * ```
2054
+ *
2055
+ * @see {@link SidebarMenuSub} - Parent submenu container
2056
+ * @see {@link SidebarMenuSubButton} - Interactive button component
2057
+ * @since 1.0.0
2058
+ */
2059
+ function SidebarMenuSubItem({
2060
+ className,
2061
+ ...props
2062
+ }: React.ComponentProps<"li">) {
2063
+ return (
2064
+ <li
2065
+ data-slot="sidebar-menu-sub-item"
2066
+ data-sidebar="menu-sub-item"
2067
+ className={cn("group/menu-sub-item relative", className)}
2068
+ {...props}
2069
+ />
2070
+ );
2071
+ }
2072
+
2073
+ /**
2074
+ * Interactive button component for submenu navigation
2075
+ *
2076
+ * The primary interactive element for nested navigation items within submenus,
2077
+ * featuring support for active states, different sizes, and composition patterns.
2078
+ * Designed specifically for hierarchical navigation with appropriate styling and spacing.
2079
+ *
2080
+ * @component
2081
+ *
2082
+ * @param {boolean} [asChild=false] - Render as child element using Slot composition
2083
+ * @param {"sm" | "md"} [size="md"] - Button size variant:
2084
+ * - `sm`: Small size with text-xs
2085
+ * - `md`: Medium size with text-sm
2086
+ * @param {boolean} [isActive=false] - Whether this submenu item is currently active
2087
+ * @param {string} [className] - Additional CSS classes
2088
+ * @param {...React.ComponentProps<"a">} props - All anchor element props
2089
+ *
2090
+ * @example
2091
+ * ```tsx
2092
+ * // Basic submenu button
2093
+ * <SidebarMenuSubItem>
2094
+ * <SidebarMenuSubButton>
2095
+ * <span>Documentation</span>
2096
+ * </SidebarMenuSubButton>
2097
+ * </SidebarMenuSubItem>
2098
+ * ```
2099
+ *
2100
+ * @example
2101
+ * ```tsx
2102
+ * // Link composition with active state
2103
+ * <SidebarMenuSubItem>
2104
+ * <SidebarMenuSubButton
2105
+ * asChild
2106
+ * isActive={pathname === '/projects/mobile'}
2107
+ * >
2108
+ * <Link href="/projects/mobile">
2109
+ * <span>Mobile Application</span>
2110
+ * </Link>
2111
+ * </SidebarMenuSubButton>
2112
+ * </SidebarMenuSubItem>
2113
+ * ```
2114
+ *
2115
+ * @example
2116
+ * ```tsx
2117
+ * // Small size variant
2118
+ * <SidebarMenuSubItem>
2119
+ * <SidebarMenuSubButton size="sm">
2120
+ * <span>API Reference</span>
2121
+ * </SidebarMenuSubButton>
2122
+ * </SidebarMenuSubItem>
2123
+ * ```
2124
+ *
2125
+ * @example
2126
+ * ```tsx
2127
+ * // With icon and custom styling
2128
+ * <SidebarMenuSubItem>
2129
+ * <SidebarMenuSubButton className="gap-3">
2130
+ * <File className="h-3 w-3" />
2131
+ * <span>README.md</span>
2132
+ * </SidebarMenuSubButton>
2133
+ * </SidebarMenuSubItem>
2134
+ * ```
2135
+ *
2136
+ * @accessibility
2137
+ * - Full keyboard navigation support
2138
+ * - Focus visible indicators
2139
+ * - Active state indication for screen readers
2140
+ * - Proper contrast ratios for all states
2141
+ * - Support for assistive technology navigation
2142
+ *
2143
+ * @features
2144
+ * - Automatic hiding when parent sidebar is collapsed
2145
+ * - Smooth hover and focus transitions
2146
+ * - Consistent spacing with parent menu items
2147
+ * - Overflow text truncation for long labels
2148
+ *
2149
+ * @see {@link SidebarMenuSubItem} - Parent submenu item container
2150
+ * @see {@link SidebarMenuSub} - Submenu container
2151
+ * @see {@link SidebarMenuButton} - Parent menu button
2152
+ * @since 1.0.0
2153
+ */
2154
+ function SidebarMenuSubButton({
2155
+ asChild = false,
2156
+ size = "md",
2157
+ isActive = false,
2158
+ className,
2159
+ ...props
2160
+ }: React.ComponentProps<"a"> & {
2161
+ asChild?: boolean;
2162
+ size?: "sm" | "md";
2163
+ isActive?: boolean;
2164
+ }) {
2165
+ const Comp = asChild ? Slot : "a";
2166
+
2167
+ return (
2168
+ <Comp
2169
+ data-slot="sidebar-menu-sub-button"
2170
+ data-sidebar="menu-sub-button"
2171
+ data-size={size}
2172
+ data-active={isActive}
2173
+ className={cn(
2174
+ "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
2175
+ "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
2176
+ size === "sm" && "text-xs",
2177
+ size === "md" && "text-sm",
2178
+ "group-data-[collapsible=icon]:hidden",
2179
+ className,
2180
+ )}
2181
+ {...props}
2182
+ />
2183
+ );
2184
+ }
2185
+
2186
+ export {
2187
+ Sidebar,
2188
+ SidebarContent,
2189
+ SidebarFooter,
2190
+ SidebarGroup,
2191
+ SidebarGroupAction,
2192
+ SidebarGroupContent,
2193
+ SidebarGroupLabel,
2194
+ SidebarHeader,
2195
+ SidebarInput,
2196
+ SidebarInset,
2197
+ SidebarMenu,
2198
+ SidebarMenuAction,
2199
+ SidebarMenuBadge,
2200
+ SidebarMenuButton,
2201
+ SidebarMenuItem,
2202
+ SidebarMenuSkeleton,
2203
+ SidebarMenuSub,
2204
+ SidebarMenuSubButton,
2205
+ SidebarMenuSubItem,
2206
+ SidebarProvider,
2207
+ SidebarRail,
2208
+ SidebarSeparator,
2209
+ SidebarTrigger,
2210
+ useSidebar,
2211
+ };