@gv-tech/design-system 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (347) hide show
  1. package/.agent/skills/dogfood-components/SKILL.md +34 -0
  2. package/.agent/skills/maintain-component/SKILL.md +42 -0
  3. package/.github/workflows/release-please.yml +2 -2
  4. package/.prettierignore +2 -0
  5. package/.release-please-manifest.json +3 -0
  6. package/CHANGELOG.md +90 -0
  7. package/dist/App.d.ts.map +1 -1
  8. package/dist/components/docs/Footer.d.ts.map +1 -1
  9. package/dist/components/docs/PropsTable.d.ts +13 -0
  10. package/dist/components/docs/PropsTable.d.ts.map +1 -0
  11. package/dist/components/docs/Sidebar.d.ts.map +1 -1
  12. package/dist/components/docs/index.d.ts +1 -0
  13. package/dist/components/docs/index.d.ts.map +1 -1
  14. package/dist/components/ui/accordion.test.d.ts +2 -0
  15. package/dist/components/ui/accordion.test.d.ts.map +1 -0
  16. package/dist/components/ui/alert-dialog.test.d.ts +2 -0
  17. package/dist/components/ui/alert-dialog.test.d.ts.map +1 -0
  18. package/dist/components/ui/alert.test.d.ts +2 -0
  19. package/dist/components/ui/alert.test.d.ts.map +1 -0
  20. package/dist/components/ui/aspect-ratio.test.d.ts +2 -0
  21. package/dist/components/ui/aspect-ratio.test.d.ts.map +1 -0
  22. package/dist/components/ui/avatar.test.d.ts +2 -0
  23. package/dist/components/ui/avatar.test.d.ts.map +1 -0
  24. package/dist/components/ui/badge.test.d.ts +2 -0
  25. package/dist/components/ui/badge.test.d.ts.map +1 -0
  26. package/dist/components/ui/breadcrumb.test.d.ts +2 -0
  27. package/dist/components/ui/breadcrumb.test.d.ts.map +1 -0
  28. package/dist/components/ui/button.test.d.ts +2 -0
  29. package/dist/components/ui/button.test.d.ts.map +1 -0
  30. package/dist/components/ui/calendar.d.ts.map +1 -1
  31. package/dist/components/ui/calendar.test.d.ts +2 -0
  32. package/dist/components/ui/calendar.test.d.ts.map +1 -0
  33. package/dist/components/ui/card.test.d.ts +2 -0
  34. package/dist/components/ui/card.test.d.ts.map +1 -0
  35. package/dist/components/ui/carousel.test.d.ts +2 -0
  36. package/dist/components/ui/carousel.test.d.ts.map +1 -0
  37. package/dist/components/ui/chart.test.d.ts +2 -0
  38. package/dist/components/ui/chart.test.d.ts.map +1 -0
  39. package/dist/components/ui/checkbox.test.d.ts +2 -0
  40. package/dist/components/ui/checkbox.test.d.ts.map +1 -0
  41. package/dist/components/ui/collapsible.test.d.ts +2 -0
  42. package/dist/components/ui/collapsible.test.d.ts.map +1 -0
  43. package/dist/components/ui/command.test.d.ts +2 -0
  44. package/dist/components/ui/command.test.d.ts.map +1 -0
  45. package/dist/components/ui/context-menu.test.d.ts +2 -0
  46. package/dist/components/ui/context-menu.test.d.ts.map +1 -0
  47. package/dist/components/ui/dialog.test.d.ts +2 -0
  48. package/dist/components/ui/dialog.test.d.ts.map +1 -0
  49. package/dist/components/ui/drawer.test.d.ts +2 -0
  50. package/dist/components/ui/drawer.test.d.ts.map +1 -0
  51. package/dist/components/ui/dropdown-menu.test.d.ts +2 -0
  52. package/dist/components/ui/dropdown-menu.test.d.ts.map +1 -0
  53. package/dist/components/ui/form.test.d.ts +2 -0
  54. package/dist/components/ui/form.test.d.ts.map +1 -0
  55. package/dist/components/ui/hover-card.test.d.ts +2 -0
  56. package/dist/components/ui/hover-card.test.d.ts.map +1 -0
  57. package/dist/components/ui/input.test.d.ts +2 -0
  58. package/dist/components/ui/input.test.d.ts.map +1 -0
  59. package/dist/components/ui/label.test.d.ts +2 -0
  60. package/dist/components/ui/label.test.d.ts.map +1 -0
  61. package/dist/components/ui/menubar.test.d.ts +2 -0
  62. package/dist/components/ui/menubar.test.d.ts.map +1 -0
  63. package/dist/components/ui/navigation-menu.test.d.ts +2 -0
  64. package/dist/components/ui/navigation-menu.test.d.ts.map +1 -0
  65. package/dist/components/ui/pagination.test.d.ts +2 -0
  66. package/dist/components/ui/pagination.test.d.ts.map +1 -0
  67. package/dist/components/ui/popover.test.d.ts +2 -0
  68. package/dist/components/ui/popover.test.d.ts.map +1 -0
  69. package/dist/components/ui/progress.d.ts.map +1 -1
  70. package/dist/components/ui/progress.test.d.ts +2 -0
  71. package/dist/components/ui/progress.test.d.ts.map +1 -0
  72. package/dist/components/ui/radio-group.test.d.ts +2 -0
  73. package/dist/components/ui/radio-group.test.d.ts.map +1 -0
  74. package/dist/components/ui/resizable.test.d.ts +2 -0
  75. package/dist/components/ui/resizable.test.d.ts.map +1 -0
  76. package/dist/components/ui/scroll-area.test.d.ts +2 -0
  77. package/dist/components/ui/scroll-area.test.d.ts.map +1 -0
  78. package/dist/components/ui/search.d.ts +16 -0
  79. package/dist/components/ui/search.d.ts.map +1 -0
  80. package/dist/components/ui/search.test.d.ts +2 -0
  81. package/dist/components/ui/search.test.d.ts.map +1 -0
  82. package/dist/components/ui/select.test.d.ts +2 -0
  83. package/dist/components/ui/select.test.d.ts.map +1 -0
  84. package/dist/components/ui/separator.test.d.ts +2 -0
  85. package/dist/components/ui/separator.test.d.ts.map +1 -0
  86. package/dist/components/ui/sheet.test.d.ts +2 -0
  87. package/dist/components/ui/sheet.test.d.ts.map +1 -0
  88. package/dist/components/ui/skeleton.test.d.ts +2 -0
  89. package/dist/components/ui/skeleton.test.d.ts.map +1 -0
  90. package/dist/components/ui/slider.test.d.ts +2 -0
  91. package/dist/components/ui/slider.test.d.ts.map +1 -0
  92. package/dist/components/ui/sonner.test.d.ts +2 -0
  93. package/dist/components/ui/sonner.test.d.ts.map +1 -0
  94. package/dist/components/ui/switch.test.d.ts +2 -0
  95. package/dist/components/ui/switch.test.d.ts.map +1 -0
  96. package/dist/components/ui/table.test.d.ts +2 -0
  97. package/dist/components/ui/table.test.d.ts.map +1 -0
  98. package/dist/components/ui/tabs.test.d.ts +2 -0
  99. package/dist/components/ui/tabs.test.d.ts.map +1 -0
  100. package/dist/components/ui/textarea.test.d.ts +2 -0
  101. package/dist/components/ui/textarea.test.d.ts.map +1 -0
  102. package/dist/components/ui/theme-toggle.d.ts +17 -0
  103. package/dist/components/ui/theme-toggle.d.ts.map +1 -0
  104. package/dist/components/ui/toast.test.d.ts +2 -0
  105. package/dist/components/ui/toast.test.d.ts.map +1 -0
  106. package/dist/components/ui/toggle-group.test.d.ts +2 -0
  107. package/dist/components/ui/toggle-group.test.d.ts.map +1 -0
  108. package/dist/components/ui/toggle.test.d.ts +2 -0
  109. package/dist/components/ui/toggle.test.d.ts.map +1 -0
  110. package/dist/components/ui/tooltip.test.d.ts +2 -0
  111. package/dist/components/ui/tooltip.test.d.ts.map +1 -0
  112. package/dist/index.cjs.js +3 -3
  113. package/dist/index.cjs.js.map +1 -1
  114. package/dist/index.d.ts +2 -0
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.es.js +978 -860
  117. package/dist/index.es.js.map +1 -1
  118. package/dist/lib/tokens.d.ts +54 -0
  119. package/dist/lib/tokens.d.ts.map +1 -0
  120. package/dist/pages/ColorTokensDocs.d.ts +2 -0
  121. package/dist/pages/ColorTokensDocs.d.ts.map +1 -0
  122. package/dist/pages/GettingStarted.d.ts.map +1 -1
  123. package/dist/pages/components/AccordionDocs.d.ts.map +1 -1
  124. package/dist/pages/components/AlertDialogDocs.d.ts.map +1 -1
  125. package/dist/pages/components/AlertDocs.d.ts.map +1 -1
  126. package/dist/pages/components/AspectRatioDocs.d.ts.map +1 -1
  127. package/dist/pages/components/AvatarDocs.d.ts.map +1 -1
  128. package/dist/pages/components/BadgeDocs.d.ts.map +1 -1
  129. package/dist/pages/components/BreadcrumbDocs.d.ts.map +1 -1
  130. package/dist/pages/components/ButtonDocs.d.ts.map +1 -1
  131. package/dist/pages/components/CalendarDocs.d.ts.map +1 -1
  132. package/dist/pages/components/CardDocs.d.ts.map +1 -1
  133. package/dist/pages/components/CarouselDocs.d.ts.map +1 -1
  134. package/dist/pages/components/ChartDocs.d.ts.map +1 -1
  135. package/dist/pages/components/CheckboxDocs.d.ts.map +1 -1
  136. package/dist/pages/components/CollapsibleDocs.d.ts.map +1 -1
  137. package/dist/pages/components/CommandDocs.d.ts.map +1 -1
  138. package/dist/pages/components/ContextMenuDocs.d.ts.map +1 -1
  139. package/dist/pages/components/DialogDocs.d.ts.map +1 -1
  140. package/dist/pages/components/DrawerDocs.d.ts.map +1 -1
  141. package/dist/pages/components/DropdownMenuDocs.d.ts.map +1 -1
  142. package/dist/pages/components/FormDocs.d.ts.map +1 -1
  143. package/dist/pages/components/HoverCardDocs.d.ts.map +1 -1
  144. package/dist/pages/components/InputDocs.d.ts.map +1 -1
  145. package/dist/pages/components/LabelDocs.d.ts.map +1 -1
  146. package/dist/pages/components/MenubarDocs.d.ts.map +1 -1
  147. package/dist/pages/components/NavigationMenuDocs.d.ts.map +1 -1
  148. package/dist/pages/components/PaginationDocs.d.ts.map +1 -1
  149. package/dist/pages/components/PopoverDocs.d.ts.map +1 -1
  150. package/dist/pages/components/ProgressDocs.d.ts.map +1 -1
  151. package/dist/pages/components/RadioGroupDocs.d.ts.map +1 -1
  152. package/dist/pages/components/ResizableDocs.d.ts.map +1 -1
  153. package/dist/pages/components/ScrollAreaDocs.d.ts.map +1 -1
  154. package/dist/pages/components/SearchDocs.d.ts +2 -0
  155. package/dist/pages/components/SearchDocs.d.ts.map +1 -0
  156. package/dist/pages/components/SelectDocs.d.ts.map +1 -1
  157. package/dist/pages/components/SeparatorDocs.d.ts.map +1 -1
  158. package/dist/pages/components/SheetDocs.d.ts.map +1 -1
  159. package/dist/pages/components/SkeletonDocs.d.ts.map +1 -1
  160. package/dist/pages/components/SliderDocs.d.ts.map +1 -1
  161. package/dist/pages/components/SonnerDocs.d.ts.map +1 -1
  162. package/dist/pages/components/SwitchDocs.d.ts.map +1 -1
  163. package/dist/pages/components/TableDocs.d.ts.map +1 -1
  164. package/dist/pages/components/TabsDocs.d.ts.map +1 -1
  165. package/dist/pages/components/TextareaDocs.d.ts.map +1 -1
  166. package/dist/pages/components/ThemeToggleDocs.d.ts +2 -0
  167. package/dist/pages/components/ThemeToggleDocs.d.ts.map +1 -0
  168. package/dist/pages/components/ToastDocs.d.ts.map +1 -1
  169. package/dist/pages/components/ToggleDocs.d.ts.map +1 -1
  170. package/dist/pages/components/ToggleGroupDocs.d.ts.map +1 -1
  171. package/dist/pages/components/TooltipDocs.d.ts.map +1 -1
  172. package/dist/pages/index.d.ts +3 -0
  173. package/dist/pages/index.d.ts.map +1 -1
  174. package/dist/registry/accordion.test.json +13 -0
  175. package/dist/registry/alert-dialog.test.json +13 -0
  176. package/dist/registry/alert.test.json +13 -0
  177. package/dist/registry/aspect-ratio.test.json +13 -0
  178. package/dist/registry/avatar.test.json +13 -0
  179. package/dist/registry/badge.test.json +13 -0
  180. package/dist/registry/breadcrumb.test.json +13 -0
  181. package/dist/registry/button.test.json +13 -0
  182. package/dist/registry/calendar.json +1 -1
  183. package/dist/registry/calendar.test.json +13 -0
  184. package/dist/registry/card.test.json +13 -0
  185. package/dist/registry/carousel.test.json +13 -0
  186. package/dist/registry/chart.test.json +13 -0
  187. package/dist/registry/checkbox.test.json +13 -0
  188. package/dist/registry/collapsible.test.json +13 -0
  189. package/dist/registry/command.test.json +13 -0
  190. package/dist/registry/context-menu.test.json +13 -0
  191. package/dist/registry/dialog.test.json +13 -0
  192. package/dist/registry/drawer.test.json +13 -0
  193. package/dist/registry/dropdown-menu.test.json +13 -0
  194. package/dist/registry/form.test.json +13 -0
  195. package/dist/registry/hover-card.test.json +13 -0
  196. package/dist/registry/index.json +336 -0
  197. package/dist/registry/input.test.json +13 -0
  198. package/dist/registry/label.test.json +13 -0
  199. package/dist/registry/menubar.test.json +13 -0
  200. package/dist/registry/navigation-menu.test.json +13 -0
  201. package/dist/registry/pagination.test.json +13 -0
  202. package/dist/registry/popover.test.json +13 -0
  203. package/dist/registry/progress.json +1 -1
  204. package/dist/registry/progress.test.json +13 -0
  205. package/dist/registry/radio-group.test.json +13 -0
  206. package/dist/registry/resizable.test.json +13 -0
  207. package/dist/registry/scroll-area.test.json +13 -0
  208. package/dist/registry/search.json +13 -0
  209. package/dist/registry/search.test.json +13 -0
  210. package/dist/registry/select.test.json +13 -0
  211. package/dist/registry/separator.test.json +13 -0
  212. package/dist/registry/sheet.test.json +13 -0
  213. package/dist/registry/skeleton.test.json +13 -0
  214. package/dist/registry/slider.test.json +13 -0
  215. package/dist/registry/sonner.test.json +13 -0
  216. package/dist/registry/switch.test.json +13 -0
  217. package/dist/registry/table.test.json +13 -0
  218. package/dist/registry/tabs.test.json +13 -0
  219. package/dist/registry/textarea.test.json +13 -0
  220. package/dist/registry/theme-toggle.json +13 -0
  221. package/dist/registry/toast.test.json +13 -0
  222. package/dist/registry/toggle-group.test.json +13 -0
  223. package/dist/registry/toggle.test.json +13 -0
  224. package/dist/registry/tooltip.test.json +13 -0
  225. package/dist/setupTests.d.ts +2 -0
  226. package/dist/setupTests.d.ts.map +1 -0
  227. package/dist/{vendor-ZhQmrf1h.mjs → vendor-BLvpSabH.mjs} +7238 -7136
  228. package/dist/vendor-BLvpSabH.mjs.map +1 -0
  229. package/dist/vendor-n4WFhtJT.js +73 -0
  230. package/dist/vendor-n4WFhtJT.js.map +1 -0
  231. package/eslint.config.mjs +8 -81
  232. package/package.json +44 -46
  233. package/release-please-config.json +36 -0
  234. package/src/App.tsx +70 -7
  235. package/src/components/docs/Footer.tsx +51 -30
  236. package/src/components/docs/PropsTable.tsx +43 -0
  237. package/src/components/docs/Sidebar.tsx +57 -71
  238. package/src/components/docs/index.ts +1 -0
  239. package/src/components/ui/accordion.test.tsx +86 -0
  240. package/src/components/ui/alert-dialog.test.tsx +89 -0
  241. package/src/components/ui/alert.test.tsx +33 -0
  242. package/src/components/ui/aspect-ratio.test.tsx +34 -0
  243. package/src/components/ui/avatar.test.tsx +33 -0
  244. package/src/components/ui/badge.test.tsx +24 -0
  245. package/src/components/ui/breadcrumb.test.tsx +55 -0
  246. package/src/components/ui/button.test.tsx +62 -0
  247. package/src/components/ui/calendar.test.tsx +23 -0
  248. package/src/components/ui/calendar.tsx +14 -10
  249. package/src/components/ui/card.test.tsx +35 -0
  250. package/src/components/ui/carousel.test.tsx +37 -0
  251. package/src/components/ui/chart.test.tsx +62 -0
  252. package/src/components/ui/checkbox.test.tsx +30 -0
  253. package/src/components/ui/collapsible.test.tsx +51 -0
  254. package/src/components/ui/command.test.tsx +79 -0
  255. package/src/components/ui/context-menu.test.tsx +37 -0
  256. package/src/components/ui/dialog.test.tsx +66 -0
  257. package/src/components/ui/drawer.test.tsx +68 -0
  258. package/src/components/ui/dropdown-menu.test.tsx +93 -0
  259. package/src/components/ui/form.test.tsx +85 -0
  260. package/src/components/ui/hover-card.test.tsx +48 -0
  261. package/src/components/ui/input.test.tsx +33 -0
  262. package/src/components/ui/label.test.tsx +27 -0
  263. package/src/components/ui/menubar.test.tsx +92 -0
  264. package/src/components/ui/navigation-menu.test.tsx +53 -0
  265. package/src/components/ui/pagination.test.tsx +57 -0
  266. package/src/components/ui/popover.test.tsx +31 -0
  267. package/src/components/ui/progress.test.tsx +18 -0
  268. package/src/components/ui/progress.tsx +1 -0
  269. package/src/components/ui/radio-group.test.tsx +39 -0
  270. package/src/components/ui/resizable.test.tsx +23 -0
  271. package/src/components/ui/scroll-area.test.tsx +15 -0
  272. package/src/components/ui/search.test.tsx +75 -0
  273. package/src/components/ui/search.tsx +93 -0
  274. package/src/components/ui/select.test.tsx +42 -0
  275. package/src/components/ui/separator.test.tsx +16 -0
  276. package/src/components/ui/sheet.test.tsx +48 -0
  277. package/src/components/ui/skeleton.test.tsx +13 -0
  278. package/src/components/ui/slider.test.tsx +18 -0
  279. package/src/components/ui/sonner.test.tsx +13 -0
  280. package/src/components/ui/switch.test.tsx +22 -0
  281. package/src/components/ui/table.test.tsx +29 -0
  282. package/src/components/ui/tabs.test.tsx +43 -0
  283. package/src/components/ui/textarea.test.tsx +21 -0
  284. package/src/components/ui/theme-toggle.tsx +108 -0
  285. package/src/components/ui/toast.test.tsx +42 -0
  286. package/src/components/ui/toggle-group.test.tsx +40 -0
  287. package/src/components/ui/toggle.test.tsx +21 -0
  288. package/src/components/ui/tooltip.test.tsx +25 -0
  289. package/src/globals.css +39 -34
  290. package/src/index.ts +2 -0
  291. package/src/lib/tokens.ts +54 -0
  292. package/src/pages/ColorTokensDocs.tsx +181 -0
  293. package/src/pages/GettingStarted.tsx +55 -35
  294. package/src/pages/components/AccordionDocs.tsx +109 -0
  295. package/src/pages/components/AlertDialogDocs.tsx +88 -0
  296. package/src/pages/components/AlertDocs.tsx +20 -0
  297. package/src/pages/components/AspectRatioDocs.tsx +21 -0
  298. package/src/pages/components/AvatarDocs.tsx +48 -0
  299. package/src/pages/components/BadgeDocs.tsx +20 -0
  300. package/src/pages/components/BreadcrumbDocs.tsx +33 -0
  301. package/src/pages/components/ButtonDocs.tsx +43 -0
  302. package/src/pages/components/CalendarDocs.tsx +43 -0
  303. package/src/pages/components/CardDocs.tsx +20 -0
  304. package/src/pages/components/CarouselDocs.tsx +31 -0
  305. package/src/pages/components/ChartDocs.tsx +131 -101
  306. package/src/pages/components/CheckboxDocs.tsx +58 -0
  307. package/src/pages/components/CollapsibleDocs.tsx +51 -0
  308. package/src/pages/components/CommandDocs.tsx +109 -0
  309. package/src/pages/components/ContextMenuDocs.tsx +65 -0
  310. package/src/pages/components/DialogDocs.tsx +98 -11
  311. package/src/pages/components/DrawerDocs.tsx +210 -15
  312. package/src/pages/components/DropdownMenuDocs.tsx +273 -11
  313. package/src/pages/components/FormDocs.tsx +149 -70
  314. package/src/pages/components/HoverCardDocs.tsx +82 -5
  315. package/src/pages/components/InputDocs.tsx +51 -20
  316. package/src/pages/components/LabelDocs.tsx +40 -9
  317. package/src/pages/components/MenubarDocs.tsx +191 -18
  318. package/src/pages/components/NavigationMenuDocs.tsx +147 -49
  319. package/src/pages/components/PaginationDocs.tsx +27 -2
  320. package/src/pages/components/PopoverDocs.tsx +124 -2
  321. package/src/pages/components/ProgressDocs.tsx +54 -24
  322. package/src/pages/components/RadioGroupDocs.tsx +95 -1
  323. package/src/pages/components/ResizableDocs.tsx +102 -75
  324. package/src/pages/components/ScrollAreaDocs.tsx +64 -51
  325. package/src/pages/components/SearchDocs.tsx +194 -0
  326. package/src/pages/components/SelectDocs.tsx +119 -48
  327. package/src/pages/components/SeparatorDocs.tsx +37 -2
  328. package/src/pages/components/SheetDocs.tsx +112 -38
  329. package/src/pages/components/SkeletonDocs.tsx +16 -20
  330. package/src/pages/components/SliderDocs.tsx +96 -10
  331. package/src/pages/components/SonnerDocs.tsx +89 -61
  332. package/src/pages/components/SwitchDocs.tsx +65 -10
  333. package/src/pages/components/TableDocs.tsx +89 -14
  334. package/src/pages/components/TabsDocs.tsx +149 -37
  335. package/src/pages/components/TextareaDocs.tsx +38 -32
  336. package/src/pages/components/ThemeToggleDocs.tsx +122 -0
  337. package/src/pages/components/ToastDocs.tsx +104 -65
  338. package/src/pages/components/ToggleDocs.tsx +55 -38
  339. package/src/pages/components/ToggleGroupDocs.tsx +96 -58
  340. package/src/pages/components/TooltipDocs.tsx +112 -3
  341. package/src/pages/index.ts +3 -0
  342. package/src/setupTests.ts +47 -0
  343. package/temp.md +292 -0
  344. package/vitest.config.ts +4 -0
  345. package/dist/vendor-CMSUBoIg.js +0 -73
  346. package/dist/vendor-CMSUBoIg.js.map +0 -1
  347. package/dist/vendor-ZhQmrf1h.mjs.map +0 -1
@@ -0,0 +1,85 @@
1
+ import { zodResolver } from '@hookform/resolvers/zod';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { useForm } from 'react-hook-form';
5
+ import { describe, expect, it } from 'vitest';
6
+ import { z } from 'zod';
7
+ import { Button } from './button';
8
+ import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from './form';
9
+ import { Input } from './input';
10
+
11
+ const formSchema = z.object({
12
+ username: z.string().min(2, {
13
+ message: 'Username must be at least 2 characters.',
14
+ }),
15
+ });
16
+
17
+ function TestForm({ onSubmit }: { onSubmit: (values: z.infer<typeof formSchema>) => void }) {
18
+ const form = useForm<z.infer<typeof formSchema>>({
19
+ resolver: zodResolver(formSchema),
20
+ defaultValues: {
21
+ username: '',
22
+ },
23
+ });
24
+
25
+ return (
26
+ <Form {...form}>
27
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
28
+ <FormField
29
+ control={form.control}
30
+ name="username"
31
+ render={({ field }) => (
32
+ <FormItem>
33
+ <FormLabel>Username</FormLabel>
34
+ <FormControl>
35
+ <Input placeholder="shadcn" {...field} />
36
+ </FormControl>
37
+ <FormDescription>This is your public display name.</FormDescription>
38
+ <FormMessage />
39
+ </FormItem>
40
+ )}
41
+ />
42
+ <Button type="submit">Submit</Button>
43
+ </form>
44
+ </Form>
45
+ );
46
+ }
47
+
48
+ describe('Form', () => {
49
+ it('renders form fields correctly', () => {
50
+ render(<TestForm onSubmit={() => {}} />);
51
+
52
+ expect(screen.getByLabelText('Username')).toBeInTheDocument();
53
+ expect(screen.getByPlaceholderText('shadcn')).toBeInTheDocument();
54
+ expect(screen.getByText('This is your public display name.')).toBeInTheDocument();
55
+ expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
56
+ });
57
+
58
+ it('validates input and displays error message', async () => {
59
+ const user = userEvent.setup();
60
+ render(<TestForm onSubmit={() => {}} />);
61
+
62
+ const submitButton = screen.getByRole('button', { name: 'Submit' });
63
+ await user.click(submitButton);
64
+
65
+ await waitFor(() => {
66
+ expect(screen.getByText('Username must be at least 2 characters.')).toBeVisible();
67
+ });
68
+ });
69
+
70
+ it('submits valid data', async () => {
71
+ const user = userEvent.setup();
72
+ const { vi } = await import('vitest');
73
+ const mockSubmit = vi.fn();
74
+
75
+ render(<TestForm onSubmit={mockSubmit} />);
76
+
77
+ const input = screen.getByLabelText('Username');
78
+ await user.type(input, 'johndoe');
79
+ await user.click(screen.getByRole('button', { name: 'Submit' }));
80
+
81
+ await waitFor(() => {
82
+ expect(mockSubmit).toHaveBeenCalledWith({ username: 'johndoe' }, expect.anything());
83
+ });
84
+ });
85
+ });
@@ -0,0 +1,48 @@
1
+ import { render, screen, waitFor } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { HoverCard, HoverCardContent, HoverCardTrigger } from './hover-card';
5
+
6
+ describe('HoverCard', () => {
7
+ it('renders trigger correctly', () => {
8
+ render(
9
+ <HoverCard>
10
+ <HoverCardTrigger>Hover me</HoverCardTrigger>
11
+ <HoverCardContent>Content</HoverCardContent>
12
+ </HoverCard>,
13
+ );
14
+
15
+ expect(screen.getByText('Hover me')).toBeInTheDocument();
16
+ });
17
+
18
+ it('shows content on hover', async () => {
19
+ const user = userEvent.setup();
20
+ render(
21
+ <HoverCard openDelay={0} closeDelay={0}>
22
+ <HoverCardTrigger>Hover me</HoverCardTrigger>
23
+ <HoverCardContent>Content</HoverCardContent>
24
+ </HoverCard>,
25
+ );
26
+
27
+ const trigger = screen.getByText('Hover me');
28
+
29
+ // Initial state
30
+ expect(screen.queryByText('Content')).not.toBeInTheDocument();
31
+
32
+ // Hover
33
+ await user.hover(trigger);
34
+
35
+ // Should be visible
36
+ await waitFor(() => {
37
+ expect(screen.getByText('Content')).toBeVisible();
38
+ });
39
+
40
+ // Unhover
41
+ await user.unhover(trigger);
42
+
43
+ // Should be hidden
44
+ await waitFor(() => {
45
+ expect(screen.queryByText('Content')).not.toBeInTheDocument();
46
+ });
47
+ });
48
+ });
@@ -0,0 +1,33 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import * as React from 'react';
4
+ import { describe, expect, it } from 'vitest';
5
+ import { Input } from './input';
6
+
7
+ describe('Input', () => {
8
+ it('renders correctly', () => {
9
+ render(<Input placeholder="Enter text" />);
10
+ expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument();
11
+ });
12
+
13
+ it('accepts user input', async () => {
14
+ const user = userEvent.setup();
15
+ render(<Input placeholder="Enter text" />);
16
+
17
+ const input = screen.getByPlaceholderText('Enter text');
18
+ await user.type(input, 'Hello World');
19
+
20
+ expect(input).toHaveValue('Hello World');
21
+ });
22
+
23
+ it('handles disabled state', () => {
24
+ render(<Input disabled placeholder="Disabled" />);
25
+ expect(screen.getByPlaceholderText('Disabled')).toBeDisabled();
26
+ });
27
+
28
+ it('forwards ref', () => {
29
+ const ref = React.createRef<HTMLInputElement>();
30
+ render(<Input ref={ref} />);
31
+ expect(ref.current).toBeInstanceOf(HTMLInputElement);
32
+ });
33
+ });
@@ -0,0 +1,27 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Label } from './label';
4
+
5
+ describe('Label', () => {
6
+ it('renders correctly', () => {
7
+ render(<Label>Test Label</Label>);
8
+ expect(screen.getByText('Test Label')).toBeInTheDocument();
9
+ });
10
+
11
+ it('renders within the DOM', () => {
12
+ const { container } = render(<Label>Test Label</Label>);
13
+ expect(container.firstChild).toBeInTheDocument();
14
+ });
15
+
16
+ it('supports htmlFor attribute', () => {
17
+ render(
18
+ <>
19
+ <Label htmlFor="test-input">Test Input</Label>
20
+ <input id="test-input" />
21
+ </>,
22
+ );
23
+
24
+ const label = screen.getByText('Test Input');
25
+ expect(label).toHaveAttribute('for', 'test-input');
26
+ });
27
+ });
@@ -0,0 +1,92 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+ import {
5
+ Menubar,
6
+ MenubarCheckboxItem,
7
+ MenubarContent,
8
+ MenubarItem,
9
+ MenubarMenu,
10
+ MenubarRadioGroup,
11
+ MenubarRadioItem,
12
+ MenubarTrigger,
13
+ } from './menubar';
14
+
15
+ describe('Menubar', () => {
16
+ it('renders trigger correctly', () => {
17
+ render(
18
+ <Menubar>
19
+ <MenubarMenu>
20
+ <MenubarTrigger>File</MenubarTrigger>
21
+ <MenubarContent>
22
+ <MenubarItem>New Tab</MenubarItem>
23
+ </MenubarContent>
24
+ </MenubarMenu>
25
+ </Menubar>,
26
+ );
27
+
28
+ expect(screen.getByText('File')).toBeInTheDocument();
29
+ });
30
+
31
+ it('opens menu on click', async () => {
32
+ const user = userEvent.setup();
33
+ render(
34
+ <Menubar>
35
+ <MenubarMenu>
36
+ <MenubarTrigger>File</MenubarTrigger>
37
+ <MenubarContent>
38
+ <MenubarItem>New Tab</MenubarItem>
39
+ <MenubarItem>New Window</MenubarItem>
40
+ </MenubarContent>
41
+ </MenubarMenu>
42
+ </Menubar>,
43
+ );
44
+
45
+ await user.click(screen.getByText('File'));
46
+
47
+ expect(screen.getByText('New Tab')).toBeVisible();
48
+ expect(screen.getByText('New Window')).toBeVisible();
49
+ });
50
+
51
+ it('handles checkbox items', async () => {
52
+ const user = userEvent.setup();
53
+ render(
54
+ <Menubar>
55
+ <MenubarMenu>
56
+ <MenubarTrigger>View</MenubarTrigger>
57
+ <MenubarContent>
58
+ <MenubarCheckboxItem checked>Show Sidebar</MenubarCheckboxItem>
59
+ <MenubarCheckboxItem checked={false}>Show Status Bar</MenubarCheckboxItem>
60
+ </MenubarContent>
61
+ </MenubarMenu>
62
+ </Menubar>,
63
+ );
64
+
65
+ await user.click(screen.getByText('View'));
66
+
67
+ expect(screen.getByRole('menuitemcheckbox', { name: 'Show Sidebar' })).toBeChecked();
68
+ expect(screen.getByRole('menuitemcheckbox', { name: 'Show Status Bar' })).not.toBeChecked();
69
+ });
70
+
71
+ it('handles radio items', async () => {
72
+ const user = userEvent.setup();
73
+ render(
74
+ <Menubar>
75
+ <MenubarMenu>
76
+ <MenubarTrigger>Profiles</MenubarTrigger>
77
+ <MenubarContent>
78
+ <MenubarRadioGroup value="andy">
79
+ <MenubarRadioItem value="andy">Andy</MenubarRadioItem>
80
+ <MenubarRadioItem value="benoit">Benoit</MenubarRadioItem>
81
+ </MenubarRadioGroup>
82
+ </MenubarContent>
83
+ </MenubarMenu>
84
+ </Menubar>,
85
+ );
86
+
87
+ await user.click(screen.getByText('Profiles'));
88
+
89
+ expect(screen.getByRole('menuitemradio', { name: 'Andy' })).toBeChecked();
90
+ expect(screen.getByRole('menuitemradio', { name: 'Benoit' })).not.toBeChecked();
91
+ });
92
+ });
@@ -0,0 +1,53 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+ import {
5
+ NavigationMenu,
6
+ NavigationMenuContent,
7
+ NavigationMenuItem,
8
+ NavigationMenuLink,
9
+ NavigationMenuList,
10
+ NavigationMenuTrigger,
11
+ } from './navigation-menu';
12
+
13
+ describe('NavigationMenu', () => {
14
+ it('renders trigger correctly', () => {
15
+ render(
16
+ <NavigationMenu>
17
+ <NavigationMenuList>
18
+ <NavigationMenuItem>
19
+ <NavigationMenuTrigger>Item One</NavigationMenuTrigger>
20
+ <NavigationMenuContent>
21
+ <NavigationMenuLink>Link One</NavigationMenuLink>
22
+ </NavigationMenuContent>
23
+ </NavigationMenuItem>
24
+ </NavigationMenuList>
25
+ </NavigationMenu>,
26
+ );
27
+
28
+ expect(screen.getByText('Item One')).toBeInTheDocument();
29
+ });
30
+
31
+ it('shows content on click (or hover depending on implementation)', async () => {
32
+ // Radix Navigation Menu usually works on hover for desktop, click for touch/mobile.
33
+ // In JSDOM, we can simulate clicks.
34
+ const user = userEvent.setup();
35
+ render(
36
+ <NavigationMenu>
37
+ <NavigationMenuList>
38
+ <NavigationMenuItem>
39
+ <NavigationMenuTrigger>Item One</NavigationMenuTrigger>
40
+ <NavigationMenuContent>
41
+ <NavigationMenuLink>Link One</NavigationMenuLink>
42
+ </NavigationMenuContent>
43
+ </NavigationMenuItem>
44
+ </NavigationMenuList>
45
+ </NavigationMenu>,
46
+ );
47
+
48
+ const trigger = screen.getByText('Item One');
49
+ await user.click(trigger);
50
+
51
+ expect(screen.getByText('Link One')).toBeVisible();
52
+ });
53
+ });
@@ -0,0 +1,57 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import {
4
+ Pagination,
5
+ PaginationContent,
6
+ PaginationEllipsis,
7
+ PaginationItem,
8
+ PaginationLink,
9
+ PaginationNext,
10
+ PaginationPrevious,
11
+ } from './pagination';
12
+
13
+ describe('Pagination', () => {
14
+ it('renders correctly', () => {
15
+ render(
16
+ <Pagination>
17
+ <PaginationContent>
18
+ <PaginationItem>
19
+ <PaginationPrevious href="#" />
20
+ </PaginationItem>
21
+ <PaginationItem>
22
+ <PaginationLink href="#">1</PaginationLink>
23
+ </PaginationItem>
24
+ <PaginationItem>
25
+ <PaginationEllipsis />
26
+ </PaginationItem>
27
+ <PaginationItem>
28
+ <PaginationNext href="#" />
29
+ </PaginationItem>
30
+ </PaginationContent>
31
+ </Pagination>,
32
+ );
33
+
34
+ expect(screen.getByRole('navigation', { name: 'pagination' })).toBeInTheDocument();
35
+ expect(screen.getByText('Previous')).toBeInTheDocument();
36
+ expect(screen.getByText('1')).toBeInTheDocument();
37
+ expect(screen.getByText('Next')).toBeInTheDocument();
38
+ expect(screen.getByText('More pages')).toBeInTheDocument();
39
+ });
40
+
41
+ it('marks active page correctly', () => {
42
+ render(
43
+ <Pagination>
44
+ <PaginationContent>
45
+ <PaginationItem>
46
+ <PaginationLink href="#" isActive>
47
+ 1
48
+ </PaginationLink>
49
+ </PaginationItem>
50
+ </PaginationContent>
51
+ </Pagination>,
52
+ );
53
+
54
+ const link = screen.getByText('1').closest('a');
55
+ expect(link).toHaveAttribute('aria-current', 'page');
56
+ });
57
+ });
@@ -0,0 +1,31 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { Popover, PopoverContent, PopoverTrigger } from './popover';
5
+
6
+ describe('Popover', () => {
7
+ it('renders trigger correctly', () => {
8
+ render(
9
+ <Popover>
10
+ <PopoverTrigger>Open</PopoverTrigger>
11
+ <PopoverContent>Content</PopoverContent>
12
+ </Popover>,
13
+ );
14
+
15
+ expect(screen.getByText('Open')).toBeInTheDocument();
16
+ });
17
+
18
+ it('opens content on click', async () => {
19
+ const user = userEvent.setup();
20
+ render(
21
+ <Popover>
22
+ <PopoverTrigger>Open</PopoverTrigger>
23
+ <PopoverContent>Content</PopoverContent>
24
+ </Popover>,
25
+ );
26
+
27
+ await user.click(screen.getByText('Open'));
28
+
29
+ expect(screen.getByText('Content')).toBeVisible();
30
+ });
31
+ });
@@ -0,0 +1,18 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { Progress } from './progress';
4
+
5
+ describe('Progress', () => {
6
+ it('renders correctly', () => {
7
+ render(<Progress value={50} aria-label="progress-bar" />);
8
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
9
+ expect(screen.getByRole('progressbar')).toHaveAttribute('aria-valuenow', '50');
10
+ });
11
+
12
+ it('renders correctly with no value', () => {
13
+ render(<Progress aria-label="progress-bar" />);
14
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
15
+ // When value is undefined, Radix UI might behave in specific ways, typically indeterminate or 0.
16
+ // Our wrapper: transform: `translateX(-${100 - (value || 0)}%)` -> -100%
17
+ });
18
+ });
@@ -10,6 +10,7 @@ const Progress = React.forwardRef<
10
10
  <ProgressPrimitive.Root
11
11
  ref={ref}
12
12
  className={cn('relative h-2 w-full overflow-hidden rounded-full bg-primary/20', className)}
13
+ value={value}
13
14
  {...props}
14
15
  >
15
16
  <ProgressPrimitive.Indicator
@@ -0,0 +1,39 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { RadioGroup, RadioGroupItem } from './radio-group';
5
+
6
+ describe('RadioGroup', () => {
7
+ it('renders correctly', () => {
8
+ render(
9
+ <RadioGroup defaultValue="option-one">
10
+ <RadioGroupItem value="option-one" id="option-one" aria-label="Option One" />
11
+ <RadioGroupItem value="option-two" id="option-two" aria-label="Option Two" />
12
+ </RadioGroup>,
13
+ );
14
+
15
+ expect(screen.getByRole('radio', { name: /Option One/i })).toBeInTheDocument();
16
+ // Radix RadioGroup renders standard inputs visually hidden.
17
+ // Testing library query by role 'radio' should find them.
18
+ // However, since we didn't provide labels, we might need to rely on 'checked' state or IDs.
19
+
20
+ const radio1 = screen.getByRole('radio', { checked: true });
21
+ expect(radio1).toBeInTheDocument();
22
+ expect(radio1).toHaveValue('option-one');
23
+ });
24
+
25
+ it('changes value on click', async () => {
26
+ const user = userEvent.setup();
27
+ render(
28
+ <RadioGroup defaultValue="option-one">
29
+ <RadioGroupItem value="option-one" />
30
+ <RadioGroupItem value="option-two" data-testid="radio-two" />
31
+ </RadioGroup>,
32
+ );
33
+
34
+ const radio2 = screen.getByTestId('radio-two');
35
+ await user.click(radio2);
36
+
37
+ expect(radio2).toBeChecked();
38
+ });
39
+ });
@@ -0,0 +1,23 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from './resizable';
4
+
5
+ describe('Resizable', () => {
6
+ it('renders correctly', () => {
7
+ // Basic render test
8
+ render(
9
+ <ResizablePanelGroup direction="horizontal">
10
+ <ResizablePanel defaultSize={50}>
11
+ <div>One</div>
12
+ </ResizablePanel>
13
+ <ResizableHandle />
14
+ <ResizablePanel defaultSize={50}>
15
+ <div>Two</div>
16
+ </ResizablePanel>
17
+ </ResizablePanelGroup>,
18
+ );
19
+
20
+ expect(screen.getByText('One')).toBeInTheDocument();
21
+ expect(screen.getByText('Two')).toBeInTheDocument();
22
+ });
23
+ });
@@ -0,0 +1,15 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { ScrollArea, ScrollBar } from './scroll-area';
4
+
5
+ describe('ScrollArea', () => {
6
+ it('renders correctly', () => {
7
+ render(
8
+ <ScrollArea className="h-[200px] w-[350px]">
9
+ <div>Content</div>
10
+ <ScrollBar />
11
+ </ScrollArea>,
12
+ );
13
+ expect(screen.getByText('Content')).toBeInTheDocument();
14
+ });
15
+ });
@@ -0,0 +1,75 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import * as React from 'react';
3
+ import { describe, expect, it, vi } from 'vitest';
4
+ import { CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Search, SearchTrigger } from './search';
5
+
6
+ // Mock CommandDialog since it uses Radix Dialog which might need a portal
7
+ vi.mock('@/components/ui/dialog', () => ({
8
+ Dialog: ({ children, open }: { children: React.ReactNode; open: boolean }) => (open ? <div>{children}</div> : null),
9
+ DialogContent: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
10
+ DialogPortal: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
11
+ DialogOverlay: () => null,
12
+ }));
13
+
14
+ describe('Search', () => {
15
+ it('renders search trigger', () => {
16
+ render(<SearchTrigger />);
17
+ expect(screen.getByText('Search docs...')).toBeInTheDocument();
18
+ });
19
+
20
+ it('opens search dialog when trigger is clicked (controlled)', () => {
21
+ const onOpenChange = vi.fn();
22
+ render(
23
+ <Search open={false} onOpenChange={onOpenChange}>
24
+ <CommandInput placeholder="Search..." />
25
+ </Search>,
26
+ );
27
+
28
+ // The dialog should be closed initially
29
+ expect(screen.queryByPlaceholderText('Search...')).not.toBeInTheDocument();
30
+ });
31
+
32
+ it('responds to keyboard shortcuts', () => {
33
+ render(
34
+ <Search>
35
+ <CommandInput placeholder="Search..." />
36
+ <CommandList>
37
+ <CommandItem>Result 1</CommandItem>
38
+ </CommandList>
39
+ </Search>,
40
+ );
41
+
42
+ // Simulate Cmd+K
43
+ fireEvent.keyDown(document, { key: 'k', metaKey: true });
44
+
45
+ // Check if dialog content is visible
46
+ expect(screen.getByPlaceholderText('Search...')).toBeInTheDocument();
47
+ });
48
+
49
+ it('filters results correctly', () => {
50
+ render(
51
+ <Search open={true}>
52
+ <CommandInput placeholder="Search..." />
53
+ <CommandList>
54
+ <CommandEmpty>No results.</CommandEmpty>
55
+ <CommandGroup heading="Components">
56
+ <SearchItem>Button</SearchItem>
57
+ <SearchItem>Input</SearchItem>
58
+ </CommandGroup>
59
+ </CommandList>
60
+ </Search>,
61
+ );
62
+
63
+ const input = screen.getByPlaceholderText('Search...');
64
+ fireEvent.change(input, { target: { value: 'But' } });
65
+
66
+ expect(screen.getByText('Button')).toBeInTheDocument();
67
+ // cmdk removes non-matching items from the DOM
68
+ expect(screen.queryByText('Input')).not.toBeInTheDocument();
69
+ });
70
+ });
71
+
72
+ // Helper component for testing
73
+ function SearchItem({ children }: { children: React.ReactNode }) {
74
+ return <CommandItem>{children}</CommandItem>;
75
+ }