@arolariu/components 0.5.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (972) hide show
  1. package/{changelog.md → CHANGELOG.md} +82 -0
  2. package/CONTRIBUTING.md +344 -265
  3. package/DEBUGGING.md +185 -103
  4. package/EXAMPLES.md +2976 -341
  5. package/{readme.md → README.md} +306 -203
  6. package/dist/components/ui/accordion.d.ts +157 -5
  7. package/dist/components/ui/accordion.d.ts.map +1 -1
  8. package/dist/components/ui/accordion.js +100 -22
  9. package/dist/components/ui/accordion.js.map +1 -1
  10. package/dist/components/ui/accordion.module.js +12 -0
  11. package/dist/components/ui/accordion.module.js.map +1 -0
  12. package/dist/components/ui/accordion_module.css +72 -0
  13. package/dist/components/ui/accordion_module.css.map +1 -0
  14. package/dist/components/ui/alert-dialog.d.ts +309 -18
  15. package/dist/components/ui/alert-dialog.d.ts.map +1 -1
  16. package/dist/components/ui/alert-dialog.js +149 -52
  17. package/dist/components/ui/alert-dialog.js.map +1 -1
  18. package/dist/components/ui/alert-dialog.module.js +13 -0
  19. package/dist/components/ui/alert-dialog.module.js.map +1 -0
  20. package/dist/components/ui/alert-dialog_module.css +89 -0
  21. package/dist/components/ui/alert-dialog_module.css.map +1 -0
  22. package/dist/components/ui/alert.d.ts +109 -6
  23. package/dist/components/ui/alert.d.ts.map +1 -1
  24. package/dist/components/ui/alert.js +12 -21
  25. package/dist/components/ui/alert.js.map +1 -1
  26. package/dist/components/ui/alert.module.js +11 -0
  27. package/dist/components/ui/alert.module.js.map +1 -0
  28. package/dist/components/ui/alert_module.css +59 -0
  29. package/dist/components/ui/alert_module.css.map +1 -0
  30. package/dist/components/ui/aspect-ratio.d.ts +24 -2
  31. package/dist/components/ui/aspect-ratio.d.ts.map +1 -1
  32. package/dist/components/ui/aspect-ratio.js +14 -3
  33. package/dist/components/ui/aspect-ratio.js.map +1 -1
  34. package/dist/components/ui/aspect-ratio.module.js +7 -0
  35. package/dist/components/ui/aspect-ratio.module.js.map +1 -0
  36. package/dist/components/ui/aspect-ratio_module.css +10 -0
  37. package/dist/components/ui/aspect-ratio_module.css.map +1 -0
  38. package/dist/components/ui/async-boundary.js +17 -0
  39. package/dist/components/ui/async-boundary.js.map +1 -0
  40. package/dist/components/ui/avatar.d.ts +88 -4
  41. package/dist/components/ui/avatar.d.ts.map +1 -1
  42. package/dist/components/ui/avatar.js +52 -20
  43. package/dist/components/ui/avatar.js.map +1 -1
  44. package/dist/components/ui/avatar.module.js +9 -0
  45. package/dist/components/ui/avatar.module.js.map +1 -0
  46. package/dist/components/ui/avatar_module.css +35 -0
  47. package/dist/components/ui/avatar_module.css.map +1 -0
  48. package/dist/components/ui/background-beams.d.ts +21 -3
  49. package/dist/components/ui/background-beams.d.ts.map +1 -1
  50. package/dist/components/ui/background-beams.js +22 -11
  51. package/dist/components/ui/background-beams.js.map +1 -1
  52. package/dist/components/ui/background-beams.module.js +8 -0
  53. package/dist/components/ui/background-beams.module.js.map +1 -0
  54. package/dist/components/ui/background-beams_module.css +22 -0
  55. package/dist/components/ui/background-beams_module.css.map +1 -0
  56. package/dist/components/ui/badge.d.ts +79 -6
  57. package/dist/components/ui/badge.d.ts.map +1 -1
  58. package/dist/components/ui/badge.js +19 -23
  59. package/dist/components/ui/badge.js.map +1 -1
  60. package/dist/components/ui/badge.module.js +11 -0
  61. package/dist/components/ui/badge.module.js.map +1 -0
  62. package/dist/components/ui/badge_module.css +63 -0
  63. package/dist/components/ui/badge_module.css.map +1 -0
  64. package/dist/components/ui/breadcrumb.d.ts +158 -13
  65. package/dist/components/ui/breadcrumb.d.ts.map +1 -1
  66. package/dist/components/ui/breadcrumb.js +39 -30
  67. package/dist/components/ui/breadcrumb.js.map +1 -1
  68. package/dist/components/ui/breadcrumb.module.js +14 -0
  69. package/dist/components/ui/breadcrumb.module.js.map +1 -0
  70. package/dist/components/ui/breadcrumb_module.css +90 -0
  71. package/dist/components/ui/breadcrumb_module.css.map +1 -0
  72. package/dist/components/ui/bubble-background.d.ts +38 -10
  73. package/dist/components/ui/bubble-background.d.ts.map +1 -1
  74. package/dist/components/ui/bubble-background.js +33 -35
  75. package/dist/components/ui/bubble-background.js.map +1 -1
  76. package/dist/components/ui/bubble-background.module.js +20 -0
  77. package/dist/components/ui/bubble-background.module.js.map +1 -0
  78. package/dist/components/ui/bubble-background_module.css +99 -0
  79. package/dist/components/ui/bubble-background_module.css.map +1 -0
  80. package/dist/components/ui/button-group.d.ts +88 -8
  81. package/dist/components/ui/button-group.d.ts.map +1 -1
  82. package/dist/components/ui/button-group.js +35 -32
  83. package/dist/components/ui/button-group.js.map +1 -1
  84. package/dist/components/ui/button-group.module.js +11 -0
  85. package/dist/components/ui/button-group.module.js.map +1 -0
  86. package/dist/components/ui/button-group_module.css +79 -0
  87. package/dist/components/ui/button-group_module.css.map +1 -0
  88. package/dist/components/ui/button.d.ts +82 -7
  89. package/dist/components/ui/button.d.ts.map +1 -1
  90. package/dist/components/ui/button.js +69 -34
  91. package/dist/components/ui/button.js.map +1 -1
  92. package/dist/components/ui/button.module.js +17 -0
  93. package/dist/components/ui/button.module.js.map +1 -0
  94. package/dist/components/ui/button_module.css +137 -0
  95. package/dist/components/ui/button_module.css.map +1 -0
  96. package/dist/components/ui/calendar.d.ts +36 -5
  97. package/dist/components/ui/calendar.d.ts.map +1 -1
  98. package/dist/components/ui/calendar.js +75 -64
  99. package/dist/components/ui/calendar.js.map +1 -1
  100. package/dist/components/ui/calendar.module.js +35 -0
  101. package/dist/components/ui/calendar.module.js.map +1 -0
  102. package/dist/components/ui/calendar_module.css +245 -0
  103. package/dist/components/ui/calendar_module.css.map +1 -0
  104. package/dist/components/ui/card-skeleton.js +41 -0
  105. package/dist/components/ui/card-skeleton.js.map +1 -0
  106. package/dist/components/ui/card-skeleton.module.js +15 -0
  107. package/dist/components/ui/card-skeleton.module.js.map +1 -0
  108. package/dist/components/ui/card-skeleton_module.css +54 -0
  109. package/dist/components/ui/card-skeleton_module.css.map +1 -0
  110. package/dist/components/ui/card.d.ts +162 -7
  111. package/dist/components/ui/card.d.ts.map +1 -1
  112. package/dist/components/ui/card.js +13 -13
  113. package/dist/components/ui/card.js.map +1 -1
  114. package/dist/components/ui/card.module.js +13 -0
  115. package/dist/components/ui/card.module.js.map +1 -0
  116. package/dist/components/ui/card_module.css +43 -0
  117. package/dist/components/ui/card_module.css.map +1 -0
  118. package/dist/components/ui/carousel.d.ts +127 -3
  119. package/dist/components/ui/carousel.d.ts.map +1 -1
  120. package/dist/components/ui/carousel.js +63 -36
  121. package/dist/components/ui/carousel.js.map +1 -1
  122. package/dist/components/ui/carousel.module.js +17 -0
  123. package/dist/components/ui/carousel.module.js.map +1 -0
  124. package/dist/components/ui/carousel_module.css +82 -0
  125. package/dist/components/ui/carousel_module.css.map +1 -0
  126. package/dist/components/ui/chart.d.ts +323 -13
  127. package/dist/components/ui/chart.d.ts.map +1 -1
  128. package/dist/components/ui/chart.js +224 -53
  129. package/dist/components/ui/chart.js.map +1 -1
  130. package/dist/components/ui/chart.module.js +27 -0
  131. package/dist/components/ui/chart.module.js.map +1 -0
  132. package/dist/components/ui/chart_module.css +159 -0
  133. package/dist/components/ui/chart_module.css.map +1 -0
  134. package/dist/components/ui/checkbox-group.d.ts +27 -0
  135. package/dist/components/ui/checkbox-group.d.ts.map +1 -0
  136. package/dist/components/ui/checkbox-group.js +26 -0
  137. package/dist/components/ui/checkbox-group.js.map +1 -0
  138. package/dist/components/ui/checkbox-group.module.js +7 -0
  139. package/dist/components/ui/checkbox-group.module.js.map +1 -0
  140. package/dist/components/ui/checkbox-group_module.css +11 -0
  141. package/dist/components/ui/checkbox-group_module.css.map +1 -0
  142. package/dist/components/ui/checkbox.d.ts +35 -2
  143. package/dist/components/ui/checkbox.d.ts.map +1 -1
  144. package/dist/components/ui/checkbox.js +40 -12
  145. package/dist/components/ui/checkbox.js.map +1 -1
  146. package/dist/components/ui/checkbox.module.js +8 -0
  147. package/dist/components/ui/checkbox.module.js.map +1 -0
  148. package/dist/components/ui/checkbox_module.css +45 -0
  149. package/dist/components/ui/checkbox_module.css.map +1 -0
  150. package/dist/components/ui/collapsible.d.ts +87 -3
  151. package/dist/components/ui/collapsible.d.ts.map +1 -1
  152. package/dist/components/ui/collapsible.js +46 -32
  153. package/dist/components/ui/collapsible.js.map +1 -1
  154. package/dist/components/ui/collapsible.module.js +8 -0
  155. package/dist/components/ui/collapsible.module.js.map +1 -0
  156. package/dist/components/ui/collapsible_module.css +26 -0
  157. package/dist/components/ui/collapsible_module.css.map +1 -0
  158. package/dist/components/ui/combobox.d.ts +335 -0
  159. package/dist/components/ui/combobox.d.ts.map +1 -0
  160. package/dist/components/ui/combobox.js +206 -0
  161. package/dist/components/ui/combobox.js.map +1 -0
  162. package/dist/components/ui/combobox.module.js +23 -0
  163. package/dist/components/ui/combobox.module.js.map +1 -0
  164. package/dist/components/ui/combobox_module.css +142 -0
  165. package/dist/components/ui/combobox_module.css.map +1 -0
  166. package/dist/components/ui/command.d.ts +284 -51
  167. package/dist/components/ui/command.d.ts.map +1 -1
  168. package/dist/components/ui/command.js +396 -51
  169. package/dist/components/ui/command.js.map +1 -1
  170. package/dist/components/ui/command.module.js +20 -0
  171. package/dist/components/ui/command.module.js.map +1 -0
  172. package/dist/components/ui/command_module.css +194 -0
  173. package/dist/components/ui/command_module.css.map +1 -0
  174. package/dist/components/ui/context-menu.d.ts +414 -21
  175. package/dist/components/ui/context-menu.d.ts.map +1 -1
  176. package/dist/components/ui/context-menu.js +190 -68
  177. package/dist/components/ui/context-menu.js.map +1 -1
  178. package/dist/components/ui/context-menu.module.js +19 -0
  179. package/dist/components/ui/context-menu.module.js.map +1 -0
  180. package/dist/components/ui/context-menu_module.css +114 -0
  181. package/dist/components/ui/context-menu_module.css.map +1 -0
  182. package/dist/components/ui/copy-button.d.ts +41 -0
  183. package/dist/components/ui/copy-button.d.ts.map +1 -0
  184. package/dist/components/ui/copy-button.js +51 -0
  185. package/dist/components/ui/copy-button.js.map +1 -0
  186. package/dist/components/ui/copy-button.module.js +8 -0
  187. package/dist/components/ui/copy-button.module.js.map +1 -0
  188. package/dist/components/ui/copy-button_module.css +37 -0
  189. package/dist/components/ui/copy-button_module.css.map +1 -0
  190. package/dist/components/ui/counting-number.d.ts +28 -2
  191. package/dist/components/ui/counting-number.d.ts.map +1 -1
  192. package/dist/components/ui/counting-number.js +31 -27
  193. package/dist/components/ui/counting-number.js.map +1 -1
  194. package/dist/components/ui/counting-number.module.js +7 -0
  195. package/dist/components/ui/counting-number.module.js.map +1 -0
  196. package/dist/components/ui/counting-number_module.css +7 -0
  197. package/dist/components/ui/counting-number_module.css.map +1 -0
  198. package/dist/components/ui/dialog.d.ts +287 -17
  199. package/dist/components/ui/dialog.d.ts.map +1 -1
  200. package/dist/components/ui/dialog.js +129 -52
  201. package/dist/components/ui/dialog.js.map +1 -1
  202. package/dist/components/ui/dialog.module.js +13 -0
  203. package/dist/components/ui/dialog.module.js.map +1 -0
  204. package/dist/components/ui/dialog_module.css +114 -0
  205. package/dist/components/ui/dialog_module.css.map +1 -0
  206. package/dist/components/ui/dot-background.d.ts +25 -35
  207. package/dist/components/ui/dot-background.d.ts.map +1 -1
  208. package/dist/components/ui/dot-background.js +31 -22
  209. package/dist/components/ui/dot-background.js.map +1 -1
  210. package/dist/components/ui/dot-background.module.js +8 -0
  211. package/dist/components/ui/dot-background.module.js.map +1 -0
  212. package/dist/components/ui/dot-background_module.css +15 -0
  213. package/dist/components/ui/dot-background_module.css.map +1 -0
  214. package/dist/components/ui/drawer.d.ts +287 -18
  215. package/dist/components/ui/drawer.d.ts.map +1 -1
  216. package/dist/components/ui/drawer.js +117 -40
  217. package/dist/components/ui/drawer.js.map +1 -1
  218. package/dist/components/ui/drawer.module.js +14 -0
  219. package/dist/components/ui/drawer.module.js.map +1 -0
  220. package/dist/components/ui/drawer_module.css +86 -0
  221. package/dist/components/ui/drawer_module.css.map +1 -0
  222. package/dist/components/ui/dropdown-menu.d.ts +414 -21
  223. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  224. package/dist/components/ui/dropdown-menu.js +189 -68
  225. package/dist/components/ui/dropdown-menu.js.map +1 -1
  226. package/dist/components/ui/dropdown-menu.module.js +19 -0
  227. package/dist/components/ui/dropdown-menu.module.js.map +1 -0
  228. package/dist/components/ui/dropdown-menu_module.css +114 -0
  229. package/dist/components/ui/dropdown-menu_module.css.map +1 -0
  230. package/dist/components/ui/dropdrawer.d.ts +307 -17
  231. package/dist/components/ui/dropdrawer.d.ts.map +1 -1
  232. package/dist/components/ui/dropdrawer.js +438 -166
  233. package/dist/components/ui/dropdrawer.js.map +1 -1
  234. package/dist/components/ui/dropdrawer.module.js +43 -0
  235. package/dist/components/ui/dropdrawer.module.js.map +1 -0
  236. package/dist/components/ui/dropdrawer_module.css +307 -0
  237. package/dist/components/ui/dropdrawer_module.css.map +1 -0
  238. package/dist/components/ui/empty.d.ts +129 -10
  239. package/dist/components/ui/empty.d.ts.map +1 -1
  240. package/dist/components/ui/empty.js +32 -47
  241. package/dist/components/ui/empty.js.map +1 -1
  242. package/dist/components/ui/empty.module.js +13 -0
  243. package/dist/components/ui/empty.module.js.map +1 -0
  244. package/dist/components/ui/empty_module.css +85 -0
  245. package/dist/components/ui/empty_module.css.map +1 -0
  246. package/dist/components/ui/error-boundary.js +61 -0
  247. package/dist/components/ui/error-boundary.js.map +1 -0
  248. package/dist/components/ui/error-boundary.module.js +10 -0
  249. package/dist/components/ui/error-boundary.module.js.map +1 -0
  250. package/dist/components/ui/error-boundary_module.css +41 -0
  251. package/dist/components/ui/error-boundary_module.css.map +1 -0
  252. package/dist/components/ui/field.d.ts +222 -23
  253. package/dist/components/ui/field.d.ts.map +1 -1
  254. package/dist/components/ui/field.js +76 -86
  255. package/dist/components/ui/field.js.map +1 -1
  256. package/dist/components/ui/field.module.js +24 -0
  257. package/dist/components/ui/field.module.js.map +1 -0
  258. package/dist/components/ui/field_module.css +185 -0
  259. package/dist/components/ui/field_module.css.map +1 -0
  260. package/dist/components/ui/fireworks-background.d.ts +27 -3
  261. package/dist/components/ui/fireworks-background.d.ts.map +1 -1
  262. package/dist/components/ui/fireworks-background.js +36 -35
  263. package/dist/components/ui/fireworks-background.js.map +1 -1
  264. package/dist/components/ui/fireworks-background.module.js +8 -0
  265. package/dist/components/ui/fireworks-background.module.js.map +1 -0
  266. package/dist/components/ui/fireworks-background_module.css +17 -0
  267. package/dist/components/ui/fireworks-background_module.css.map +1 -0
  268. package/dist/components/ui/flip-button.d.ts +27 -3
  269. package/dist/components/ui/flip-button.d.ts.map +1 -1
  270. package/dist/components/ui/flip-button.js +27 -17
  271. package/dist/components/ui/flip-button.js.map +1 -1
  272. package/dist/components/ui/flip-button.module.js +11 -0
  273. package/dist/components/ui/flip-button.module.js.map +1 -0
  274. package/dist/components/ui/flip-button_module.css +47 -0
  275. package/dist/components/ui/flip-button_module.css.map +1 -0
  276. package/dist/components/ui/focus-scope.js +70 -0
  277. package/dist/components/ui/focus-scope.js.map +1 -0
  278. package/dist/components/ui/focus-scope.module.js +7 -0
  279. package/dist/components/ui/focus-scope.module.js.map +1 -0
  280. package/dist/components/ui/focus-scope_module.css +6 -0
  281. package/dist/components/ui/focus-scope_module.css.map +1 -0
  282. package/dist/components/ui/form-skeleton.js +32 -0
  283. package/dist/components/ui/form-skeleton.js.map +1 -0
  284. package/dist/components/ui/form-skeleton.module.js +11 -0
  285. package/dist/components/ui/form-skeleton.module.js.map +1 -0
  286. package/dist/components/ui/form-skeleton_module.css +30 -0
  287. package/dist/components/ui/form-skeleton_module.css.map +1 -0
  288. package/dist/components/ui/form.d.ts +143 -13
  289. package/dist/components/ui/form.d.ts.map +1 -1
  290. package/dist/components/ui/form.js +55 -21
  291. package/dist/components/ui/form.js.map +1 -1
  292. package/dist/components/ui/form.module.js +10 -0
  293. package/dist/components/ui/form.module.js.map +1 -0
  294. package/dist/components/ui/form_module.css +22 -0
  295. package/dist/components/ui/form_module.css.map +1 -0
  296. package/dist/components/ui/gradient-background.d.ts +21 -3
  297. package/dist/components/ui/gradient-background.d.ts.map +1 -1
  298. package/dist/components/ui/gradient-background.js +8 -4
  299. package/dist/components/ui/gradient-background.js.map +1 -1
  300. package/dist/components/ui/gradient-background.module.js +7 -0
  301. package/dist/components/ui/gradient-background.module.js.map +1 -0
  302. package/dist/components/ui/gradient-background_module.css +9 -0
  303. package/dist/components/ui/gradient-background_module.css.map +1 -0
  304. package/dist/components/ui/gradient-text.d.ts +23 -2
  305. package/dist/components/ui/gradient-text.d.ts.map +1 -1
  306. package/dist/components/ui/gradient-text.js +8 -6
  307. package/dist/components/ui/gradient-text.js.map +1 -1
  308. package/dist/components/ui/gradient-text.module.js +9 -0
  309. package/dist/components/ui/gradient-text.module.js.map +1 -0
  310. package/dist/components/ui/gradient-text_module.css +24 -0
  311. package/dist/components/ui/gradient-text_module.css.map +1 -0
  312. package/dist/components/ui/highlight-text.d.ts +24 -2
  313. package/dist/components/ui/highlight-text.d.ts.map +1 -1
  314. package/dist/components/ui/highlight-text.js +7 -10
  315. package/dist/components/ui/highlight-text.js.map +1 -1
  316. package/dist/components/ui/highlight-text.module.js +7 -0
  317. package/dist/components/ui/highlight-text.module.js.map +1 -0
  318. package/dist/components/ui/highlight-text_module.css +16 -0
  319. package/dist/components/ui/highlight-text_module.css.map +1 -0
  320. package/dist/components/ui/hole-background.d.ts +23 -2
  321. package/dist/components/ui/hole-background.d.ts.map +1 -1
  322. package/dist/components/ui/hole-background.js +155 -118
  323. package/dist/components/ui/hole-background.js.map +1 -1
  324. package/dist/components/ui/hole-background.module.js +10 -0
  325. package/dist/components/ui/hole-background.module.js.map +1 -0
  326. package/dist/components/ui/hole-background_module.css +85 -0
  327. package/dist/components/ui/hole-background_module.css.map +1 -0
  328. package/dist/components/ui/hover-card.d.ts +85 -4
  329. package/dist/components/ui/hover-card.d.ts.map +1 -1
  330. package/dist/components/ui/hover-card.js +52 -10
  331. package/dist/components/ui/hover-card.js.map +1 -1
  332. package/dist/components/ui/hover-card.module.js +8 -0
  333. package/dist/components/ui/hover-card.module.js.map +1 -0
  334. package/dist/components/ui/hover-card_module.css +23 -0
  335. package/dist/components/ui/hover-card_module.css.map +1 -0
  336. package/dist/components/ui/input-group.d.ts +132 -13
  337. package/dist/components/ui/input-group.d.ts.map +1 -1
  338. package/dist/components/ui/input-group.js +62 -66
  339. package/dist/components/ui/input-group.js.map +1 -1
  340. package/dist/components/ui/input-group.module.js +20 -0
  341. package/dist/components/ui/input-group.module.js.map +1 -0
  342. package/dist/components/ui/input-group_module.css +150 -0
  343. package/dist/components/ui/input-group_module.css.map +1 -0
  344. package/dist/components/ui/input-otp.d.ts +110 -30
  345. package/dist/components/ui/input-otp.d.ts.map +1 -1
  346. package/dist/components/ui/input-otp.js +24 -15
  347. package/dist/components/ui/input-otp.js.map +1 -1
  348. package/dist/components/ui/input-otp.module.js +17 -0
  349. package/dist/components/ui/input-otp.module.js.map +1 -0
  350. package/dist/components/ui/input-otp_module.css +89 -0
  351. package/dist/components/ui/input-otp_module.css.map +1 -0
  352. package/dist/components/ui/input.d.ts +31 -1
  353. package/dist/components/ui/input.d.ts.map +1 -1
  354. package/dist/components/ui/input.js +21 -8
  355. package/dist/components/ui/input.js.map +1 -1
  356. package/dist/components/ui/input.module.js +7 -0
  357. package/dist/components/ui/input.module.js.map +1 -0
  358. package/dist/components/ui/input_module.css +40 -0
  359. package/dist/components/ui/input_module.css.map +1 -0
  360. package/dist/components/ui/item.d.ts +221 -19
  361. package/dist/components/ui/item.d.ts.map +1 -1
  362. package/dist/components/ui/item.js +66 -90
  363. package/dist/components/ui/item.js.map +1 -1
  364. package/dist/components/ui/item.module.js +22 -0
  365. package/dist/components/ui/item.module.js.map +1 -0
  366. package/dist/components/ui/item_module.css +143 -0
  367. package/dist/components/ui/item_module.css.map +1 -0
  368. package/dist/components/ui/kbd.d.ts +43 -2
  369. package/dist/components/ui/kbd.d.ts.map +1 -1
  370. package/dist/components/ui/kbd.js +12 -12
  371. package/dist/components/ui/kbd.js.map +1 -1
  372. package/dist/components/ui/kbd.module.js +8 -0
  373. package/dist/components/ui/kbd.module.js.map +1 -0
  374. package/dist/components/ui/kbd_module.css +35 -0
  375. package/dist/components/ui/kbd_module.css.map +1 -0
  376. package/dist/components/ui/label.d.ts +30 -3
  377. package/dist/components/ui/label.d.ts.map +1 -1
  378. package/dist/components/ui/label.js +7 -8
  379. package/dist/components/ui/label.js.map +1 -1
  380. package/dist/components/ui/label.module.js +7 -0
  381. package/dist/components/ui/label.module.js.map +1 -0
  382. package/dist/components/ui/label_module.css +17 -0
  383. package/dist/components/ui/label_module.css.map +1 -0
  384. package/dist/components/ui/list-skeleton.js +35 -0
  385. package/dist/components/ui/list-skeleton.js.map +1 -0
  386. package/dist/components/ui/list-skeleton.module.js +12 -0
  387. package/dist/components/ui/list-skeleton.module.js.map +1 -0
  388. package/dist/components/ui/list-skeleton_module.css +39 -0
  389. package/dist/components/ui/list-skeleton_module.css.map +1 -0
  390. package/dist/components/ui/loading-overlay.js +21 -0
  391. package/dist/components/ui/loading-overlay.js.map +1 -0
  392. package/dist/components/ui/loading-overlay.module.js +9 -0
  393. package/dist/components/ui/loading-overlay.module.js.map +1 -0
  394. package/dist/components/ui/loading-overlay_module.css +22 -0
  395. package/dist/components/ui/loading-overlay_module.css.map +1 -0
  396. package/dist/components/ui/menubar.d.ts +420 -22
  397. package/dist/components/ui/menubar.d.ts.map +1 -1
  398. package/dist/components/ui/menubar.js +199 -100
  399. package/dist/components/ui/menubar.js.map +1 -1
  400. package/dist/components/ui/menubar.module.js +21 -0
  401. package/dist/components/ui/menubar.module.js.map +1 -0
  402. package/dist/components/ui/menubar_module.css +145 -0
  403. package/dist/components/ui/menubar_module.css.map +1 -0
  404. package/dist/components/ui/meter.d.ts +85 -0
  405. package/dist/components/ui/meter.d.ts.map +1 -0
  406. package/dist/components/ui/meter.js +75 -0
  407. package/dist/components/ui/meter.js.map +1 -0
  408. package/dist/components/ui/meter.module.js +10 -0
  409. package/dist/components/ui/meter.module.js.map +1 -0
  410. package/dist/components/ui/meter_module.css +31 -0
  411. package/dist/components/ui/meter_module.css.map +1 -0
  412. package/dist/components/ui/navigation-menu.d.ts +233 -11
  413. package/dist/components/ui/navigation-menu.d.ts.map +1 -1
  414. package/dist/components/ui/navigation-menu.js +138 -49
  415. package/dist/components/ui/navigation-menu.js.map +1 -1
  416. package/dist/components/ui/navigation-menu.module.js +18 -0
  417. package/dist/components/ui/navigation-menu.module.js.map +1 -0
  418. package/dist/components/ui/navigation-menu_module.css +112 -0
  419. package/dist/components/ui/navigation-menu_module.css.map +1 -0
  420. package/dist/components/ui/number-field.d.ts +138 -0
  421. package/dist/components/ui/number-field.d.ts.map +1 -0
  422. package/dist/components/ui/number-field.js +111 -0
  423. package/dist/components/ui/number-field.js.map +1 -0
  424. package/dist/components/ui/number-field.module.js +15 -0
  425. package/dist/components/ui/number-field.module.js.map +1 -0
  426. package/dist/components/ui/number-field_module.css +125 -0
  427. package/dist/components/ui/number-field_module.css.map +1 -0
  428. package/dist/components/ui/pagination.d.ts +150 -24
  429. package/dist/components/ui/pagination.d.ts.map +1 -1
  430. package/dist/components/ui/pagination.js +41 -38
  431. package/dist/components/ui/pagination.js.map +1 -1
  432. package/dist/components/ui/pagination.module.js +14 -0
  433. package/dist/components/ui/pagination.module.js.map +1 -0
  434. package/dist/components/ui/pagination_module.css +66 -0
  435. package/dist/components/ui/pagination_module.css.map +1 -0
  436. package/dist/components/ui/popover.d.ts +133 -5
  437. package/dist/components/ui/popover.d.ts.map +1 -1
  438. package/dist/components/ui/popover.js +68 -14
  439. package/dist/components/ui/popover.js.map +1 -1
  440. package/dist/components/ui/popover.module.js +9 -0
  441. package/dist/components/ui/popover.module.js.map +1 -0
  442. package/dist/components/ui/popover_module.css +28 -0
  443. package/dist/components/ui/popover_module.css.map +1 -0
  444. package/dist/components/ui/progress.d.ts +31 -2
  445. package/dist/components/ui/progress.d.ts.map +1 -1
  446. package/dist/components/ui/progress.js +22 -13
  447. package/dist/components/ui/progress.js.map +1 -1
  448. package/dist/components/ui/progress.module.js +8 -0
  449. package/dist/components/ui/progress.module.js.map +1 -0
  450. package/dist/components/ui/progress_module.css +20 -0
  451. package/dist/components/ui/progress_module.css.map +1 -0
  452. package/dist/components/ui/radio-group.d.ts +42 -3
  453. package/dist/components/ui/radio-group.d.ts.map +1 -1
  454. package/dist/components/ui/radio-group.js +38 -16
  455. package/dist/components/ui/radio-group.js.map +1 -1
  456. package/dist/components/ui/radio-group.module.js +10 -0
  457. package/dist/components/ui/radio-group.module.js.map +1 -0
  458. package/dist/components/ui/radio-group_module.css +44 -0
  459. package/dist/components/ui/radio-group_module.css.map +1 -0
  460. package/dist/components/ui/resizable.d.ts +78 -5
  461. package/dist/components/ui/resizable.d.ts.map +1 -1
  462. package/dist/components/ui/resizable.js +23 -13
  463. package/dist/components/ui/resizable.js.map +1 -1
  464. package/dist/components/ui/resizable.module.js +10 -0
  465. package/dist/components/ui/resizable.module.js.map +1 -0
  466. package/dist/components/ui/resizable_module.css +70 -0
  467. package/dist/components/ui/resizable_module.css.map +1 -0
  468. package/dist/components/ui/ripple-button.d.ts +23 -2
  469. package/dist/components/ui/ripple-button.d.ts.map +1 -1
  470. package/dist/components/ui/ripple-button.js +26 -11
  471. package/dist/components/ui/ripple-button.js.map +1 -1
  472. package/dist/components/ui/ripple-button.module.js +9 -0
  473. package/dist/components/ui/ripple-button.module.js.map +1 -0
  474. package/dist/components/ui/ripple-button_module.css +38 -0
  475. package/dist/components/ui/ripple-button_module.css.map +1 -0
  476. package/dist/components/ui/scratcher.d.ts +26 -3
  477. package/dist/components/ui/scratcher.d.ts.map +1 -1
  478. package/dist/components/ui/scratcher.js +89 -90
  479. package/dist/components/ui/scratcher.js.map +1 -1
  480. package/dist/components/ui/scratcher.module.js +8 -0
  481. package/dist/components/ui/scratcher.module.js.map +1 -0
  482. package/dist/components/ui/scratcher_module.css +13 -0
  483. package/dist/components/ui/scratcher_module.css.map +1 -0
  484. package/dist/components/ui/scroll-area.d.ts +44 -3
  485. package/dist/components/ui/scroll-area.d.ts.map +1 -1
  486. package/dist/components/ui/scroll-area.js +44 -19
  487. package/dist/components/ui/scroll-area.js.map +1 -1
  488. package/dist/components/ui/scroll-area.module.js +14 -0
  489. package/dist/components/ui/scroll-area.module.js.map +1 -0
  490. package/dist/components/ui/scroll-area_module.css +51 -0
  491. package/dist/components/ui/scroll-area_module.css.map +1 -0
  492. package/dist/components/ui/select.d.ts +269 -11
  493. package/dist/components/ui/select.d.ts.map +1 -1
  494. package/dist/components/ui/select.js +152 -67
  495. package/dist/components/ui/select.js.map +1 -1
  496. package/dist/components/ui/select.module.js +20 -0
  497. package/dist/components/ui/select.module.js.map +1 -0
  498. package/dist/components/ui/select_module.css +134 -0
  499. package/dist/components/ui/select_module.css.map +1 -0
  500. package/dist/components/ui/separator.d.ts +33 -2
  501. package/dist/components/ui/separator.d.ts.map +1 -1
  502. package/dist/components/ui/separator.js +20 -9
  503. package/dist/components/ui/separator.js.map +1 -1
  504. package/dist/components/ui/separator.module.js +9 -0
  505. package/dist/components/ui/separator.module.js.map +1 -0
  506. package/dist/components/ui/separator_module.css +17 -0
  507. package/dist/components/ui/separator_module.css.map +1 -0
  508. package/dist/components/ui/sheet.d.ts +297 -23
  509. package/dist/components/ui/sheet.d.ts.map +1 -1
  510. package/dist/components/ui/sheet.js +121 -63
  511. package/dist/components/ui/sheet.js.map +1 -1
  512. package/dist/components/ui/sheet.module.js +18 -0
  513. package/dist/components/ui/sheet.module.js.map +1 -0
  514. package/dist/components/ui/sheet_module.css +136 -0
  515. package/dist/components/ui/sheet_module.css.map +1 -0
  516. package/dist/components/ui/sidebar.d.ts +491 -23
  517. package/dist/components/ui/sidebar.d.ts.map +1 -1
  518. package/dist/components/ui/sidebar.js +214 -143
  519. package/dist/components/ui/sidebar.js.map +1 -1
  520. package/dist/components/ui/sidebar.module.js +50 -0
  521. package/dist/components/ui/sidebar.module.js.map +1 -0
  522. package/dist/components/ui/sidebar_module.css +569 -0
  523. package/dist/components/ui/sidebar_module.css.map +1 -0
  524. package/dist/components/ui/skeleton.d.ts +30 -1
  525. package/dist/components/ui/skeleton.d.ts.map +1 -1
  526. package/dist/components/ui/skeleton.js +7 -7
  527. package/dist/components/ui/skeleton.js.map +1 -1
  528. package/dist/components/ui/skeleton.module.js +8 -0
  529. package/dist/components/ui/skeleton.module.js.map +1 -0
  530. package/dist/components/ui/skeleton_module.css +18 -0
  531. package/dist/components/ui/skeleton_module.css.map +1 -0
  532. package/dist/components/ui/slider.d.ts +48 -2
  533. package/dist/components/ui/slider.d.ts.map +1 -1
  534. package/dist/components/ui/slider.js +44 -17
  535. package/dist/components/ui/slider.js.map +1 -1
  536. package/dist/components/ui/slider.module.js +11 -0
  537. package/dist/components/ui/slider.module.js.map +1 -0
  538. package/dist/components/ui/slider_module.css +55 -0
  539. package/dist/components/ui/slider_module.css.map +1 -0
  540. package/dist/components/ui/sonner.d.ts +138 -4
  541. package/dist/components/ui/sonner.d.ts.map +1 -1
  542. package/dist/components/ui/sonner.js +450 -17
  543. package/dist/components/ui/sonner.js.map +1 -1
  544. package/dist/components/ui/sonner.module.js +34 -0
  545. package/dist/components/ui/sonner.module.js.map +1 -0
  546. package/dist/components/ui/sonner_module.css +233 -0
  547. package/dist/components/ui/sonner_module.css.map +1 -0
  548. package/dist/components/ui/spinner.d.ts +20 -1
  549. package/dist/components/ui/spinner.d.ts.map +1 -1
  550. package/dist/components/ui/spinner.js +29 -11
  551. package/dist/components/ui/spinner.js.map +1 -1
  552. package/dist/components/ui/spinner.module.js +10 -0
  553. package/dist/components/ui/spinner.module.js.map +1 -0
  554. package/dist/components/ui/spinner_module.css +28 -0
  555. package/dist/components/ui/spinner_module.css.map +1 -0
  556. package/dist/components/ui/stepper.d.ts +48 -0
  557. package/dist/components/ui/stepper.d.ts.map +1 -0
  558. package/dist/components/ui/stepper.js +41 -0
  559. package/dist/components/ui/stepper.js.map +1 -0
  560. package/dist/components/ui/stepper.module.js +12 -0
  561. package/dist/components/ui/stepper.module.js.map +1 -0
  562. package/dist/components/ui/stepper_module.css +75 -0
  563. package/dist/components/ui/stepper_module.css.map +1 -0
  564. package/dist/components/ui/switch.d.ts +29 -2
  565. package/dist/components/ui/switch.d.ts.map +1 -1
  566. package/dist/components/ui/switch.js +21 -9
  567. package/dist/components/ui/switch.js.map +1 -1
  568. package/dist/components/ui/switch.module.js +8 -0
  569. package/dist/components/ui/switch.module.js.map +1 -0
  570. package/dist/components/ui/switch_module.css +45 -0
  571. package/dist/components/ui/switch_module.css.map +1 -0
  572. package/dist/components/ui/table-skeleton.js +34 -0
  573. package/dist/components/ui/table-skeleton.js.map +1 -0
  574. package/dist/components/ui/table-skeleton.module.js +11 -0
  575. package/dist/components/ui/table-skeleton.module.js.map +1 -0
  576. package/dist/components/ui/table-skeleton_module.css +32 -0
  577. package/dist/components/ui/table-skeleton_module.css.map +1 -0
  578. package/dist/components/ui/table.d.ts +170 -8
  579. package/dist/components/ui/table.d.ts.map +1 -1
  580. package/dist/components/ui/table.js +17 -17
  581. package/dist/components/ui/table.js.map +1 -1
  582. package/dist/components/ui/table.module.js +15 -0
  583. package/dist/components/ui/table.module.js.map +1 -0
  584. package/dist/components/ui/table_module.css +71 -0
  585. package/dist/components/ui/table_module.css.map +1 -0
  586. package/dist/components/ui/tabs.d.ts +114 -5
  587. package/dist/components/ui/tabs.d.ts.map +1 -1
  588. package/dist/components/ui/tabs.js +71 -20
  589. package/dist/components/ui/tabs.js.map +1 -1
  590. package/dist/components/ui/tabs.module.js +10 -0
  591. package/dist/components/ui/tabs.module.js.map +1 -0
  592. package/dist/components/ui/tabs_module.css +89 -0
  593. package/dist/components/ui/tabs_module.css.map +1 -0
  594. package/dist/components/ui/textarea.d.ts +24 -1
  595. package/dist/components/ui/textarea.d.ts.map +1 -1
  596. package/dist/components/ui/textarea.js +2 -2
  597. package/dist/components/ui/textarea.js.map +1 -1
  598. package/dist/components/ui/textarea.module.js +7 -0
  599. package/dist/components/ui/textarea.module.js.map +1 -0
  600. package/dist/components/ui/textarea_module.css +33 -0
  601. package/dist/components/ui/textarea_module.css.map +1 -0
  602. package/dist/components/ui/timeline.d.ts +111 -0
  603. package/dist/components/ui/timeline.d.ts.map +1 -0
  604. package/dist/components/ui/timeline.js +34 -0
  605. package/dist/components/ui/timeline.js.map +1 -0
  606. package/dist/components/ui/timeline.module.js +10 -0
  607. package/dist/components/ui/timeline.module.js.map +1 -0
  608. package/dist/components/ui/timeline_module.css +47 -0
  609. package/dist/components/ui/timeline_module.css.map +1 -0
  610. package/dist/components/ui/toggle-group.d.ts +75 -10
  611. package/dist/components/ui/toggle-group.d.ts.map +1 -1
  612. package/dist/components/ui/toggle-group.js +32 -21
  613. package/dist/components/ui/toggle-group.js.map +1 -1
  614. package/dist/components/ui/toggle-group.module.js +7 -0
  615. package/dist/components/ui/toggle-group.module.js.map +1 -0
  616. package/dist/components/ui/toggle-group_module.css +8 -0
  617. package/dist/components/ui/toggle-group_module.css.map +1 -0
  618. package/dist/components/ui/toggle.d.ts +60 -11
  619. package/dist/components/ui/toggle.d.ts.map +1 -1
  620. package/dist/components/ui/toggle.js +29 -29
  621. package/dist/components/ui/toggle.js.map +1 -1
  622. package/dist/components/ui/toggle.module.js +12 -0
  623. package/dist/components/ui/toggle.module.js.map +1 -0
  624. package/dist/components/ui/toggle_module.css +62 -0
  625. package/dist/components/ui/toggle_module.css.map +1 -0
  626. package/dist/components/ui/toolbar.d.ts +107 -0
  627. package/dist/components/ui/toolbar.d.ts.map +1 -0
  628. package/dist/components/ui/toolbar.js +90 -0
  629. package/dist/components/ui/toolbar.js.map +1 -0
  630. package/dist/components/ui/toolbar.module.js +12 -0
  631. package/dist/components/ui/toolbar.module.js.map +1 -0
  632. package/dist/components/ui/toolbar_module.css +115 -0
  633. package/dist/components/ui/toolbar_module.css.map +1 -0
  634. package/dist/components/ui/tooltip.d.ts +119 -5
  635. package/dist/components/ui/tooltip.d.ts.map +1 -1
  636. package/dist/components/ui/tooltip.js +48 -13
  637. package/dist/components/ui/tooltip.js.map +1 -1
  638. package/dist/components/ui/tooltip.module.js +9 -0
  639. package/dist/components/ui/tooltip.module.js.map +1 -0
  640. package/dist/components/ui/tooltip_module.css +35 -0
  641. package/dist/components/ui/tooltip_module.css.map +1 -0
  642. package/dist/components/ui/typewriter.d.ts +48 -13
  643. package/dist/components/ui/typewriter.d.ts.map +1 -1
  644. package/dist/components/ui/typewriter.js +46 -49
  645. package/dist/components/ui/typewriter.js.map +1 -1
  646. package/dist/components/ui/typewriter.module.js +16 -0
  647. package/dist/components/ui/typewriter.module.js.map +1 -0
  648. package/dist/components/ui/typewriter_module.css +102 -0
  649. package/dist/components/ui/typewriter_module.css.map +1 -0
  650. package/dist/components/ui/visually-hidden.d.ts +38 -0
  651. package/dist/components/ui/visually-hidden.d.ts.map +1 -0
  652. package/dist/components/ui/visually-hidden.js +13 -0
  653. package/dist/components/ui/visually-hidden.js.map +1 -0
  654. package/dist/components/ui/visually-hidden.module.js +7 -0
  655. package/dist/components/ui/visually-hidden.module.js.map +1 -0
  656. package/dist/components/ui/visually-hidden_module.css +14 -0
  657. package/dist/components/ui/visually-hidden_module.css.map +1 -0
  658. package/dist/hooks/useAnnounce.js +46 -0
  659. package/dist/hooks/useAnnounce.js.map +1 -0
  660. package/dist/hooks/useBreakpoint.d.ts +17 -0
  661. package/dist/hooks/useBreakpoint.d.ts.map +1 -0
  662. package/dist/hooks/useBreakpoint.js +16 -0
  663. package/dist/hooks/useBreakpoint.js.map +1 -0
  664. package/dist/hooks/useClipboard.d.ts +77 -0
  665. package/dist/hooks/useClipboard.d.ts.map +1 -0
  666. package/dist/hooks/useClipboard.js +42 -0
  667. package/dist/hooks/useClipboard.js.map +1 -0
  668. package/dist/hooks/useColorScheme.d.ts +14 -0
  669. package/dist/hooks/useColorScheme.d.ts.map +1 -0
  670. package/dist/hooks/useColorScheme.js +9 -0
  671. package/dist/hooks/useColorScheme.js.map +1 -0
  672. package/dist/hooks/useControllableState.d.ts +54 -0
  673. package/dist/hooks/useControllableState.d.ts.map +1 -0
  674. package/dist/hooks/useControllableState.js +29 -0
  675. package/dist/hooks/useControllableState.js.map +1 -0
  676. package/dist/hooks/useDebounce.d.ts +33 -0
  677. package/dist/hooks/useDebounce.d.ts.map +1 -0
  678. package/dist/hooks/useDebounce.js +20 -0
  679. package/dist/hooks/useDebounce.js.map +1 -0
  680. package/dist/hooks/useEventCallback.d.ts +34 -0
  681. package/dist/hooks/useEventCallback.d.ts.map +1 -0
  682. package/dist/hooks/useEventCallback.js +12 -0
  683. package/dist/hooks/useEventCallback.js.map +1 -0
  684. package/dist/hooks/useFocusManager.js +51 -0
  685. package/dist/hooks/useFocusManager.js.map +1 -0
  686. package/dist/hooks/useFocusVisible.d.ts +50 -0
  687. package/dist/hooks/useFocusVisible.d.ts.map +1 -0
  688. package/dist/hooks/useFocusVisible.js +35 -0
  689. package/dist/hooks/useFocusVisible.js.map +1 -0
  690. package/dist/hooks/useId.d.ts +30 -0
  691. package/dist/hooks/useId.d.ts.map +1 -0
  692. package/dist/hooks/useId.js +9 -0
  693. package/dist/hooks/useId.js.map +1 -0
  694. package/dist/hooks/useIntersectionObserver.d.ts +51 -0
  695. package/dist/hooks/useIntersectionObserver.d.ts.map +1 -0
  696. package/dist/hooks/useIntersectionObserver.js +25 -0
  697. package/dist/hooks/useIntersectionObserver.js.map +1 -0
  698. package/dist/hooks/useInterval.d.ts +55 -0
  699. package/dist/hooks/useInterval.d.ts.map +1 -0
  700. package/dist/hooks/useInterval.js +24 -0
  701. package/dist/hooks/useInterval.js.map +1 -0
  702. package/dist/hooks/useIsMobile.d.ts +5 -11
  703. package/dist/hooks/useIsMobile.d.ts.map +1 -1
  704. package/dist/hooks/useIsMobile.js +2 -13
  705. package/dist/hooks/useIsMobile.js.map +1 -1
  706. package/dist/hooks/useLocalStorage.d.ts +43 -0
  707. package/dist/hooks/useLocalStorage.d.ts.map +1 -0
  708. package/dist/hooks/useLocalStorage.js +53 -0
  709. package/dist/hooks/useLocalStorage.js.map +1 -0
  710. package/dist/hooks/useMediaQuery.d.ts +14 -0
  711. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  712. package/dist/hooks/useMediaQuery.js +20 -0
  713. package/dist/hooks/useMediaQuery.js.map +1 -0
  714. package/dist/hooks/useMergedRefs.d.ts +27 -0
  715. package/dist/hooks/useMergedRefs.d.ts.map +1 -0
  716. package/dist/hooks/useMergedRefs.js +11 -0
  717. package/dist/hooks/useMergedRefs.js.map +1 -0
  718. package/dist/hooks/useOnClickOutside.d.ts +32 -0
  719. package/dist/hooks/useOnClickOutside.d.ts.map +1 -0
  720. package/dist/hooks/useOnClickOutside.js +23 -0
  721. package/dist/hooks/useOnClickOutside.js.map +1 -0
  722. package/dist/hooks/usePrefersContrast.d.ts +19 -0
  723. package/dist/hooks/usePrefersContrast.d.ts.map +1 -0
  724. package/dist/hooks/usePrefersContrast.js +8 -0
  725. package/dist/hooks/usePrefersContrast.js.map +1 -0
  726. package/dist/hooks/usePrevious.d.ts +33 -0
  727. package/dist/hooks/usePrevious.d.ts.map +1 -0
  728. package/dist/hooks/usePrevious.js +14 -0
  729. package/dist/hooks/usePrevious.js.map +1 -0
  730. package/dist/hooks/useReducedMotion.d.ts +19 -0
  731. package/dist/hooks/useReducedMotion.d.ts.map +1 -0
  732. package/dist/hooks/useReducedMotion.js +2 -0
  733. package/dist/hooks/useThrottle.d.ts +37 -0
  734. package/dist/hooks/useThrottle.d.ts.map +1 -0
  735. package/dist/hooks/useThrottle.js +34 -0
  736. package/dist/hooks/useThrottle.js.map +1 -0
  737. package/dist/hooks/useTimeout.d.ts +28 -0
  738. package/dist/hooks/useTimeout.d.ts.map +1 -0
  739. package/dist/hooks/useTimeout.js +24 -0
  740. package/dist/hooks/useTimeout.js.map +1 -0
  741. package/dist/index.css +104 -5363
  742. package/dist/index.css.map +1 -1
  743. package/dist/index.d.ts +52 -8
  744. package/dist/index.d.ts.map +1 -1
  745. package/dist/index.js +103 -72
  746. package/dist/lib/utilities.d.ts +5 -5
  747. package/dist/lib/utilities.d.ts.map +1 -1
  748. package/dist/lib/utilities.js +1 -2
  749. package/dist/lib/utilities.js.map +1 -1
  750. package/dist/motion/Collapse.js +19 -0
  751. package/dist/motion/Collapse.js.map +1 -0
  752. package/dist/motion/Collapse.module.js +8 -0
  753. package/dist/motion/Collapse.module.js.map +1 -0
  754. package/dist/motion/Collapse_module.css +25 -0
  755. package/dist/motion/Collapse_module.css.map +1 -0
  756. package/dist/motion/Presence.js +14 -0
  757. package/dist/motion/Presence.js.map +1 -0
  758. package/dist/motion/index.js +5 -0
  759. package/dist/motion/presets.js +117 -0
  760. package/dist/motion/presets.js.map +1 -0
  761. package/dist/motion/tokens.js +41 -0
  762. package/dist/motion/tokens.js.map +1 -0
  763. package/dist/rslib-runtime.js +39 -0
  764. package/dist/rslib-runtime.js.map +1 -0
  765. package/package.json +233 -67
  766. package/src/components/ui/accordion.module.css +70 -0
  767. package/src/components/ui/accordion.tsx +278 -44
  768. package/src/components/ui/alert-dialog.module.css +87 -0
  769. package/src/components/ui/alert-dialog.tsx +481 -99
  770. package/src/components/ui/alert.module.css +57 -0
  771. package/src/components/ui/alert.tsx +136 -43
  772. package/src/components/ui/aspect-ratio.module.css +7 -0
  773. package/src/components/ui/aspect-ratio.tsx +38 -3
  774. package/src/components/ui/async-boundary.tsx +56 -0
  775. package/src/components/ui/avatar.module.css +31 -0
  776. package/src/components/ui/avatar.tsx +149 -36
  777. package/src/components/ui/background-beams.module.css +20 -0
  778. package/src/components/ui/background-beams.tsx +173 -134
  779. package/src/components/ui/badge.module.css +60 -0
  780. package/src/components/ui/badge.tsx +100 -32
  781. package/src/components/ui/breadcrumb.module.css +87 -0
  782. package/src/components/ui/breadcrumb.tsx +256 -74
  783. package/src/components/ui/bubble-background.module.css +97 -0
  784. package/src/components/ui/bubble-background.tsx +92 -52
  785. package/src/components/ui/button-group.module.css +76 -0
  786. package/src/components/ui/button-group.tsx +135 -46
  787. package/src/components/ui/button.module.css +138 -0
  788. package/src/components/ui/button.tsx +159 -41
  789. package/src/components/ui/calendar.module.css +250 -0
  790. package/src/components/ui/calendar.tsx +135 -111
  791. package/src/components/ui/card-skeleton.module.css +50 -0
  792. package/src/components/ui/card-skeleton.tsx +69 -0
  793. package/src/components/ui/card.module.css +41 -0
  794. package/src/components/ui/card.tsx +175 -22
  795. package/src/components/ui/carousel.module.css +80 -0
  796. package/src/components/ui/carousel.tsx +186 -43
  797. package/src/components/ui/chart.module.css +164 -0
  798. package/src/components/ui/chart.tsx +447 -102
  799. package/src/components/ui/checkbox-group.module.css +8 -0
  800. package/src/components/ui/checkbox-group.tsx +53 -0
  801. package/src/components/ui/checkbox.module.css +43 -0
  802. package/src/components/ui/checkbox.tsx +81 -19
  803. package/src/components/ui/collapsible.module.css +24 -0
  804. package/src/components/ui/collapsible.tsx +140 -3
  805. package/src/components/ui/combobox.module.css +158 -0
  806. package/src/components/ui/combobox.tsx +569 -0
  807. package/src/components/ui/command.module.css +193 -0
  808. package/src/components/ui/command.tsx +893 -114
  809. package/src/components/ui/context-menu.module.css +113 -0
  810. package/src/components/ui/context-menu.tsx +619 -157
  811. package/src/components/ui/copy-button.module.css +34 -0
  812. package/src/components/ui/copy-button.tsx +116 -0
  813. package/src/components/ui/counting-number.module.css +4 -0
  814. package/src/components/ui/counting-number.tsx +69 -31
  815. package/src/components/ui/dialog.module.css +113 -0
  816. package/src/components/ui/dialog.tsx +427 -81
  817. package/src/components/ui/dot-background.module.css +12 -0
  818. package/src/components/ui/dot-background.tsx +134 -126
  819. package/src/components/ui/drawer.module.css +85 -0
  820. package/src/components/ui/drawer.tsx +410 -80
  821. package/src/components/ui/dropdown-menu.module.css +113 -0
  822. package/src/components/ui/dropdown-menu.tsx +619 -159
  823. package/src/components/ui/dropdrawer.module.css +322 -0
  824. package/src/components/ui/dropdrawer.tsx +870 -400
  825. package/src/components/ui/empty.module.css +84 -0
  826. package/src/components/ui/empty.tsx +176 -52
  827. package/src/components/ui/error-boundary.module.css +36 -0
  828. package/src/components/ui/error-boundary.tsx +127 -0
  829. package/src/components/ui/field.module.css +179 -0
  830. package/src/components/ui/field.tsx +345 -139
  831. package/src/components/ui/fireworks-background.module.css +13 -0
  832. package/src/components/ui/fireworks-background.tsx +89 -51
  833. package/src/components/ui/flip-button.module.css +44 -0
  834. package/src/components/ui/flip-button.tsx +59 -28
  835. package/src/components/ui/focus-scope.module.css +3 -0
  836. package/src/components/ui/focus-scope.tsx +160 -0
  837. package/src/components/ui/form-skeleton.module.css +28 -0
  838. package/src/components/ui/form-skeleton.tsx +62 -0
  839. package/src/components/ui/form.module.css +20 -0
  840. package/src/components/ui/form.tsx +244 -33
  841. package/src/components/ui/gradient-background.module.css +6 -0
  842. package/src/components/ui/gradient-background.tsx +27 -5
  843. package/src/components/ui/gradient-text.module.css +23 -0
  844. package/src/components/ui/gradient-text.tsx +36 -9
  845. package/src/components/ui/highlight-text.module.css +14 -0
  846. package/src/components/ui/highlight-text.tsx +37 -15
  847. package/src/components/ui/hole-background.module.css +84 -0
  848. package/src/components/ui/hole-background.tsx +290 -162
  849. package/src/components/ui/hover-card.module.css +21 -0
  850. package/src/components/ui/hover-card.tsx +142 -21
  851. package/src/components/ui/input-group.module.css +148 -0
  852. package/src/components/ui/input-group.tsx +222 -98
  853. package/src/components/ui/input-otp.module.css +92 -0
  854. package/src/components/ui/input-otp.tsx +159 -33
  855. package/src/components/ui/input.module.css +37 -0
  856. package/src/components/ui/input.tsx +56 -14
  857. package/src/components/ui/item.module.css +143 -0
  858. package/src/components/ui/item.tsx +331 -104
  859. package/src/components/ui/kbd.module.css +31 -0
  860. package/src/components/ui/kbd.tsx +60 -17
  861. package/src/components/ui/label.module.css +13 -0
  862. package/src/components/ui/label.tsx +38 -14
  863. package/src/components/ui/list-skeleton.module.css +35 -0
  864. package/src/components/ui/list-skeleton.tsx +70 -0
  865. package/src/components/ui/loading-overlay.module.css +19 -0
  866. package/src/components/ui/loading-overlay.tsx +72 -0
  867. package/src/components/ui/menubar.module.css +144 -0
  868. package/src/components/ui/menubar.tsx +604 -192
  869. package/src/components/ui/meter.module.css +32 -0
  870. package/src/components/ui/meter.tsx +169 -0
  871. package/src/components/ui/navigation-menu.module.css +110 -0
  872. package/src/components/ui/navigation-menu.tsx +381 -99
  873. package/src/components/ui/number-field.module.css +126 -0
  874. package/src/components/ui/number-field.tsx +247 -0
  875. package/src/components/ui/pagination.module.css +64 -0
  876. package/src/components/ui/pagination.tsx +250 -72
  877. package/src/components/ui/popover.module.css +26 -0
  878. package/src/components/ui/popover.tsx +207 -25
  879. package/src/components/ui/progress.module.css +15 -0
  880. package/src/components/ui/progress.tsx +54 -16
  881. package/src/components/ui/radio-group.module.css +41 -0
  882. package/src/components/ui/radio-group.tsx +88 -34
  883. package/src/components/ui/resizable.module.css +67 -0
  884. package/src/components/ui/resizable.tsx +106 -26
  885. package/src/components/ui/ripple-button.module.css +35 -0
  886. package/src/components/ui/ripple-button.tsx +55 -21
  887. package/src/components/ui/scratcher.module.css +9 -0
  888. package/src/components/ui/scratcher.tsx +134 -108
  889. package/src/components/ui/scroll-area.module.css +47 -0
  890. package/src/components/ui/scroll-area.tsx +93 -34
  891. package/src/components/ui/select.module.css +131 -0
  892. package/src/components/ui/select.tsx +435 -124
  893. package/src/components/ui/separator.module.css +14 -0
  894. package/src/components/ui/separator.tsx +60 -18
  895. package/src/components/ui/sheet.module.css +138 -0
  896. package/src/components/ui/sheet.tsx +427 -95
  897. package/src/components/ui/sidebar.module.css +594 -0
  898. package/src/components/ui/sidebar.tsx +900 -425
  899. package/src/components/ui/skeleton.module.css +14 -0
  900. package/src/components/ui/skeleton.tsx +39 -9
  901. package/src/components/ui/slider.module.css +48 -0
  902. package/src/components/ui/slider.tsx +89 -16
  903. package/src/components/ui/sonner.module.css +246 -0
  904. package/src/components/ui/sonner.tsx +777 -25
  905. package/src/components/ui/spinner.module.css +25 -0
  906. package/src/components/ui/spinner.tsx +51 -12
  907. package/src/components/ui/stepper.module.css +72 -0
  908. package/src/components/ui/stepper.tsx +95 -0
  909. package/src/components/ui/switch.module.css +42 -0
  910. package/src/components/ui/switch.tsx +53 -20
  911. package/src/components/ui/table-skeleton.module.css +29 -0
  912. package/src/components/ui/table-skeleton.tsx +79 -0
  913. package/src/components/ui/table.module.css +66 -0
  914. package/src/components/ui/table.tsx +235 -61
  915. package/src/components/ui/tabs.module.css +89 -0
  916. package/src/components/ui/tabs.tsx +192 -45
  917. package/src/components/ui/textarea.module.css +30 -0
  918. package/src/components/ui/textarea.tsx +30 -10
  919. package/src/components/ui/timeline.module.css +43 -0
  920. package/src/components/ui/timeline.tsx +153 -0
  921. package/src/components/ui/toggle-group.module.css +5 -0
  922. package/src/components/ui/toggle-group.tsx +115 -32
  923. package/src/components/ui/toggle.module.css +57 -0
  924. package/src/components/ui/toggle.tsx +89 -33
  925. package/src/components/ui/toolbar.module.css +112 -0
  926. package/src/components/ui/toolbar.tsx +209 -0
  927. package/src/components/ui/tooltip.module.css +39 -0
  928. package/src/components/ui/tooltip.tsx +181 -24
  929. package/src/components/ui/typewriter.module.css +101 -0
  930. package/src/components/ui/typewriter.tsx +130 -128
  931. package/src/components/ui/visually-hidden.module.css +11 -0
  932. package/src/components/ui/visually-hidden.tsx +50 -0
  933. package/src/css-modules.d.ts +9 -0
  934. package/src/hooks/useAnnounce.tsx +73 -0
  935. package/src/hooks/useBreakpoint.tsx +41 -0
  936. package/src/hooks/useClipboard.tsx +137 -0
  937. package/src/hooks/useColorScheme.tsx +23 -0
  938. package/src/hooks/useControllableState.tsx +81 -0
  939. package/src/hooks/useDebounce.tsx +50 -0
  940. package/src/hooks/useEventCallback.tsx +47 -0
  941. package/src/hooks/useFocusManager.tsx +89 -0
  942. package/src/hooks/useFocusVisible.tsx +88 -0
  943. package/src/hooks/useId.tsx +36 -0
  944. package/src/hooks/useIntersectionObserver.tsx +81 -0
  945. package/src/hooks/useInterval.tsx +80 -0
  946. package/src/hooks/useIsMobile.tsx +7 -28
  947. package/src/hooks/useLocalStorage.tsx +111 -0
  948. package/src/hooks/useMediaQuery.tsx +34 -0
  949. package/src/hooks/useMergedRefs.tsx +48 -0
  950. package/src/hooks/useOnClickOutside.tsx +55 -0
  951. package/src/hooks/usePrefersContrast.tsx +24 -0
  952. package/src/hooks/usePrevious.tsx +44 -0
  953. package/src/hooks/useReducedMotion.tsx +20 -0
  954. package/src/hooks/useThrottle.tsx +78 -0
  955. package/src/hooks/useTimeout.tsx +51 -0
  956. package/src/index.css +127 -65
  957. package/src/index.ts +219 -18
  958. package/src/lib/utilities.ts +8 -7
  959. package/src/motion/Collapse.module.css +22 -0
  960. package/src/motion/Collapse.tsx +52 -0
  961. package/src/motion/Presence.tsx +44 -0
  962. package/src/motion/index.ts +13 -0
  963. package/src/motion/presets.ts +77 -0
  964. package/src/motion/tokens.ts +37 -0
  965. package/src/stories/DesignPrinciples.mdx +48 -0
  966. package/src/stories/GettingStarted.mdx +92 -0
  967. package/src/stories/Welcome.mdx +44 -0
  968. package/src/hooks/useIsMobile.test.tsx +0 -96
  969. package/src/hooks/useWindowSize.test.tsx +0 -57
  970. package/src/index.test.ts +0 -537
  971. package/src/lib/color-conversion-utilities.test.ts +0 -225
  972. package/src/lib/utilities.test.ts +0 -37
package/EXAMPLES.md CHANGED
@@ -1,22 +1,61 @@
1
1
  # 💡 Usage Examples for @arolariu/components
2
2
 
3
- > **Real-world examples to get you building faster!** Copy, paste, and customize these patterns for your projects.
3
+ > **Real-world examples to get you building faster.** Copy, paste, and customize these patterns for your projects.
4
4
 
5
5
  ## 🚀 Getting Started
6
6
 
7
7
  ### Installation & Setup
8
8
 
9
9
  ```bash
10
- # Install the package
11
10
  npm install @arolariu/components
12
11
 
13
- # Install peer dependencies if needed
14
- npm install react react-dom tailwindcss
12
+ # Peer dependencies (install if not already in your project)
13
+ npm install react react-dom @base-ui/react motion
15
14
  ```
16
15
 
17
16
  ```tsx
18
- // Add to your app's root (App.tsx, main.tsx, or _app.tsx)
17
+ // Import design tokens only once in your app entry point
19
18
  import "@arolariu/components/styles";
19
+
20
+ // Components auto-load their CSS when imported
21
+ import { Button, Card } from "@arolariu/components";
22
+ ```
23
+
24
+ `@arolariu/components/styles` provides design tokens only. Component CSS is loaded automatically when components are imported.
25
+
26
+ ```tsx
27
+ // Use local CSS Modules for application-specific layout and composition
28
+ import styles from "./my-component.module.css";
29
+ ```
30
+
31
+ `tailwindcss` is not a peer dependency in v1.0.0.
32
+
33
+ ### Useful Subpath Imports
34
+
35
+ ```tsx
36
+ import { Button } from "@arolariu/components/button";
37
+ import { useIsMobile } from "@arolariu/components/useIsMobile";
38
+ import { cn } from "@arolariu/components/utilities";
39
+ import { hexToHsl } from "@arolariu/components/color-conversion-utilities";
40
+ ```
41
+
42
+ ### Composition with the `render` Prop
43
+
44
+ ```tsx
45
+ import { Button } from "@arolariu/components";
46
+
47
+ // Use render prop instead of asChild
48
+ <Button render={<a href="/dashboard" />}>
49
+ Go to Dashboard
50
+ </Button>
51
+ ```
52
+
53
+ ```css
54
+ /* my-component.module.css */
55
+ .page {
56
+ min-height: 100vh;
57
+ padding: 2rem;
58
+ }
20
59
  ```
21
60
 
22
61
  ---
@@ -26,51 +65,91 @@ import "@arolariu/components/styles";
26
65
  ### Simple Card Layout
27
66
 
28
67
  ```tsx
68
+ import { Badge } from "@arolariu/components/badge";
69
+ import { Button } from "@arolariu/components/button";
29
70
  import {
30
71
  Card,
31
- CardHeader,
32
- CardTitle,
33
72
  CardContent,
34
73
  CardFooter,
74
+ CardHeader,
75
+ CardTitle,
35
76
  } from "@arolariu/components/card";
36
- import { Button } from "@arolariu/components/button";
37
- import { Badge } from "@arolariu/components/badge";
77
+ import styles from "./product-card.module.css";
38
78
 
39
79
  export function ProductCard() {
40
80
  return (
41
- <Card className="w-96">
81
+ <Card className={styles.card}>
42
82
  <CardHeader>
43
- <div className="flex items-center justify-between">
83
+ <div className={styles.headerRow}>
44
84
  <CardTitle>Premium Plan</CardTitle>
45
85
  <Badge variant="secondary">Popular</Badge>
46
86
  </div>
47
87
  </CardHeader>
48
- <CardContent>
49
- <p className="text-3xl font-bold">
50
- $29<span className="text-sm font-normal">/month</span>
88
+ <CardContent className={styles.content}>
89
+ <p className={styles.price}>
90
+ $29<span className={styles.priceSuffix}>/month</span>
51
91
  </p>
52
- <ul className="mt-4 space-y-2">
92
+ <ul className={styles.featureList}>
53
93
  <li>✅ Unlimited projects</li>
54
94
  <li>✅ Priority support</li>
55
95
  <li>✅ Advanced analytics</li>
56
96
  </ul>
57
97
  </CardContent>
58
98
  <CardFooter>
59
- <Button className="w-full">Subscribe Now</Button>
99
+ <Button className={styles.primaryAction}>Subscribe Now</Button>
60
100
  </CardFooter>
61
101
  </Card>
62
102
  );
63
103
  }
64
104
  ```
65
105
 
106
+ ```css
107
+ /* product-card.module.css */
108
+ .card {
109
+ width: 24rem;
110
+ }
111
+
112
+ .headerRow {
113
+ display: flex;
114
+ align-items: center;
115
+ justify-content: space-between;
116
+ gap: 1rem;
117
+ }
118
+
119
+ .content {
120
+ display: grid;
121
+ gap: 1rem;
122
+ }
123
+
124
+ .price {
125
+ font-size: 1.875rem;
126
+ font-weight: 700;
127
+ }
128
+
129
+ .priceSuffix {
130
+ font-size: 0.875rem;
131
+ font-weight: 400;
132
+ }
133
+
134
+ .featureList {
135
+ display: grid;
136
+ gap: 0.5rem;
137
+ padding-left: 1.25rem;
138
+ }
139
+
140
+ .primaryAction {
141
+ width: 100%;
142
+ }
143
+ ```
144
+
66
145
  ### Dashboard Layout with Sidebar
67
146
 
68
147
  ```tsx
69
148
  import {
70
- Sidebar,
71
- SidebarContent,
72
- SidebarMenuItem,
73
- } from "@arolariu/components/sidebar";
149
+ Avatar,
150
+ AvatarFallback,
151
+ AvatarImage,
152
+ } from "@arolariu/components/avatar";
74
153
  import {
75
154
  Card,
76
155
  CardContent,
@@ -79,61 +158,73 @@ import {
79
158
  } from "@arolariu/components/card";
80
159
  import { Progress } from "@arolariu/components/progress";
81
160
  import {
82
- Avatar,
83
- AvatarImage,
84
- AvatarFallback,
85
- } from "@arolariu/components/avatar";
161
+ Sidebar,
162
+ SidebarContent,
163
+ SidebarMenu,
164
+ SidebarMenuButton,
165
+ SidebarMenuItem,
166
+ SidebarProvider,
167
+ } from "@arolariu/components/sidebar";
168
+ import styles from "./dashboard.module.css";
86
169
 
87
170
  export function Dashboard() {
88
171
  return (
89
- <div className="flex h-screen">
90
- {/* Sidebar */}
91
- <Sidebar>
92
- <SidebarContent>
93
- <SidebarMenuItem href="/dashboard">Dashboard</SidebarMenuItem>
94
- <SidebarMenuItem href="/projects">Projects</SidebarMenuItem>
95
- <SidebarMenuItem href="/settings">Settings</SidebarMenuItem>
96
- </SidebarContent>
97
- </Sidebar>
98
-
99
- {/* Main Content */}
100
- <main className="flex-1 p-6 overflow-auto">
101
- <h1 className="text-3xl font-bold mb-6">Dashboard</h1>
102
-
103
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
104
- <Card>
105
- <CardHeader>
106
- <CardTitle>Project Progress</CardTitle>
107
- </CardHeader>
108
- <CardContent>
109
- <Progress value={75} className="w-full" />
110
- <p className="text-sm text-muted-foreground mt-2">75% complete</p>
111
- </CardContent>
112
- </Card>
113
-
114
- <Card>
115
- <CardHeader>
116
- <CardTitle>Team Members</CardTitle>
117
- </CardHeader>
118
- <CardContent>
119
- <div className="flex -space-x-2">
120
- <Avatar className="border-2 border-background">
121
- <AvatarImage src="/avatar1.jpg" />
122
- <AvatarFallback>JD</AvatarFallback>
123
- </Avatar>
124
- <Avatar className="border-2 border-background">
125
- <AvatarImage src="/avatar2.jpg" />
126
- <AvatarFallback>SM</AvatarFallback>
127
- </Avatar>
128
- <Avatar className="border-2 border-background">
129
- <AvatarFallback>+3</AvatarFallback>
130
- </Avatar>
131
- </div>
132
- </CardContent>
133
- </Card>
134
- </div>
135
- </main>
136
- </div>
172
+ <SidebarProvider>
173
+ <div className={styles.layout}>
174
+ <Sidebar>
175
+ <SidebarContent>
176
+ <SidebarMenu>
177
+ <SidebarMenuItem>
178
+ <SidebarMenuButton isActive>Dashboard</SidebarMenuButton>
179
+ </SidebarMenuItem>
180
+ <SidebarMenuItem>
181
+ <SidebarMenuButton>Projects</SidebarMenuButton>
182
+ </SidebarMenuItem>
183
+ <SidebarMenuItem>
184
+ <SidebarMenuButton>Settings</SidebarMenuButton>
185
+ </SidebarMenuItem>
186
+ </SidebarMenu>
187
+ </SidebarContent>
188
+ </Sidebar>
189
+
190
+ <main className={styles.main}>
191
+ <h1 className={styles.title}>Dashboard</h1>
192
+
193
+ <div className={styles.cardGrid}>
194
+ <Card>
195
+ <CardHeader>
196
+ <CardTitle>Project Progress</CardTitle>
197
+ </CardHeader>
198
+ <CardContent className={styles.stack}>
199
+ <Progress value={75} />
200
+ <p className={styles.mutedText}>75% complete</p>
201
+ </CardContent>
202
+ </Card>
203
+
204
+ <Card>
205
+ <CardHeader>
206
+ <CardTitle>Team Members</CardTitle>
207
+ </CardHeader>
208
+ <CardContent>
209
+ <div className={styles.avatarRow}>
210
+ <Avatar className={styles.avatar}>
211
+ <AvatarImage src="/avatar1.jpg" />
212
+ <AvatarFallback>JD</AvatarFallback>
213
+ </Avatar>
214
+ <Avatar className={styles.avatar}>
215
+ <AvatarImage src="/avatar2.jpg" />
216
+ <AvatarFallback>SM</AvatarFallback>
217
+ </Avatar>
218
+ <Avatar className={styles.avatar}>
219
+ <AvatarFallback>+3</AvatarFallback>
220
+ </Avatar>
221
+ </div>
222
+ </CardContent>
223
+ </Card>
224
+ </div>
225
+ </main>
226
+ </div>
227
+ </SidebarProvider>
137
228
  );
138
229
  }
139
230
  ```
@@ -145,19 +236,21 @@ export function Dashboard() {
145
236
  ### Complete Login Form
146
237
 
147
238
  ```tsx
239
+ import { useState } from "react";
240
+
241
+ import { Alert, AlertDescription } from "@arolariu/components/alert";
242
+ import { Button } from "@arolariu/components/button";
148
243
  import {
149
244
  Card,
150
- CardHeader,
151
- CardTitle,
152
245
  CardContent,
153
246
  CardFooter,
247
+ CardHeader,
248
+ CardTitle,
154
249
  } from "@arolariu/components/card";
250
+ import { Checkbox } from "@arolariu/components/checkbox";
155
251
  import { Input } from "@arolariu/components/input";
156
- import { Button } from "@arolariu/components/button";
157
252
  import { Label } from "@arolariu/components/label";
158
- import { Checkbox } from "@arolariu/components/checkbox";
159
- import { Alert, AlertDescription } from "@arolariu/components/alert";
160
- import { useState } from "react";
253
+ import styles from "./login-form.module.css";
161
254
 
162
255
  export function LoginForm() {
163
256
  const [email, setEmail] = useState("");
@@ -166,16 +259,15 @@ export function LoginForm() {
166
259
  const [error, setError] = useState("");
167
260
  const [loading, setLoading] = useState(false);
168
261
 
169
- const handleSubmit = async (e: React.FormEvent) => {
170
- e.preventDefault();
262
+ const handleSubmit = async (event: React.FormEvent) => {
263
+ event.preventDefault();
171
264
  setLoading(true);
172
265
  setError("");
173
266
 
174
267
  try {
175
- // Your login logic here
176
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate API call
177
- console.log("Login successful!");
178
- } catch (err) {
268
+ await new Promise((resolve) => setTimeout(resolve, 1000));
269
+ console.log("Login successful");
270
+ } catch {
179
271
  setError("Invalid email or password");
180
272
  } finally {
181
273
  setLoading(false);
@@ -183,43 +275,43 @@ export function LoginForm() {
183
275
  };
184
276
 
185
277
  return (
186
- <div className="min-h-screen flex items-center justify-center bg-gray-50">
187
- <Card className="w-full max-w-md">
278
+ <div className={styles.page}>
279
+ <Card className={styles.card}>
188
280
  <CardHeader>
189
- <CardTitle className="text-center">Welcome Back</CardTitle>
281
+ <CardTitle className={styles.centeredTitle}>Welcome Back</CardTitle>
190
282
  </CardHeader>
191
283
  <form onSubmit={handleSubmit}>
192
- <CardContent className="space-y-4">
193
- {error && (
284
+ <CardContent className={styles.content}>
285
+ {error ? (
194
286
  <Alert variant="destructive">
195
287
  <AlertDescription>{error}</AlertDescription>
196
288
  </Alert>
197
- )}
289
+ ) : null}
198
290
 
199
- <div className="space-y-2">
291
+ <div className={styles.field}>
200
292
  <Label htmlFor="email">Email</Label>
201
293
  <Input
202
294
  id="email"
203
295
  type="email"
204
296
  placeholder="you@example.com"
205
297
  value={email}
206
- onChange={(e) => setEmail(e.target.value)}
298
+ onChange={(event) => setEmail(event.target.value)}
207
299
  required
208
300
  />
209
301
  </div>
210
302
 
211
- <div className="space-y-2">
303
+ <div className={styles.field}>
212
304
  <Label htmlFor="password">Password</Label>
213
305
  <Input
214
306
  id="password"
215
307
  type="password"
216
308
  value={password}
217
- onChange={(e) => setPassword(e.target.value)}
309
+ onChange={(event) => setPassword(event.target.value)}
218
310
  required
219
311
  />
220
312
  </div>
221
313
 
222
- <div className="flex items-center space-x-2">
314
+ <div className={styles.checkboxRow}>
223
315
  <Checkbox
224
316
  id="remember"
225
317
  checked={rememberMe}
@@ -229,13 +321,20 @@ export function LoginForm() {
229
321
  </div>
230
322
  </CardContent>
231
323
 
232
- <CardFooter className="flex flex-col space-y-2">
233
- <Button type="submit" className="w-full" disabled={loading}>
324
+ <CardFooter className={styles.footer}>
325
+ <Button
326
+ type="submit"
327
+ className={styles.submitButton}
328
+ disabled={loading}
329
+ >
234
330
  {loading ? "Signing in..." : "Sign In"}
235
331
  </Button>
236
- <Button variant="link" size="sm">
332
+ <a
333
+ className={styles.link}
334
+ href="/forgot-password"
335
+ >
237
336
  Forgot your password?
238
- </Button>
337
+ </a>
239
338
  </CardFooter>
240
339
  </form>
241
340
  </Card>
@@ -247,9 +346,11 @@ export function LoginForm() {
247
346
  ### Advanced Form with Validation
248
347
 
249
348
  ```tsx
250
- import { useForm } from "react-hook-form";
251
349
  import { zodResolver } from "@hookform/resolvers/zod";
350
+ import { useForm } from "react-hook-form";
252
351
  import * as z from "zod";
352
+
353
+ import { Button } from "@arolariu/components/button";
253
354
  import {
254
355
  Form,
255
356
  FormControl,
@@ -260,7 +361,6 @@ import {
260
361
  FormMessage,
261
362
  } from "@arolariu/components/form";
262
363
  import { Input } from "@arolariu/components/input";
263
- import { Button } from "@arolariu/components/button";
264
364
  import {
265
365
  Select,
266
366
  SelectContent,
@@ -269,6 +369,7 @@ import {
269
369
  SelectValue,
270
370
  } from "@arolariu/components/select";
271
371
  import { Textarea } from "@arolariu/components/textarea";
372
+ import styles from "./profile-form.module.css";
272
373
 
273
374
  const formSchema = z.object({
274
375
  firstName: z.string().min(2, "First name must be at least 2 characters"),
@@ -298,9 +399,9 @@ export function ProfileForm() {
298
399
  <Form {...form}>
299
400
  <form
300
401
  onSubmit={form.handleSubmit(onSubmit)}
301
- className="space-y-6 max-w-md"
402
+ className={styles.form}
302
403
  >
303
- <div className="grid grid-cols-2 gap-4">
404
+ <div className={styles.twoColumnGrid}>
304
405
  <FormField
305
406
  control={form.control}
306
407
  name="firstName"
@@ -308,7 +409,10 @@ export function ProfileForm() {
308
409
  <FormItem>
309
410
  <FormLabel>First Name</FormLabel>
310
411
  <FormControl>
311
- <Input placeholder="John" {...field} />
412
+ <Input
413
+ placeholder="John"
414
+ {...field}
415
+ />
312
416
  </FormControl>
313
417
  <FormMessage />
314
418
  </FormItem>
@@ -322,7 +426,10 @@ export function ProfileForm() {
322
426
  <FormItem>
323
427
  <FormLabel>Last Name</FormLabel>
324
428
  <FormControl>
325
- <Input placeholder="Doe" {...field} />
429
+ <Input
430
+ placeholder="Doe"
431
+ {...field}
432
+ />
326
433
  </FormControl>
327
434
  <FormMessage />
328
435
  </FormItem>
@@ -337,10 +444,13 @@ export function ProfileForm() {
337
444
  <FormItem>
338
445
  <FormLabel>Email</FormLabel>
339
446
  <FormControl>
340
- <Input placeholder="john.doe@example.com" {...field} />
447
+ <Input
448
+ placeholder="john.doe@example.com"
449
+ {...field}
450
+ />
341
451
  </FormControl>
342
452
  <FormDescription>
343
- We'll never share your email with anyone else.
453
+ We&apos;ll never share your email with anyone else.
344
454
  </FormDescription>
345
455
  <FormMessage />
346
456
  </FormItem>
@@ -353,7 +463,10 @@ export function ProfileForm() {
353
463
  render={({ field }) => (
354
464
  <FormItem>
355
465
  <FormLabel>Role</FormLabel>
356
- <Select onValueChange={field.onChange} defaultValue={field.value}>
466
+ <Select
467
+ defaultValue={field.value}
468
+ onValueChange={field.onChange}
469
+ >
357
470
  <FormControl>
358
471
  <SelectTrigger>
359
472
  <SelectValue placeholder="Select a role" />
@@ -379,7 +492,7 @@ export function ProfileForm() {
379
492
  <FormControl>
380
493
  <Textarea
381
494
  placeholder="Tell us about yourself"
382
- className="min-h-[100px]"
495
+ className={styles.textarea}
383
496
  {...field}
384
497
  />
385
498
  </FormControl>
@@ -402,17 +515,10 @@ export function ProfileForm() {
402
515
  ### Responsive Header Navigation
403
516
 
404
517
  ```tsx
405
- import {
406
- NavigationMenu,
407
- NavigationMenuItem,
408
- NavigationMenuList,
409
- } from "@arolariu/components/navigation-menu";
410
- import { Button } from "@arolariu/components/button";
411
- import { Sheet, SheetContent, SheetTrigger } from "@arolariu/components/sheet";
412
518
  import {
413
519
  Avatar,
414
- AvatarImage,
415
520
  AvatarFallback,
521
+ AvatarImage,
416
522
  } from "@arolariu/components/avatar";
417
523
  import {
418
524
  DropdownMenu,
@@ -420,101 +526,82 @@ import {
420
526
  DropdownMenuItem,
421
527
  DropdownMenuTrigger,
422
528
  } from "@arolariu/components/dropdown-menu";
423
- import { MenuIcon, User, Settings, LogOut } from "lucide-react";
529
+ import {
530
+ NavigationMenu,
531
+ NavigationMenuItem,
532
+ NavigationMenuLink,
533
+ NavigationMenuList,
534
+ } from "@arolariu/components/navigation-menu";
535
+ import { Sheet, SheetContent, SheetTrigger } from "@arolariu/components/sheet";
536
+ import { LogOut, MenuIcon, Settings, User } from "lucide-react";
537
+ import styles from "./app-header.module.css";
424
538
 
425
539
  export function AppHeader() {
426
540
  return (
427
- <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
428
- <div className="container flex h-14 items-center">
429
- <div className="mr-4 hidden md:flex">
430
- <a className="mr-6 flex items-center space-x-2" href="/">
431
- <span className="hidden font-bold sm:inline-block">MyApp</span>
541
+ <header className={styles.header}>
542
+ <div className={styles.headerInner}>
543
+ <div className={styles.desktopArea}>
544
+ <a
545
+ className={styles.brandLink}
546
+ href="/"
547
+ >
548
+ <span className={styles.brandName}>MyApp</span>
432
549
  </a>
433
550
 
434
551
  <NavigationMenu>
435
552
  <NavigationMenuList>
436
553
  <NavigationMenuItem>
437
- <Button variant="ghost" href="/dashboard">
438
- Dashboard
439
- </Button>
554
+ <NavigationMenuLink href="/dashboard">Dashboard</NavigationMenuLink>
440
555
  </NavigationMenuItem>
441
556
  <NavigationMenuItem>
442
- <Button variant="ghost" href="/projects">
443
- Projects
444
- </Button>
557
+ <NavigationMenuLink href="/projects">Projects</NavigationMenuLink>
445
558
  </NavigationMenuItem>
446
559
  <NavigationMenuItem>
447
- <Button variant="ghost" href="/analytics">
448
- Analytics
449
- </Button>
560
+ <NavigationMenuLink href="/analytics">Analytics</NavigationMenuLink>
450
561
  </NavigationMenuItem>
451
562
  </NavigationMenuList>
452
563
  </NavigationMenu>
453
564
  </div>
454
565
 
455
- {/* Mobile Navigation */}
456
566
  <Sheet>
457
- <SheetTrigger asChild>
458
- <Button
459
- variant="ghost"
460
- className="mr-2 px-0 text-base hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 md:hidden"
461
- >
462
- <MenuIcon className="h-5 w-5" />
463
- </Button>
567
+ <SheetTrigger
568
+ render={<button type="button" className={styles.mobileMenuButton} />}
569
+ >
570
+ <MenuIcon />
464
571
  </SheetTrigger>
465
572
  <SheetContent side="left">
466
- <nav className="flex flex-col space-y-3">
467
- <Button
468
- variant="ghost"
469
- className="justify-start"
470
- href="/dashboard"
471
- >
472
- Dashboard
473
- </Button>
474
- <Button
475
- variant="ghost"
476
- className="justify-start"
477
- href="/projects"
478
- >
479
- Projects
480
- </Button>
481
- <Button
482
- variant="ghost"
483
- className="justify-start"
484
- href="/analytics"
485
- >
486
- Analytics
487
- </Button>
573
+ <nav className={styles.mobileNav}>
574
+ <a href="/dashboard">Dashboard</a>
575
+ <a href="/projects">Projects</a>
576
+ <a href="/analytics">Analytics</a>
488
577
  </nav>
489
578
  </SheetContent>
490
579
  </Sheet>
491
580
 
492
- <div className="flex flex-1 items-center justify-between space-x-2 md:justify-end">
493
- <div className="w-full flex-1 md:w-auto md:flex-none">
494
- {/* Search or other content can go here */}
495
- </div>
496
-
497
- {/* User Menu */}
581
+ <div className={styles.actions}>
498
582
  <DropdownMenu>
499
- <DropdownMenuTrigger asChild>
500
- <Button variant="ghost" className="relative h-8 w-8 rounded-full">
501
- <Avatar className="h-8 w-8">
502
- <AvatarImage src="/avatars/01.png" alt="User" />
503
- <AvatarFallback>JD</AvatarFallback>
504
- </Avatar>
505
- </Button>
583
+ <DropdownMenuTrigger
584
+ render={<button type="button" className={styles.avatarButton} />}
585
+ >
586
+ <Avatar>
587
+ <AvatarImage
588
+ src="/avatars/01.png"
589
+ alt="User"
590
+ />
591
+ <AvatarFallback>JD</AvatarFallback>
592
+ </Avatar>
506
593
  </DropdownMenuTrigger>
507
- <DropdownMenuContent className="w-56" align="end" forceMount>
594
+ <DropdownMenuContent align="end">
508
595
  <DropdownMenuItem>
509
- <User className="mr-2 h-4 w-4" />
596
+ <User />
510
597
  <span>Profile</span>
511
598
  </DropdownMenuItem>
512
599
  <DropdownMenuItem>
513
- <Settings className="mr-2 h-4 w-4" />
600
+ <Settings />
514
601
  <span>Settings</span>
515
602
  </DropdownMenuItem>
516
603
  <DropdownMenuItem>
517
- <LogOut className="mr-2 h-4 w-4" />
604
+ <LogOut />
518
605
  <span>Log out</span>
519
606
  </DropdownMenuItem>
520
607
  </DropdownMenuContent>
@@ -533,6 +620,13 @@ export function AppHeader() {
533
620
  ### Interactive Data Table
534
621
 
535
622
  ```tsx
623
+ import { Badge } from "@arolariu/components/badge";
624
+ import {
625
+ DropdownMenu,
626
+ DropdownMenuContent,
627
+ DropdownMenuItem,
628
+ DropdownMenuTrigger,
629
+ } from "@arolariu/components/dropdown-menu";
536
630
  import {
537
631
  Table,
538
632
  TableBody,
@@ -542,15 +636,8 @@ import {
542
636
  TableHeader,
543
637
  TableRow,
544
638
  } from "@arolariu/components/table";
545
- import { Badge } from "@arolariu/components/badge";
546
- import { Button } from "@arolariu/components/button";
547
- import {
548
- DropdownMenu,
549
- DropdownMenuContent,
550
- DropdownMenuItem,
551
- DropdownMenuTrigger,
552
- } from "@arolariu/components/dropdown-menu";
553
- import { MoreHorizontal, Eye, Edit, Trash } from "lucide-react";
639
+ import { Edit, Eye, MoreHorizontal, Trash } from "lucide-react";
640
+ import styles from "./users-table.module.css";
554
641
 
555
642
  interface User {
556
643
  id: string;
@@ -600,8 +687,8 @@ export function UsersTable() {
600
687
  };
601
688
 
602
689
  return (
603
- <div className="w-full">
604
- <div className="rounded-md border">
690
+ <div className={styles.wrapper}>
691
+ <div className={styles.tableShell}>
605
692
  <Table>
606
693
  <TableCaption>A list of your team members.</TableCaption>
607
694
  <TableHeader>
@@ -611,35 +698,35 @@ export function UsersTable() {
611
698
  <TableHead>Role</TableHead>
612
699
  <TableHead>Status</TableHead>
613
700
  <TableHead>Last Login</TableHead>
614
- <TableHead className="w-[100px]">Actions</TableHead>
701
+ <TableHead className={styles.actionsColumn}>Actions</TableHead>
615
702
  </TableRow>
616
703
  </TableHeader>
617
704
  <TableBody>
618
705
  {users.map((user) => (
619
706
  <TableRow key={user.id}>
620
- <TableCell className="font-medium">{user.name}</TableCell>
707
+ <TableCell className={styles.emphasisCell}>{user.name}</TableCell>
621
708
  <TableCell>{user.email}</TableCell>
622
709
  <TableCell>{user.role}</TableCell>
623
710
  <TableCell>{getStatusBadge(user.status)}</TableCell>
624
711
  <TableCell>{user.lastLogin}</TableCell>
625
712
  <TableCell>
626
713
  <DropdownMenu>
627
- <DropdownMenuTrigger asChild>
628
- <Button variant="ghost" className="h-8 w-8 p-0">
629
- <MoreHorizontal className="h-4 w-4" />
630
- </Button>
714
+ <DropdownMenuTrigger
715
+ render={<button type="button" className={styles.iconButton} />}
716
+ >
717
+ <MoreHorizontal />
631
718
  </DropdownMenuTrigger>
632
719
  <DropdownMenuContent align="end">
633
720
  <DropdownMenuItem>
634
- <Eye className="mr-2 h-4 w-4" />
721
+ <Eye />
635
722
  View
636
723
  </DropdownMenuItem>
637
724
  <DropdownMenuItem>
638
- <Edit className="mr-2 h-4 w-4" />
725
+ <Edit />
639
726
  Edit
640
727
  </DropdownMenuItem>
641
- <DropdownMenuItem className="text-red-600">
642
- <Trash className="mr-2 h-4 w-4" />
728
+ <DropdownMenuItem className={styles.dangerItem}>
729
+ <Trash />
643
730
  Delete
644
731
  </DropdownMenuItem>
645
732
  </DropdownMenuContent>
@@ -673,8 +760,8 @@ import {
673
760
  AlertDialogTitle,
674
761
  AlertDialogTrigger,
675
762
  } from "@arolariu/components/alert-dialog";
676
- import { Button } from "@arolariu/components/button";
677
763
  import { Trash } from "lucide-react";
764
+ import styles from "./delete-confirmation.module.css";
678
765
 
679
766
  export function DeleteConfirmation({
680
767
  itemName,
@@ -685,26 +772,26 @@ export function DeleteConfirmation({
685
772
  }) {
686
773
  return (
687
774
  <AlertDialog>
688
- <AlertDialogTrigger asChild>
689
- <Button variant="destructive" size="sm">
690
- <Trash className="mr-2 h-4 w-4" />
691
- Delete
692
- </Button>
775
+ <AlertDialogTrigger
776
+ render={<button type="button" className={styles.triggerButton} />}
777
+ >
778
+ <Trash />
779
+ Delete
693
780
  </AlertDialogTrigger>
694
781
  <AlertDialogContent>
695
782
  <AlertDialogHeader>
696
783
  <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
697
784
  <AlertDialogDescription>
698
- This action cannot be undone. This will permanently delete "
699
- {itemName}" and remove all associated data from our servers.
785
+ This action cannot be undone. This will permanently delete
786
+ {" "}
787
+ {itemName}
788
+ {" "}
789
+ and remove all associated data from our servers.
700
790
  </AlertDialogDescription>
701
791
  </AlertDialogHeader>
702
792
  <AlertDialogFooter>
703
793
  <AlertDialogCancel>Cancel</AlertDialogCancel>
704
- <AlertDialogAction
705
- onClick={onConfirm}
706
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
707
- >
794
+ <AlertDialogAction onClick={onConfirm}>
708
795
  Yes, delete it
709
796
  </AlertDialogAction>
710
797
  </AlertDialogFooter>
@@ -717,6 +804,7 @@ export function DeleteConfirmation({
717
804
  ### Settings Modal
718
805
 
719
806
  ```tsx
807
+ import { Button } from "@arolariu/components/button";
720
808
  import {
721
809
  Dialog,
722
810
  DialogContent,
@@ -726,10 +814,8 @@ import {
726
814
  DialogTitle,
727
815
  DialogTrigger,
728
816
  } from "@arolariu/components/dialog";
729
- import { Button } from "@arolariu/components/button";
730
817
  import { Input } from "@arolariu/components/input";
731
818
  import { Label } from "@arolariu/components/label";
732
- import { Switch } from "@arolariu/components/switch";
733
819
  import {
734
820
  Select,
735
821
  SelectContent,
@@ -737,24 +823,21 @@ import {
737
823
  SelectTrigger,
738
824
  SelectValue,
739
825
  } from "@arolariu/components/select";
740
- import {
741
- Tabs,
742
- TabsContent,
743
- TabsList,
744
- TabsTrigger,
745
- } from "@arolariu/components/tabs";
826
+ import { Switch } from "@arolariu/components/switch";
827
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@arolariu/components/tabs";
746
828
  import { Settings } from "lucide-react";
829
+ import styles from "./settings-dialog.module.css";
747
830
 
748
831
  export function SettingsDialog() {
749
832
  return (
750
833
  <Dialog>
751
- <DialogTrigger asChild>
752
- <Button variant="outline">
753
- <Settings className="mr-2 h-4 w-4" />
754
- Settings
755
- </Button>
834
+ <DialogTrigger
835
+ render={<button type="button" className={styles.trigger} />}
836
+ >
837
+ <Settings />
838
+ Settings
756
839
  </DialogTrigger>
757
- <DialogContent className="sm:max-w-[525px]">
840
+ <DialogContent className={styles.dialogContent}>
758
841
  <DialogHeader>
759
842
  <DialogTitle>Settings</DialogTitle>
760
843
  <DialogDescription>
@@ -762,23 +845,35 @@ export function SettingsDialog() {
762
845
  </DialogDescription>
763
846
  </DialogHeader>
764
847
 
765
- <Tabs defaultValue="general" className="w-full">
766
- <TabsList className="grid w-full grid-cols-3">
848
+ <Tabs
849
+ defaultValue="general"
850
+ className={styles.tabs}
851
+ >
852
+ <TabsList className={styles.tabsList}>
767
853
  <TabsTrigger value="general">General</TabsTrigger>
768
854
  <TabsTrigger value="notifications">Notifications</TabsTrigger>
769
855
  <TabsTrigger value="security">Security</TabsTrigger>
770
856
  </TabsList>
771
857
 
772
- <TabsContent value="general" className="space-y-4">
773
- <div className="space-y-2">
858
+ <TabsContent
859
+ value="general"
860
+ className={styles.panel}
861
+ >
862
+ <div className={styles.field}>
774
863
  <Label htmlFor="name">Display Name</Label>
775
- <Input id="name" defaultValue="John Doe" />
864
+ <Input
865
+ id="name"
866
+ defaultValue="John Doe"
867
+ />
776
868
  </div>
777
- <div className="space-y-2">
869
+ <div className={styles.field}>
778
870
  <Label htmlFor="email">Email</Label>
779
- <Input id="email" defaultValue="john@example.com" />
871
+ <Input
872
+ id="email"
873
+ defaultValue="john@example.com"
874
+ />
780
875
  </div>
781
- <div className="space-y-2">
876
+ <div className={styles.field}>
782
877
  <Label htmlFor="timezone">Timezone</Label>
783
878
  <Select defaultValue="utc">
784
879
  <SelectTrigger>
@@ -793,20 +888,23 @@ export function SettingsDialog() {
793
888
  </div>
794
889
  </TabsContent>
795
890
 
796
- <TabsContent value="notifications" className="space-y-4">
797
- <div className="flex items-center justify-between">
798
- <div className="space-y-0.5">
891
+ <TabsContent
892
+ value="notifications"
893
+ className={styles.panel}
894
+ >
895
+ <div className={styles.switchRow}>
896
+ <div className={styles.switchText}>
799
897
  <Label>Email Notifications</Label>
800
- <div className="text-sm text-muted-foreground">
898
+ <div className={styles.mutedText}>
801
899
  Receive emails about your account activity.
802
900
  </div>
803
901
  </div>
804
902
  <Switch />
805
903
  </div>
806
- <div className="flex items-center justify-between">
807
- <div className="space-y-0.5">
904
+ <div className={styles.switchRow}>
905
+ <div className={styles.switchText}>
808
906
  <Label>Push Notifications</Label>
809
- <div className="text-sm text-muted-foreground">
907
+ <div className={styles.mutedText}>
810
908
  Receive push notifications on your devices.
811
909
  </div>
812
910
  </div>
@@ -814,18 +912,30 @@ export function SettingsDialog() {
814
912
  </div>
815
913
  </TabsContent>
816
914
 
817
- <TabsContent value="security" className="space-y-4">
818
- <div className="space-y-2">
915
+ <TabsContent
916
+ value="security"
917
+ className={styles.panel}
918
+ >
919
+ <div className={styles.field}>
819
920
  <Label htmlFor="current-password">Current Password</Label>
820
- <Input id="current-password" type="password" />
921
+ <Input
922
+ id="current-password"
923
+ type="password"
924
+ />
821
925
  </div>
822
- <div className="space-y-2">
926
+ <div className={styles.field}>
823
927
  <Label htmlFor="new-password">New Password</Label>
824
- <Input id="new-password" type="password" />
928
+ <Input
929
+ id="new-password"
930
+ type="password"
931
+ />
825
932
  </div>
826
- <div className="space-y-2">
933
+ <div className={styles.field}>
827
934
  <Label htmlFor="confirm-password">Confirm Password</Label>
828
- <Input id="confirm-password" type="password" />
935
+ <Input
936
+ id="confirm-password"
937
+ type="password"
938
+ />
829
939
  </div>
830
940
  </TabsContent>
831
941
  </Tabs>
@@ -842,81 +952,75 @@ export function SettingsDialog() {
842
952
 
843
953
  ---
844
954
 
845
- ## 🎨 Background Effects Examples
955
+ ## 🎨 Theming Examples
956
+
957
+ ### App Theme with `--ac-*` Tokens
958
+
959
+ ```css
960
+ :root {
961
+ --ac-primary: oklch(0.6 0.2 250);
962
+ --ac-radius: 0.5rem;
963
+ }
964
+ ```
965
+
966
+ ```css
967
+ /* app-theme.module.css */
968
+ .themeScope {
969
+ --ac-primary: oklch(0.68 0.2 258);
970
+ --ac-primary-foreground: oklch(0.98 0.01 258);
971
+ --ac-secondary: oklch(0.95 0.02 286);
972
+ --ac-background: oklch(0.99 0 0);
973
+ --ac-radius-md: 0.75rem;
974
+ --ac-radius-lg: 1rem;
975
+ }
846
976
 
847
- ### Animated Landing Page
977
+ .themeScope[data-theme="dark"] {
978
+ --ac-background: oklch(0.17 0.01 286);
979
+ --ac-foreground: oklch(0.98 0 0);
980
+ --ac-card: oklch(0.2 0.01 286);
981
+ }
982
+ ```
848
983
 
849
984
  ```tsx
850
- import { DotBackground } from "@arolariu/components/dot-background";
851
- import { BubbleBackground } from "@arolariu/components/bubble-background";
852
- import { GradientBackground } from "@arolariu/components/gradient-background";
853
985
  import { Button } from "@arolariu/components/button";
854
- import { Card, CardContent } from "@arolariu/components/card";
986
+ import { Card, CardContent, CardHeader, CardTitle } from "@arolariu/components/card";
987
+ import styles from "./app-theme.module.css";
855
988
 
856
- export function LandingPage() {
989
+ export function ThemePreview() {
857
990
  return (
858
- <div className="relative min-h-screen overflow-hidden">
859
- {/* Animated Background */}
860
- <DotBackground className="absolute inset-0" />
861
- <GradientBackground className="absolute inset-0" />
862
-
863
- {/* Content */}
864
- <div className="relative z-10 flex min-h-screen flex-col items-center justify-center px-4 text-center">
865
- <h1 className="mb-6 text-4xl font-bold tracking-tight sm:text-6xl">
866
- Build Beautiful Apps
867
- <span className="bg-gradient-to-r from-purple-600 to-pink-600 bg-clip-text text-transparent">
868
- {" "}
869
- Faster
870
- </span>
871
- </h1>
872
-
873
- <p className="mb-8 max-w-2xl text-lg text-muted-foreground">
874
- Create stunning user interfaces with our comprehensive React component
875
- library. Built with accessibility, performance, and developer
876
- experience in mind.
877
- </p>
991
+ <section
992
+ className={styles.themeScope}
993
+ data-theme="dark"
994
+ >
995
+ <Card>
996
+ <CardHeader>
997
+ <CardTitle>Custom theme scope</CardTitle>
998
+ </CardHeader>
999
+ <CardContent>
1000
+ <Button>Token-driven button</Button>
1001
+ </CardContent>
1002
+ </Card>
1003
+ </section>
1004
+ );
1005
+ }
1006
+ ```
878
1007
 
879
- <div className="flex flex-col gap-4 sm:flex-row">
880
- <Button size="lg" className="px-8">
881
- Get Started
882
- </Button>
883
- <Button variant="outline" size="lg" className="px-8">
884
- View Components
885
- </Button>
886
- </div>
1008
+ ### Styling Base UI State Attributes
887
1009
 
888
- {/* Feature Cards */}
889
- <div className="mt-16 grid gap-6 sm:grid-cols-3">
890
- <Card className="bg-card/50 backdrop-blur">
891
- <CardContent className="p-6 text-center">
892
- <h3 className="mb-2 text-lg font-semibold">60+ Components</h3>
893
- <p className="text-sm text-muted-foreground">
894
- Comprehensive set of UI components for any project
895
- </p>
896
- </CardContent>
897
- </Card>
1010
+ ```css
1011
+ /* checkbox-demo.module.css */
1012
+ .checkboxRow {
1013
+ display: inline-flex;
1014
+ align-items: center;
1015
+ gap: 0.75rem;
1016
+ }
898
1017
 
899
- <Card className="bg-card/50 backdrop-blur">
900
- <CardContent className="p-6 text-center">
901
- <h3 className="mb-2 text-lg font-semibold">TypeScript First</h3>
902
- <p className="text-sm text-muted-foreground">
903
- Full type safety and excellent developer experience
904
- </p>
905
- </CardContent>
906
- </Card>
1018
+ .checkboxRow :global([data-checked]) {
1019
+ box-shadow: 0 0 0 2px color-mix(in oklab, var(--ac-primary) 25%, transparent);
1020
+ }
907
1021
 
908
- <Card className="bg-card/50 backdrop-blur">
909
- <CardContent className="p-6 text-center">
910
- <h3 className="mb-2 text-lg font-semibold">Accessible</h3>
911
- <p className="text-sm text-muted-foreground">
912
- Built on Radix UI with WAI-ARIA compliance
913
- </p>
914
- </CardContent>
915
- </Card>
916
- </div>
917
- </div>
918
- </div>
919
- );
1022
+ .checkboxRow :global([data-disabled]) {
1023
+ opacity: 0.5;
920
1024
  }
921
1025
  ```
922
1026
 
@@ -927,6 +1031,9 @@ export function LandingPage() {
927
1031
  ### Mobile-Optimized Form
928
1032
 
929
1033
  ```tsx
1034
+ import { Button } from "@arolariu/components/button";
1035
+ import { Input } from "@arolariu/components/input";
1036
+ import { Label } from "@arolariu/components/label";
930
1037
  import {
931
1038
  Sheet,
932
1039
  SheetContent,
@@ -935,21 +1042,22 @@ import {
935
1042
  SheetTitle,
936
1043
  SheetTrigger,
937
1044
  } from "@arolariu/components/sheet";
938
- import { Button } from "@arolariu/components/button";
939
- import { Input } from "@arolariu/components/input";
940
- import { Label } from "@arolariu/components/label";
941
1045
  import { Textarea } from "@arolariu/components/textarea";
942
1046
  import { Plus } from "lucide-react";
1047
+ import styles from "./mobile-add-form.module.css";
943
1048
 
944
1049
  export function MobileAddForm() {
945
1050
  return (
946
1051
  <Sheet>
947
- <SheetTrigger asChild>
948
- <Button className="fixed bottom-4 right-4 h-14 w-14 rounded-full shadow-lg md:hidden">
949
- <Plus className="h-6 w-6" />
950
- </Button>
1052
+ <SheetTrigger
1053
+ render={<button type="button" className={styles.fab} />}
1054
+ >
1055
+ <Plus />
951
1056
  </SheetTrigger>
952
- <SheetContent side="bottom" className="h-[80vh]">
1057
+ <SheetContent
1058
+ side="bottom"
1059
+ className={styles.sheetContent}
1060
+ >
953
1061
  <SheetHeader>
954
1062
  <SheetTitle>Add New Item</SheetTitle>
955
1063
  <SheetDescription>
@@ -957,24 +1065,30 @@ export function MobileAddForm() {
957
1065
  </SheetDescription>
958
1066
  </SheetHeader>
959
1067
 
960
- <div className="mt-6 space-y-4">
961
- <div className="space-y-2">
1068
+ <div className={styles.formStack}>
1069
+ <div className={styles.field}>
962
1070
  <Label htmlFor="title">Title</Label>
963
- <Input id="title" placeholder="Enter title" />
1071
+ <Input
1072
+ id="title"
1073
+ placeholder="Enter title"
1074
+ />
964
1075
  </div>
965
1076
 
966
- <div className="space-y-2">
1077
+ <div className={styles.field}>
967
1078
  <Label htmlFor="description">Description</Label>
968
1079
  <Textarea
969
1080
  id="description"
970
1081
  placeholder="Enter description"
971
- className="min-h-[100px]"
1082
+ className={styles.textarea}
972
1083
  />
973
1084
  </div>
974
1085
 
975
- <div className="flex gap-2 pt-4">
976
- <Button className="flex-1">Save</Button>
977
- <Button variant="outline" className="flex-1">
1086
+ <div className={styles.actionRow}>
1087
+ <Button className={styles.flexButton}>Save</Button>
1088
+ <Button
1089
+ variant="outline"
1090
+ className={styles.flexButton}
1091
+ >
978
1092
  Cancel
979
1093
  </Button>
980
1094
  </div>
@@ -996,7 +1110,7 @@ export function MobileAddForm() {
996
1110
  import { Button } from "@arolariu/components/button";
997
1111
  import { Card } from "@arolariu/components/card";
998
1112
 
999
- // ❌ Avoid barrel imports
1113
+ // ❌ Avoid barrel imports when bundle size matters
1000
1114
  import { Button, Card } from "@arolariu/components";
1001
1115
  ```
1002
1116
 
@@ -1004,8 +1118,11 @@ import { Button, Card } from "@arolariu/components";
1004
1118
 
1005
1119
  ```tsx
1006
1120
  // ✅ Always include proper labels and ARIA attributes
1007
- <Button aria-label="Close dialog" onClick={handleClose}>
1008
- <X className="h-4 w-4" />
1121
+ <Button
1122
+ aria-label="Close dialog"
1123
+ onClick={handleClose}
1124
+ >
1125
+ <X />
1009
1126
  </Button>
1010
1127
 
1011
1128
  // ✅ Use semantic HTML structure
@@ -1019,17 +1136,2535 @@ import { Button, Card } from "@arolariu/components";
1019
1136
 
1020
1137
  ### Responsive Design
1021
1138
 
1022
- ```tsx
1023
- // ✅ Use Tailwind's responsive utilities
1024
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
1025
- {/* components */}
1026
- </div>
1027
-
1028
- // ✅ Hide/show components based on screen size
1029
- <div className="block md:hidden">Mobile only content</div>
1030
- <div className="hidden md:block">Desktop only content</div>
1139
+ ```css
1140
+ /* responsive-layout.module.css */
1141
+ .grid {
1142
+ display: grid;
1143
+ gap: 1rem;
1144
+ grid-template-columns: 1fr;
1145
+ }
1146
+
1147
+ @media (min-width: 48rem) {
1148
+ .grid {
1149
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1150
+ }
1151
+ }
1152
+
1153
+ @media (min-width: 64rem) {
1154
+ .grid {
1155
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1156
+ }
1157
+ }
1031
1158
  ```
1032
1159
 
1160
+ Ready to build something amazing? **[🚀 Start with our Quick Start Guide](./README.md#-quick-start)**
1161
+
1033
1162
  ---
1034
1163
 
1164
+ ## 🎓 Pattern Recipes
1165
+
1166
+ > **Real-world patterns ready to copy, paste, and customize.** These recipes demonstrate common UI patterns using @arolariu/components with best practices for forms, data, modals, and error handling.
1167
+
1168
+ ### Recipe 1: Login Form with Validation
1169
+
1170
+ **Complete login form with zod validation, error handling, and loading states.**
1171
+
1172
+ ```tsx
1173
+ import {zodResolver} from "@hookform/resolvers/zod";
1174
+ import {useForm} from "react-hook-form";
1175
+ import * as z from "zod";
1176
+
1177
+ import {Alert, AlertDescription} from "@arolariu/components/alert";
1178
+ import {Button} from "@arolariu/components/button";
1179
+ import {
1180
+ Card,
1181
+ CardContent,
1182
+ CardDescription,
1183
+ CardFooter,
1184
+ CardHeader,
1185
+ CardTitle,
1186
+ } from "@arolariu/components/card";
1187
+ import {Checkbox} from "@arolariu/components/checkbox";
1188
+ import {
1189
+ Form,
1190
+ FormControl,
1191
+ FormField,
1192
+ FormItem,
1193
+ FormLabel,
1194
+ FormMessage,
1195
+ } from "@arolariu/components/form";
1196
+ import {Input} from "@arolariu/components/input";
1197
+ import {toast} from "@arolariu/components/sonner";
1198
+ import styles from "./login-form.module.css";
1199
+
1200
+ // Define validation schema
1201
+ const loginSchema = z.object({
1202
+ email: z.string().email("Please enter a valid email address"),
1203
+ password: z.string().min(8, "Password must be at least 8 characters"),
1204
+ rememberMe: z.boolean().default(false),
1205
+ });
1206
+
1207
+ type LoginFormValues = z.infer<typeof loginSchema>;
1208
+
1209
+ export function LoginForm() {
1210
+ const form = useForm<LoginFormValues>({
1211
+ resolver: zodResolver(loginSchema),
1212
+ defaultValues: {
1213
+ email: "",
1214
+ password: "",
1215
+ rememberMe: false,
1216
+ },
1217
+ });
1218
+
1219
+ async function onSubmit(values: LoginFormValues) {
1220
+ try {
1221
+ // Simulate API call
1222
+ await new Promise((resolve) => setTimeout(resolve, 1500));
1223
+
1224
+ // Check credentials (mock)
1225
+ if (values.email === "demo@example.com" && values.password === "password123") {
1226
+ toast.success("Login successful! Redirecting...");
1227
+ // Redirect to dashboard
1228
+ window.location.href = "/dashboard";
1229
+ } else {
1230
+ throw new Error("Invalid credentials");
1231
+ }
1232
+ } catch (error) {
1233
+ toast.error("Login failed. Please check your credentials and try again.");
1234
+ }
1235
+ }
1236
+
1237
+ return (
1238
+ <div className={styles.page}>
1239
+ <Card className={styles.card}>
1240
+ <CardHeader className={styles.header}>
1241
+ <CardTitle>Welcome Back</CardTitle>
1242
+ <CardDescription>
1243
+ Sign in to your account to continue
1244
+ </CardDescription>
1245
+ </CardHeader>
1246
+
1247
+ <Form {...form}>
1248
+ <form onSubmit={form.handleSubmit(onSubmit)}>
1249
+ <CardContent className={styles.content}>
1250
+ {form.formState.errors.root ? (
1251
+ <Alert variant="destructive">
1252
+ <AlertDescription>
1253
+ {form.formState.errors.root.message}
1254
+ </AlertDescription>
1255
+ </Alert>
1256
+ ) : null}
1257
+
1258
+ <FormField
1259
+ control={form.control}
1260
+ name="email"
1261
+ render={({field}) => (
1262
+ <FormItem>
1263
+ <FormLabel>Email</FormLabel>
1264
+ <FormControl>
1265
+ <Input
1266
+ type="email"
1267
+ placeholder="you@example.com"
1268
+ autoComplete="email"
1269
+ {...field}
1270
+ />
1271
+ </FormControl>
1272
+ <FormMessage />
1273
+ </FormItem>
1274
+ )}
1275
+ />
1276
+
1277
+ <FormField
1278
+ control={form.control}
1279
+ name="password"
1280
+ render={({field}) => (
1281
+ <FormItem>
1282
+ <FormLabel>Password</FormLabel>
1283
+ <FormControl>
1284
+ <Input
1285
+ type="password"
1286
+ placeholder="••••••••"
1287
+ autoComplete="current-password"
1288
+ {...field}
1289
+ />
1290
+ </FormControl>
1291
+ <FormMessage />
1292
+ </FormItem>
1293
+ )}
1294
+ />
1295
+
1296
+ <FormField
1297
+ control={form.control}
1298
+ name="rememberMe"
1299
+ render={({field}) => (
1300
+ <FormItem className={styles.checkboxItem}>
1301
+ <FormControl>
1302
+ <Checkbox
1303
+ checked={field.value}
1304
+ onCheckedChange={field.onChange}
1305
+ />
1306
+ </FormControl>
1307
+ <FormLabel className={styles.checkboxLabel}>
1308
+ Remember me for 30 days
1309
+ </FormLabel>
1310
+ </FormItem>
1311
+ )}
1312
+ />
1313
+ </CardContent>
1314
+
1315
+ <CardFooter className={styles.footer}>
1316
+ <Button
1317
+ type="submit"
1318
+ className={styles.submitButton}
1319
+ disabled={form.formState.isSubmitting}
1320
+ >
1321
+ {form.formState.isSubmitting ? "Signing in..." : "Sign In"}
1322
+ </Button>
1323
+
1324
+ <div className={styles.links}>
1325
+ <a href="/forgot-password" className={styles.link}>
1326
+ Forgot password?
1327
+ </a>
1328
+ <a href="/signup" className={styles.link}>
1329
+ Create account
1330
+ </a>
1331
+ </div>
1332
+ </CardFooter>
1333
+ </form>
1334
+ </Form>
1335
+ </Card>
1336
+ </div>
1337
+ );
1338
+ }
1339
+ ```
1340
+
1341
+ ```css
1342
+ /* login-form.module.css */
1343
+ .page {
1344
+ display: flex;
1345
+ align-items: center;
1346
+ justify-content: center;
1347
+ min-height: 100vh;
1348
+ padding: 1rem;
1349
+ background-color: var(--ac-muted);
1350
+ }
1351
+
1352
+ .card {
1353
+ width: min(28rem, 100%);
1354
+ }
1355
+
1356
+ .header {
1357
+ text-align: center;
1358
+ }
1359
+
1360
+ .content {
1361
+ display: grid;
1362
+ gap: 1rem;
1363
+ }
1364
+
1365
+ .checkboxItem {
1366
+ display: flex;
1367
+ flex-direction: row;
1368
+ align-items: center;
1369
+ gap: 0.5rem;
1370
+ }
1371
+
1372
+ .checkboxLabel {
1373
+ margin-top: 0;
1374
+ font-weight: 400;
1375
+ }
1376
+
1377
+ .footer {
1378
+ display: flex;
1379
+ flex-direction: column;
1380
+ gap: 1rem;
1381
+ }
1382
+
1383
+ .submitButton {
1384
+ width: 100%;
1385
+ }
1386
+
1387
+ .links {
1388
+ display: flex;
1389
+ justify-content: space-between;
1390
+ font-size: 0.875rem;
1391
+ }
1392
+
1393
+ .link {
1394
+ color: var(--ac-primary);
1395
+ text-decoration: none;
1396
+ }
1397
+
1398
+ .link:hover {
1399
+ text-decoration: underline;
1400
+ }
1401
+ ```
1402
+
1403
+ ---
1404
+
1405
+ ### Recipe 2: Data Table with Sorting (TanStack Table)
1406
+
1407
+ **Sortable, filterable data table with row actions and pagination.**
1408
+
1409
+ ```tsx
1410
+ import {
1411
+ createColumnHelper,
1412
+ flexRender,
1413
+ getCoreRowModel,
1414
+ getPaginationRowModel,
1415
+ getSortedRowModel,
1416
+ useReactTable,
1417
+ type SortingState,
1418
+ } from "@tanstack/react-table";
1419
+ import {ArrowUpDown, ChevronLeft, ChevronRight, MoreHorizontal} from "lucide-react";
1420
+ import {useState} from "react";
1421
+
1422
+ import {Badge} from "@arolariu/components/badge";
1423
+ import {Button} from "@arolariu/components/button";
1424
+ import {
1425
+ DropdownMenu,
1426
+ DropdownMenuContent,
1427
+ DropdownMenuItem,
1428
+ DropdownMenuLabel,
1429
+ DropdownMenuSeparator,
1430
+ DropdownMenuTrigger,
1431
+ } from "@arolariu/components/dropdown-menu";
1432
+ import {Input} from "@arolariu/components/input";
1433
+ import {
1434
+ Table,
1435
+ TableBody,
1436
+ TableCell,
1437
+ TableHead,
1438
+ TableHeader,
1439
+ TableRow,
1440
+ } from "@arolariu/components/table";
1441
+ import {toast} from "@arolariu/components/sonner";
1442
+ import styles from "./data-table.module.css";
1443
+
1444
+ interface User {
1445
+ id: string;
1446
+ name: string;
1447
+ email: string;
1448
+ role: "admin" | "user" | "guest";
1449
+ status: "active" | "inactive";
1450
+ createdAt: Date;
1451
+ }
1452
+
1453
+ const data: User[] = [
1454
+ {
1455
+ id: "1",
1456
+ name: "John Doe",
1457
+ email: "john@example.com",
1458
+ role: "admin",
1459
+ status: "active",
1460
+ createdAt: new Date("2024-01-15"),
1461
+ },
1462
+ {
1463
+ id: "2",
1464
+ name: "Jane Smith",
1465
+ email: "jane@example.com",
1466
+ role: "user",
1467
+ status: "active",
1468
+ createdAt: new Date("2024-02-20"),
1469
+ },
1470
+ {
1471
+ id: "3",
1472
+ name: "Bob Johnson",
1473
+ email: "bob@example.com",
1474
+ role: "guest",
1475
+ status: "inactive",
1476
+ createdAt: new Date("2024-03-10"),
1477
+ },
1478
+ ];
1479
+
1480
+ const columnHelper = createColumnHelper<User>();
1481
+
1482
+ export function DataTableWithSorting() {
1483
+ const [sorting, setSorting] = useState<SortingState>([]);
1484
+ const [globalFilter, setGlobalFilter] = useState("");
1485
+
1486
+ const columns = [
1487
+ columnHelper.accessor("name", {
1488
+ header: ({column}) => (
1489
+ <button
1490
+ type="button"
1491
+ className={styles.sortButton}
1492
+ onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
1493
+ >
1494
+ Name
1495
+ <ArrowUpDown className={styles.sortIcon} />
1496
+ </button>
1497
+ ),
1498
+ cell: (info) => <span className={styles.emphasisText}>{info.getValue()}</span>,
1499
+ }),
1500
+ columnHelper.accessor("email", {
1501
+ header: "Email",
1502
+ }),
1503
+ columnHelper.accessor("role", {
1504
+ header: "Role",
1505
+ cell: (info) => {
1506
+ const role = info.getValue();
1507
+ return (
1508
+ <Badge variant={role === "admin" ? "default" : "secondary"}>
1509
+ {role}
1510
+ </Badge>
1511
+ );
1512
+ },
1513
+ }),
1514
+ columnHelper.accessor("status", {
1515
+ header: "Status",
1516
+ cell: (info) => {
1517
+ const status = info.getValue();
1518
+ return (
1519
+ <Badge variant={status === "active" ? "default" : "outline"}>
1520
+ {status}
1521
+ </Badge>
1522
+ );
1523
+ },
1524
+ }),
1525
+ columnHelper.accessor("createdAt", {
1526
+ header: ({column}) => (
1527
+ <button
1528
+ type="button"
1529
+ className={styles.sortButton}
1530
+ onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
1531
+ >
1532
+ Created At
1533
+ <ArrowUpDown className={styles.sortIcon} />
1534
+ </button>
1535
+ ),
1536
+ cell: (info) => info.getValue().toLocaleDateString(),
1537
+ }),
1538
+ columnHelper.display({
1539
+ id: "actions",
1540
+ cell: ({row}) => (
1541
+ <DropdownMenu>
1542
+ <DropdownMenuTrigger render={<button type="button" className={styles.iconButton} />}>
1543
+ <MoreHorizontal />
1544
+ </DropdownMenuTrigger>
1545
+ <DropdownMenuContent align="end">
1546
+ <DropdownMenuLabel>Actions</DropdownMenuLabel>
1547
+ <DropdownMenuItem
1548
+ onClick={() => {
1549
+ navigator.clipboard.writeText(row.original.id);
1550
+ toast.success("User ID copied to clipboard");
1551
+ }}
1552
+ >
1553
+ Copy ID
1554
+ </DropdownMenuItem>
1555
+ <DropdownMenuSeparator />
1556
+ <DropdownMenuItem onClick={() => toast.info(`Viewing user: ${row.original.name}`)}>
1557
+ View details
1558
+ </DropdownMenuItem>
1559
+ <DropdownMenuItem onClick={() => toast.info(`Editing user: ${row.original.name}`)}>
1560
+ Edit user
1561
+ </DropdownMenuItem>
1562
+ </DropdownMenuContent>
1563
+ </DropdownMenu>
1564
+ ),
1565
+ }),
1566
+ ];
1567
+
1568
+ const table = useReactTable({
1569
+ data,
1570
+ columns,
1571
+ state: {
1572
+ sorting,
1573
+ globalFilter,
1574
+ },
1575
+ onSortingChange: setSorting,
1576
+ onGlobalFilterChange: setGlobalFilter,
1577
+ getCoreRowModel: getCoreRowModel(),
1578
+ getSortedRowModel: getSortedRowModel(),
1579
+ getPaginationRowModel: getPaginationRowModel(),
1580
+ initialState: {
1581
+ pagination: {
1582
+ pageSize: 5,
1583
+ },
1584
+ },
1585
+ });
1586
+
1587
+ return (
1588
+ <div className={styles.container}>
1589
+ <div className={styles.toolbar}>
1590
+ <Input
1591
+ placeholder="Search users..."
1592
+ value={globalFilter}
1593
+ onChange={(e) => setGlobalFilter(e.target.value)}
1594
+ className={styles.searchInput}
1595
+ />
1596
+ </div>
1597
+
1598
+ <div className={styles.tableWrapper}>
1599
+ <Table>
1600
+ <TableHeader>
1601
+ {table.getHeaderGroups().map((headerGroup) => (
1602
+ <TableRow key={headerGroup.id}>
1603
+ {headerGroup.headers.map((header) => (
1604
+ <TableHead key={header.id}>
1605
+ {header.isPlaceholder
1606
+ ? null
1607
+ : flexRender(header.column.columnDef.header, header.getContext())}
1608
+ </TableHead>
1609
+ ))}
1610
+ </TableRow>
1611
+ ))}
1612
+ </TableHeader>
1613
+ <TableBody>
1614
+ {table.getRowModel().rows.length > 0 ? (
1615
+ table.getRowModel().rows.map((row) => (
1616
+ <TableRow key={row.id}>
1617
+ {row.getVisibleCells().map((cell) => (
1618
+ <TableCell key={cell.id}>
1619
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
1620
+ </TableCell>
1621
+ ))}
1622
+ </TableRow>
1623
+ ))
1624
+ ) : (
1625
+ <TableRow>
1626
+ <TableCell colSpan={columns.length} className={styles.emptyCell}>
1627
+ No results found.
1628
+ </TableCell>
1629
+ </TableRow>
1630
+ )}
1631
+ </TableBody>
1632
+ </Table>
1633
+ </div>
1634
+
1635
+ <div className={styles.pagination}>
1636
+ <div className={styles.paginationInfo}>
1637
+ Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
1638
+ </div>
1639
+ <div className={styles.paginationButtons}>
1640
+ <Button
1641
+ variant="outline"
1642
+ size="sm"
1643
+ onClick={() => table.previousPage()}
1644
+ disabled={!table.getCanPreviousPage()}
1645
+ >
1646
+ <ChevronLeft />
1647
+ Previous
1648
+ </Button>
1649
+ <Button
1650
+ variant="outline"
1651
+ size="sm"
1652
+ onClick={() => table.nextPage()}
1653
+ disabled={!table.getCanNextPage()}
1654
+ >
1655
+ Next
1656
+ <ChevronRight />
1657
+ </Button>
1658
+ </div>
1659
+ </div>
1660
+ </div>
1661
+ );
1662
+ }
1663
+ ```
1664
+
1665
+ ```css
1666
+ /* data-table.module.css */
1667
+ .container {
1668
+ display: grid;
1669
+ gap: 1rem;
1670
+ }
1671
+
1672
+ .toolbar {
1673
+ display: flex;
1674
+ gap: 0.5rem;
1675
+ }
1676
+
1677
+ .searchInput {
1678
+ max-width: 20rem;
1679
+ }
1680
+
1681
+ .tableWrapper {
1682
+ border: 1px solid var(--ac-border);
1683
+ border-radius: var(--ac-radius-md);
1684
+ overflow: hidden;
1685
+ }
1686
+
1687
+ .sortButton {
1688
+ display: inline-flex;
1689
+ align-items: center;
1690
+ gap: 0.5rem;
1691
+ font-weight: 500;
1692
+ background: none;
1693
+ border: none;
1694
+ cursor: pointer;
1695
+ }
1696
+
1697
+ .sortIcon {
1698
+ width: 1rem;
1699
+ height: 1rem;
1700
+ opacity: 0.5;
1701
+ }
1702
+
1703
+ .emphasisText {
1704
+ font-weight: 500;
1705
+ }
1706
+
1707
+ .iconButton {
1708
+ display: inline-flex;
1709
+ align-items: center;
1710
+ justify-content: center;
1711
+ width: 2rem;
1712
+ height: 2rem;
1713
+ border: none;
1714
+ background: none;
1715
+ border-radius: var(--ac-radius-sm);
1716
+ cursor: pointer;
1717
+ }
1718
+
1719
+ .iconButton:hover {
1720
+ background-color: var(--ac-accent);
1721
+ }
1722
+
1723
+ .emptyCell {
1724
+ text-align: center;
1725
+ padding: 2rem;
1726
+ color: var(--ac-muted-foreground);
1727
+ }
1728
+
1729
+ .pagination {
1730
+ display: flex;
1731
+ align-items: center;
1732
+ justify-content: space-between;
1733
+ }
1734
+
1735
+ .paginationInfo {
1736
+ font-size: 0.875rem;
1737
+ color: var(--ac-muted-foreground);
1738
+ }
1739
+
1740
+ .paginationButtons {
1741
+ display: flex;
1742
+ gap: 0.5rem;
1743
+ }
1744
+ ```
1745
+
1746
+ ---
1747
+
1748
+ ### Recipe 3: Modal Form (Dialog + Form + Validation)
1749
+
1750
+ **Dialog with form validation and async submission.**
1751
+
1752
+ ```tsx
1753
+ import {zodResolver} from "@hookform/resolvers/zod";
1754
+ import {Plus} from "lucide-react";
1755
+ import {useState} from "react";
1756
+ import {useForm} from "react-hook-form";
1757
+ import * as z from "zod";
1758
+
1759
+ import {Button} from "@arolariu/components/button";
1760
+ import {
1761
+ Dialog,
1762
+ DialogContent,
1763
+ DialogDescription,
1764
+ DialogFooter,
1765
+ DialogHeader,
1766
+ DialogTitle,
1767
+ DialogTrigger,
1768
+ } from "@arolariu/components/dialog";
1769
+ import {
1770
+ Form,
1771
+ FormControl,
1772
+ FormDescription,
1773
+ FormField,
1774
+ FormItem,
1775
+ FormLabel,
1776
+ FormMessage,
1777
+ } from "@arolariu/components/form";
1778
+ import {Input} from "@arolariu/components/input";
1779
+ import {
1780
+ Select,
1781
+ SelectContent,
1782
+ SelectItem,
1783
+ SelectTrigger,
1784
+ SelectValue,
1785
+ } from "@arolariu/components/select";
1786
+ import {Textarea} from "@arolariu/components/textarea";
1787
+ import {toast} from "@arolariu/components/sonner";
1788
+ import styles from "./modal-form.module.css";
1789
+
1790
+ const projectSchema = z.object({
1791
+ name: z.string().min(3, "Project name must be at least 3 characters"),
1792
+ description: z.string().max(500, "Description must be less than 500 characters").optional(),
1793
+ category: z.enum(["web", "mobile", "desktop", "other"], {
1794
+ required_error: "Please select a category",
1795
+ }),
1796
+ budget: z.string().regex(/^\d+$/, "Budget must be a valid number"),
1797
+ });
1798
+
1799
+ type ProjectFormValues = z.infer<typeof projectSchema>;
1800
+
1801
+ export function CreateProjectModal() {
1802
+ const [open, setOpen] = useState(false);
1803
+
1804
+ const form = useForm<ProjectFormValues>({
1805
+ resolver: zodResolver(projectSchema),
1806
+ defaultValues: {
1807
+ name: "",
1808
+ description: "",
1809
+ category: undefined,
1810
+ budget: "",
1811
+ },
1812
+ });
1813
+
1814
+ async function onSubmit(values: ProjectFormValues) {
1815
+ try {
1816
+ // Simulate API call
1817
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1818
+
1819
+ console.log("Project created:", values);
1820
+ toast.success("Project created successfully!");
1821
+
1822
+ // Close modal and reset form
1823
+ setOpen(false);
1824
+ form.reset();
1825
+ } catch (error) {
1826
+ toast.error("Failed to create project. Please try again.");
1827
+ }
1828
+ }
1829
+
1830
+ return (
1831
+ <Dialog open={open} onOpenChange={setOpen}>
1832
+ <DialogTrigger render={<Button />}>
1833
+ <Plus />
1834
+ Create Project
1835
+ </DialogTrigger>
1836
+
1837
+ <DialogContent className={styles.content}>
1838
+ <DialogHeader>
1839
+ <DialogTitle>Create New Project</DialogTitle>
1840
+ <DialogDescription>
1841
+ Fill in the details below to create a new project. Click save when you're done.
1842
+ </DialogDescription>
1843
+ </DialogHeader>
1844
+
1845
+ <Form {...form}>
1846
+ <form onSubmit={form.handleSubmit(onSubmit)} className={styles.form}>
1847
+ <FormField
1848
+ control={form.control}
1849
+ name="name"
1850
+ render={({field}) => (
1851
+ <FormItem>
1852
+ <FormLabel>Project Name</FormLabel>
1853
+ <FormControl>
1854
+ <Input placeholder="My Awesome Project" {...field} />
1855
+ </FormControl>
1856
+ <FormDescription>
1857
+ Choose a unique name for your project.
1858
+ </FormDescription>
1859
+ <FormMessage />
1860
+ </FormItem>
1861
+ )}
1862
+ />
1863
+
1864
+ <FormField
1865
+ control={form.control}
1866
+ name="category"
1867
+ render={({field}) => (
1868
+ <FormItem>
1869
+ <FormLabel>Category</FormLabel>
1870
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
1871
+ <FormControl>
1872
+ <SelectTrigger>
1873
+ <SelectValue placeholder="Select a category" />
1874
+ </SelectTrigger>
1875
+ </FormControl>
1876
+ <SelectContent>
1877
+ <SelectItem value="web">Web Application</SelectItem>
1878
+ <SelectItem value="mobile">Mobile App</SelectItem>
1879
+ <SelectItem value="desktop">Desktop Application</SelectItem>
1880
+ <SelectItem value="other">Other</SelectItem>
1881
+ </SelectContent>
1882
+ </Select>
1883
+ <FormMessage />
1884
+ </FormItem>
1885
+ )}
1886
+ />
1887
+
1888
+ <FormField
1889
+ control={form.control}
1890
+ name="budget"
1891
+ render={({field}) => (
1892
+ <FormItem>
1893
+ <FormLabel>Budget (USD)</FormLabel>
1894
+ <FormControl>
1895
+ <Input type="text" placeholder="10000" {...field} />
1896
+ </FormControl>
1897
+ <FormMessage />
1898
+ </FormItem>
1899
+ )}
1900
+ />
1901
+
1902
+ <FormField
1903
+ control={form.control}
1904
+ name="description"
1905
+ render={({field}) => (
1906
+ <FormItem>
1907
+ <FormLabel>Description</FormLabel>
1908
+ <FormControl>
1909
+ <Textarea
1910
+ placeholder="Describe your project..."
1911
+ className={styles.textarea}
1912
+ {...field}
1913
+ />
1914
+ </FormControl>
1915
+ <FormMessage />
1916
+ </FormItem>
1917
+ )}
1918
+ />
1919
+
1920
+ <DialogFooter>
1921
+ <Button
1922
+ type="button"
1923
+ variant="outline"
1924
+ onClick={() => setOpen(false)}
1925
+ >
1926
+ Cancel
1927
+ </Button>
1928
+ <Button type="submit" disabled={form.formState.isSubmitting}>
1929
+ {form.formState.isSubmitting ? "Creating..." : "Create Project"}
1930
+ </Button>
1931
+ </DialogFooter>
1932
+ </form>
1933
+ </Form>
1934
+ </DialogContent>
1935
+ </Dialog>
1936
+ );
1937
+ }
1938
+ ```
1939
+
1940
+ ```css
1941
+ /* modal-form.module.css */
1942
+ .content {
1943
+ max-width: 32rem;
1944
+ }
1945
+
1946
+ .form {
1947
+ display: grid;
1948
+ gap: 1rem;
1949
+ padding-block: 1rem;
1950
+ }
1951
+
1952
+ .textarea {
1953
+ min-height: 6rem;
1954
+ resize: vertical;
1955
+ }
1956
+ ```
1957
+
1958
+ ---
1959
+
1960
+ ### Recipe 4: Toast Notifications (Sonner)
1961
+
1962
+ **Comprehensive toast notification patterns for all use cases.**
1963
+
1964
+ ```tsx
1965
+ import {CheckCircle2, Info, Loader2, XCircle} from "lucide-react";
1966
+
1967
+ import {Button} from "@arolariu/components/button";
1968
+ import {Card, CardContent, CardHeader, CardTitle} from "@arolariu/components/card";
1969
+ import {toast, Toaster} from "@arolariu/components/sonner";
1970
+ import styles from "./toast-demo.module.css";
1971
+
1972
+ export function ToastDemo() {
1973
+ // Basic toasts
1974
+ const showSuccess = () => {
1975
+ toast.success("Operation completed successfully!");
1976
+ };
1977
+
1978
+ const showError = () => {
1979
+ toast.error("Something went wrong. Please try again.");
1980
+ };
1981
+
1982
+ const showInfo = () => {
1983
+ toast.info("This is an informational message.");
1984
+ };
1985
+
1986
+ const showWarning = () => {
1987
+ toast.warning("Warning: This action cannot be undone!");
1988
+ };
1989
+
1990
+ // Toast with action
1991
+ const showWithAction = () => {
1992
+ toast.success("File uploaded successfully", {
1993
+ action: {
1994
+ label: "View",
1995
+ onClick: () => console.log("View clicked"),
1996
+ },
1997
+ });
1998
+ };
1999
+
2000
+ // Toast with description
2001
+ const showWithDescription = () => {
2002
+ toast.success("Project created", {
2003
+ description: "Your project has been created and is now live.",
2004
+ });
2005
+ };
2006
+
2007
+ // Promise toast (loading → success/error)
2008
+ const showPromiseToast = () => {
2009
+ const uploadPromise = new Promise((resolve, reject) => {
2010
+ setTimeout(() => {
2011
+ Math.random() > 0.5 ? resolve({name: "document.pdf"}) : reject(new Error("Upload failed"));
2012
+ }, 2000);
2013
+ });
2014
+
2015
+ toast.promise(uploadPromise, {
2016
+ loading: "Uploading file...",
2017
+ success: (data: {name: string}) => `${data.name} uploaded successfully!`,
2018
+ error: "Failed to upload file.",
2019
+ });
2020
+ };
2021
+
2022
+ // Custom styled toast
2023
+ const showCustomToast = () => {
2024
+ toast.custom(
2025
+ <div className={styles.customToast}>
2026
+ <CheckCircle2 className={styles.customIcon} />
2027
+ <div className={styles.customContent}>
2028
+ <div className={styles.customTitle}>Custom Toast</div>
2029
+ <div className={styles.customDescription}>
2030
+ This is a fully customized toast notification.
2031
+ </div>
2032
+ </div>
2033
+ </div>
2034
+ );
2035
+ };
2036
+
2037
+ // Loading toast (manual control)
2038
+ const showLoadingToast = () => {
2039
+ const toastId = toast.loading("Processing your request...");
2040
+
2041
+ setTimeout(() => {
2042
+ toast.success("Request processed!", {id: toastId});
2043
+ }, 3000);
2044
+ };
2045
+
2046
+ return (
2047
+ <>
2048
+ <Toaster position="top-right" richColors />
2049
+
2050
+ <div className={styles.container}>
2051
+ <Card>
2052
+ <CardHeader>
2053
+ <CardTitle>Toast Notification Examples</CardTitle>
2054
+ </CardHeader>
2055
+ <CardContent className={styles.grid}>
2056
+ <div className={styles.section}>
2057
+ <h3 className={styles.sectionTitle}>Basic Toasts</h3>
2058
+ <div className={styles.buttonGroup}>
2059
+ <Button onClick={showSuccess} variant="default">
2060
+ <CheckCircle2 />
2061
+ Success Toast
2062
+ </Button>
2063
+ <Button onClick={showError} variant="destructive">
2064
+ <XCircle />
2065
+ Error Toast
2066
+ </Button>
2067
+ <Button onClick={showInfo} variant="outline">
2068
+ <Info />
2069
+ Info Toast
2070
+ </Button>
2071
+ <Button onClick={showWarning} variant="outline">
2072
+ Warning Toast
2073
+ </Button>
2074
+ </div>
2075
+ </div>
2076
+
2077
+ <div className={styles.section}>
2078
+ <h3 className={styles.sectionTitle}>Advanced Toasts</h3>
2079
+ <div className={styles.buttonGroup}>
2080
+ <Button onClick={showWithAction} variant="secondary">
2081
+ Toast with Action
2082
+ </Button>
2083
+ <Button onClick={showWithDescription} variant="secondary">
2084
+ Toast with Description
2085
+ </Button>
2086
+ <Button onClick={showPromiseToast} variant="secondary">
2087
+ <Loader2 />
2088
+ Promise Toast
2089
+ </Button>
2090
+ <Button onClick={showLoadingToast} variant="secondary">
2091
+ Loading Toast
2092
+ </Button>
2093
+ </div>
2094
+ </div>
2095
+
2096
+ <div className={styles.section}>
2097
+ <h3 className={styles.sectionTitle}>Custom Toast</h3>
2098
+ <Button onClick={showCustomToast} variant="outline">
2099
+ Show Custom Toast
2100
+ </Button>
2101
+ </div>
2102
+ </CardContent>
2103
+ </Card>
2104
+ </div>
2105
+ </>
2106
+ );
2107
+ }
2108
+ ```
2109
+
2110
+ ```css
2111
+ /* toast-demo.module.css */
2112
+ .container {
2113
+ display: flex;
2114
+ align-items: center;
2115
+ justify-content: center;
2116
+ min-height: 100vh;
2117
+ padding: 1rem;
2118
+ }
2119
+
2120
+ .grid {
2121
+ display: grid;
2122
+ gap: 2rem;
2123
+ }
2124
+
2125
+ .section {
2126
+ display: grid;
2127
+ gap: 1rem;
2128
+ }
2129
+
2130
+ .sectionTitle {
2131
+ font-size: 1rem;
2132
+ font-weight: 600;
2133
+ }
2134
+
2135
+ .buttonGroup {
2136
+ display: grid;
2137
+ gap: 0.5rem;
2138
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
2139
+ }
2140
+
2141
+ .customToast {
2142
+ display: flex;
2143
+ align-items: flex-start;
2144
+ gap: 0.75rem;
2145
+ padding: 1rem;
2146
+ background-color: var(--ac-card);
2147
+ border: 1px solid var(--ac-border);
2148
+ border-radius: var(--ac-radius-md);
2149
+ box-shadow: var(--ac-shadow-lg);
2150
+ }
2151
+
2152
+ .customIcon {
2153
+ flex-shrink: 0;
2154
+ width: 1.25rem;
2155
+ height: 1.25rem;
2156
+ color: var(--ac-primary);
2157
+ }
2158
+
2159
+ .customContent {
2160
+ display: grid;
2161
+ gap: 0.25rem;
2162
+ }
2163
+
2164
+ .customTitle {
2165
+ font-weight: 600;
2166
+ }
2167
+
2168
+ .customDescription {
2169
+ font-size: 0.875rem;
2170
+ color: var(--ac-muted-foreground);
2171
+ }
2172
+ ```
2173
+
2174
+ ---
2175
+
2176
+ ### Recipe 5: Sidebar Navigation (with Keyboard Support)
2177
+
2178
+ **Responsive sidebar with keyboard navigation and active states.**
2179
+
2180
+ ```tsx
2181
+ import {
2182
+ ChevronDown,
2183
+ FileText,
2184
+ Home,
2185
+ Settings,
2186
+ Users,
2187
+ } from "lucide-react";
2188
+ import {useState} from "react";
2189
+
2190
+ import {
2191
+ Collapsible,
2192
+ CollapsibleContent,
2193
+ CollapsibleTrigger,
2194
+ } from "@arolariu/components/collapsible";
2195
+ import {
2196
+ Sidebar,
2197
+ SidebarContent,
2198
+ SidebarGroup,
2199
+ SidebarGroupContent,
2200
+ SidebarGroupLabel,
2201
+ SidebarMenu,
2202
+ SidebarMenuButton,
2203
+ SidebarMenuItem,
2204
+ SidebarMenuSub,
2205
+ SidebarMenuSubButton,
2206
+ SidebarMenuSubItem,
2207
+ SidebarProvider,
2208
+ SidebarTrigger,
2209
+ } from "@arolariu/components/sidebar";
2210
+ import styles from "./app-sidebar.module.css";
2211
+
2212
+ const menuItems = [
2213
+ {
2214
+ title: "Dashboard",
2215
+ icon: Home,
2216
+ url: "/dashboard",
2217
+ },
2218
+ {
2219
+ title: "Team",
2220
+ icon: Users,
2221
+ url: "/team",
2222
+ submenu: [
2223
+ {title: "Members", url: "/team/members"},
2224
+ {title: "Roles", url: "/team/roles"},
2225
+ {title: "Invitations", url: "/team/invitations"},
2226
+ ],
2227
+ },
2228
+ {
2229
+ title: "Projects",
2230
+ icon: FileText,
2231
+ url: "/projects",
2232
+ submenu: [
2233
+ {title: "Active", url: "/projects/active"},
2234
+ {title: "Archived", url: "/projects/archived"},
2235
+ {title: "Templates", url: "/projects/templates"},
2236
+ ],
2237
+ },
2238
+ {
2239
+ title: "Settings",
2240
+ icon: Settings,
2241
+ url: "/settings",
2242
+ },
2243
+ ];
2244
+
2245
+ export function AppSidebar() {
2246
+ const [activeItem, setActiveItem] = useState("/dashboard");
2247
+
2248
+ return (
2249
+ <SidebarProvider>
2250
+ <div className={styles.layout}>
2251
+ <Sidebar>
2252
+ <SidebarContent>
2253
+ <SidebarGroup>
2254
+ <SidebarGroupLabel>Application</SidebarGroupLabel>
2255
+ <SidebarGroupContent>
2256
+ <SidebarMenu>
2257
+ {menuItems.map((item) => {
2258
+ const isActive = activeItem === item.url || activeItem.startsWith(item.url + "/");
2259
+
2260
+ if (item.submenu) {
2261
+ return (
2262
+ <Collapsible key={item.title} defaultOpen={isActive}>
2263
+ <SidebarMenuItem>
2264
+ <CollapsibleTrigger asChild>
2265
+ <SidebarMenuButton isActive={isActive}>
2266
+ <item.icon />
2267
+ <span>{item.title}</span>
2268
+ <ChevronDown className={styles.chevron} />
2269
+ </SidebarMenuButton>
2270
+ </CollapsibleTrigger>
2271
+ <CollapsibleContent>
2272
+ <SidebarMenuSub>
2273
+ {item.submenu.map((subitem) => (
2274
+ <SidebarMenuSubItem key={subitem.title}>
2275
+ <SidebarMenuSubButton
2276
+ isActive={activeItem === subitem.url}
2277
+ onClick={() => setActiveItem(subitem.url)}
2278
+ >
2279
+ {subitem.title}
2280
+ </SidebarMenuSubButton>
2281
+ </SidebarMenuSubItem>
2282
+ ))}
2283
+ </SidebarMenuSub>
2284
+ </CollapsibleContent>
2285
+ </SidebarMenuItem>
2286
+ </Collapsible>
2287
+ );
2288
+ }
2289
+
2290
+ return (
2291
+ <SidebarMenuItem key={item.title}>
2292
+ <SidebarMenuButton
2293
+ isActive={isActive}
2294
+ onClick={() => setActiveItem(item.url)}
2295
+ >
2296
+ <item.icon />
2297
+ <span>{item.title}</span>
2298
+ </SidebarMenuButton>
2299
+ </SidebarMenuItem>
2300
+ );
2301
+ })}
2302
+ </SidebarMenu>
2303
+ </SidebarGroupContent>
2304
+ </SidebarGroup>
2305
+ </SidebarContent>
2306
+ </Sidebar>
2307
+
2308
+ <main className={styles.main}>
2309
+ <div className={styles.header}>
2310
+ <SidebarTrigger />
2311
+ <h1 className={styles.title}>Welcome to Dashboard</h1>
2312
+ </div>
2313
+
2314
+ <div className={styles.content}>
2315
+ <p>Current route: {activeItem}</p>
2316
+ </div>
2317
+ </main>
2318
+ </div>
2319
+ </SidebarProvider>
2320
+ );
2321
+ }
2322
+ ```
2323
+
2324
+ ```css
2325
+ /* app-sidebar.module.css */
2326
+ .layout {
2327
+ display: flex;
2328
+ min-height: 100vh;
2329
+ }
2330
+
2331
+ .main {
2332
+ flex: 1;
2333
+ display: grid;
2334
+ grid-template-rows: auto 1fr;
2335
+ }
2336
+
2337
+ .header {
2338
+ display: flex;
2339
+ align-items: center;
2340
+ gap: 1rem;
2341
+ padding: 1rem;
2342
+ border-bottom: 1px solid var(--ac-border);
2343
+ }
2344
+
2345
+ .title {
2346
+ font-size: 1.5rem;
2347
+ font-weight: 600;
2348
+ }
2349
+
2350
+ .content {
2351
+ padding: 2rem;
2352
+ }
2353
+
2354
+ .chevron {
2355
+ margin-left: auto;
2356
+ transition: transform 150ms;
2357
+ }
2358
+
2359
+ :global([data-state="open"]) .chevron {
2360
+ transform: rotate(180deg);
2361
+ }
2362
+ ```
2363
+
2364
+ ---
2365
+
2366
+ ### Recipe 6: Accessible Dropdown Menu (with Keyboard Nav)
2367
+
2368
+ **Fully accessible dropdown menu with keyboard shortcuts.**
2369
+
2370
+ ```tsx
2371
+ import {
2372
+ Copy,
2373
+ Download,
2374
+ Edit,
2375
+ LogOut,
2376
+ MoreVertical,
2377
+ Share2,
2378
+ Trash2,
2379
+ User,
2380
+ } from "lucide-react";
2381
+
2382
+ import {Button} from "@arolariu/components/button";
2383
+ import {
2384
+ DropdownMenu,
2385
+ DropdownMenuContent,
2386
+ DropdownMenuGroup,
2387
+ DropdownMenuItem,
2388
+ DropdownMenuLabel,
2389
+ DropdownMenuSeparator,
2390
+ DropdownMenuShortcut,
2391
+ DropdownMenuTrigger,
2392
+ } from "@arolariu/components/dropdown-menu";
2393
+ import {toast} from "@arolariu/components/sonner";
2394
+ import styles from "./dropdown-demo.module.css";
2395
+
2396
+ export function AccessibleDropdownMenu() {
2397
+ const handleAction = (action: string) => {
2398
+ toast.info(`Action: ${action}`);
2399
+ };
2400
+
2401
+ return (
2402
+ <div className={styles.container}>
2403
+ <DropdownMenu>
2404
+ <DropdownMenuTrigger render={<Button variant="outline" />}>
2405
+ <MoreVertical />
2406
+ Actions
2407
+ </DropdownMenuTrigger>
2408
+
2409
+ <DropdownMenuContent align="end" className={styles.content}>
2410
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
2411
+
2412
+ <DropdownMenuSeparator />
2413
+
2414
+ <DropdownMenuGroup>
2415
+ <DropdownMenuItem onClick={() => handleAction("Profile")}>
2416
+ <User />
2417
+ <span>Profile</span>
2418
+ <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
2419
+ </DropdownMenuItem>
2420
+
2421
+ <DropdownMenuItem onClick={() => handleAction("Edit")}>
2422
+ <Edit />
2423
+ <span>Edit</span>
2424
+ <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>
2425
+ </DropdownMenuItem>
2426
+
2427
+ <DropdownMenuItem onClick={() => handleAction("Copy")}>
2428
+ <Copy />
2429
+ <span>Copy Link</span>
2430
+ <DropdownMenuShortcut>⌘C</DropdownMenuShortcut>
2431
+ </DropdownMenuItem>
2432
+
2433
+ <DropdownMenuItem onClick={() => handleAction("Share")}>
2434
+ <Share2 />
2435
+ <span>Share</span>
2436
+ <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
2437
+ </DropdownMenuItem>
2438
+ </DropdownMenuGroup>
2439
+
2440
+ <DropdownMenuSeparator />
2441
+
2442
+ <DropdownMenuGroup>
2443
+ <DropdownMenuItem onClick={() => handleAction("Download")}>
2444
+ <Download />
2445
+ <span>Download</span>
2446
+ <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
2447
+ </DropdownMenuItem>
2448
+ </DropdownMenuGroup>
2449
+
2450
+ <DropdownMenuSeparator />
2451
+
2452
+ <DropdownMenuItem
2453
+ onClick={() => handleAction("Delete")}
2454
+ className={styles.dangerItem}
2455
+ >
2456
+ <Trash2 />
2457
+ <span>Delete</span>
2458
+ <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
2459
+ </DropdownMenuItem>
2460
+
2461
+ <DropdownMenuSeparator />
2462
+
2463
+ <DropdownMenuItem onClick={() => handleAction("Logout")}>
2464
+ <LogOut />
2465
+ <span>Log out</span>
2466
+ <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
2467
+ </DropdownMenuItem>
2468
+ </DropdownMenuContent>
2469
+ </DropdownMenu>
2470
+
2471
+ <div className={styles.instructions}>
2472
+ <p className={styles.instructionTitle}>Keyboard Navigation:</p>
2473
+ <ul className={styles.instructionList}>
2474
+ <li><kbd>Enter</kbd> or <kbd>Space</kbd> - Open menu</li>
2475
+ <li><kbd>↑</kbd> <kbd>↓</kbd> - Navigate items</li>
2476
+ <li><kbd>Enter</kbd> - Select item</li>
2477
+ <li><kbd>Esc</kbd> - Close menu</li>
2478
+ </ul>
2479
+ </div>
2480
+ </div>
2481
+ );
2482
+ }
2483
+ ```
2484
+
2485
+ ```css
2486
+ /* dropdown-demo.module.css */
2487
+ .container {
2488
+ display: flex;
2489
+ flex-direction: column;
2490
+ align-items: center;
2491
+ gap: 2rem;
2492
+ padding: 4rem 1rem;
2493
+ }
2494
+
2495
+ .content {
2496
+ min-width: 14rem;
2497
+ }
2498
+
2499
+ .dangerItem {
2500
+ color: var(--ac-destructive);
2501
+ }
2502
+
2503
+ .instructions {
2504
+ display: grid;
2505
+ gap: 0.5rem;
2506
+ padding: 1rem;
2507
+ background-color: var(--ac-muted);
2508
+ border-radius: var(--ac-radius-md);
2509
+ }
2510
+
2511
+ .instructionTitle {
2512
+ font-weight: 600;
2513
+ }
2514
+
2515
+ .instructionList {
2516
+ display: grid;
2517
+ gap: 0.25rem;
2518
+ padding-left: 1.5rem;
2519
+ font-size: 0.875rem;
2520
+ color: var(--ac-muted-foreground);
2521
+ }
2522
+
2523
+ .instructionList kbd {
2524
+ display: inline-block;
2525
+ padding: 0.125rem 0.375rem;
2526
+ background-color: var(--ac-background);
2527
+ border: 1px solid var(--ac-border);
2528
+ border-radius: var(--ac-radius-sm);
2529
+ font-family: var(--ac-font-mono);
2530
+ font-size: 0.75rem;
2531
+ }
2532
+ ```
2533
+
2534
+ ---
2535
+
2536
+ ### Recipe 7: Date Picker (Calendar Integration)
2537
+
2538
+ **Calendar-based date picker with range selection.**
2539
+
2540
+ ```tsx
2541
+ import {format} from "date-fns";
2542
+ import {Calendar as CalendarIcon} from "lucide-react";
2543
+ import {useState} from "react";
2544
+
2545
+ import {Button} from "@arolariu/components/button";
2546
+ import {Calendar} from "@arolariu/components/calendar";
2547
+ import {
2548
+ Popover,
2549
+ PopoverContent,
2550
+ PopoverTrigger,
2551
+ } from "@arolariu/components/popover";
2552
+ import {cn} from "@arolariu/components/utilities";
2553
+ import styles from "./date-picker.module.css";
2554
+
2555
+ export function DatePicker() {
2556
+ const [date, setDate] = useState<Date | undefined>();
2557
+
2558
+ return (
2559
+ <div className={styles.container}>
2560
+ <div className={styles.field}>
2561
+ <label className={styles.label}>Select Date</label>
2562
+ <Popover>
2563
+ <PopoverTrigger render={<Button variant="outline" className={styles.trigger} />}>
2564
+ <CalendarIcon className={styles.icon} />
2565
+ {date ? format(date, "PPP") : <span>Pick a date</span>}
2566
+ </PopoverTrigger>
2567
+ <PopoverContent align="start" className={styles.popoverContent}>
2568
+ <Calendar
2569
+ mode="single"
2570
+ selected={date}
2571
+ onSelect={setDate}
2572
+ initialFocus
2573
+ />
2574
+ </PopoverContent>
2575
+ </Popover>
2576
+ </div>
2577
+ </div>
2578
+ );
2579
+ }
2580
+
2581
+ export function DateRangePicker() {
2582
+ const [dateRange, setDateRange] = useState<{from: Date | undefined; to: Date | undefined}>({
2583
+ from: undefined,
2584
+ to: undefined,
2585
+ });
2586
+
2587
+ return (
2588
+ <div className={styles.container}>
2589
+ <div className={styles.field}>
2590
+ <label className={styles.label}>Select Date Range</label>
2591
+ <Popover>
2592
+ <PopoverTrigger render={<Button variant="outline" className={styles.trigger} />}>
2593
+ <CalendarIcon className={styles.icon} />
2594
+ {dateRange.from ? (
2595
+ dateRange.to ? (
2596
+ <>
2597
+ {format(dateRange.from, "LLL dd, y")} - {format(dateRange.to, "LLL dd, y")}
2598
+ </>
2599
+ ) : (
2600
+ format(dateRange.from, "LLL dd, y")
2601
+ )
2602
+ ) : (
2603
+ <span>Pick a date range</span>
2604
+ )}
2605
+ </PopoverTrigger>
2606
+ <PopoverContent align="start" className={styles.popoverContent}>
2607
+ <Calendar
2608
+ mode="range"
2609
+ selected={dateRange}
2610
+ onSelect={(range) =>
2611
+ setDateRange({
2612
+ from: range?.from,
2613
+ to: range?.to,
2614
+ })
2615
+ }
2616
+ numberOfMonths={2}
2617
+ initialFocus
2618
+ />
2619
+ </PopoverContent>
2620
+ </Popover>
2621
+ </div>
2622
+ </div>
2623
+ );
2624
+ }
2625
+ ```
2626
+
2627
+ ```css
2628
+ /* date-picker.module.css */
2629
+ .container {
2630
+ display: flex;
2631
+ align-items: center;
2632
+ justify-content: center;
2633
+ min-height: 100vh;
2634
+ padding: 1rem;
2635
+ }
2636
+
2637
+ .field {
2638
+ display: grid;
2639
+ gap: 0.5rem;
2640
+ width: min(24rem, 100%);
2641
+ }
2642
+
2643
+ .label {
2644
+ font-weight: 500;
2645
+ }
2646
+
2647
+ .trigger {
2648
+ justify-content: flex-start;
2649
+ text-align: left;
2650
+ font-weight: 400;
2651
+ }
2652
+
2653
+ .icon {
2654
+ width: 1rem;
2655
+ height: 1rem;
2656
+ margin-right: 0.5rem;
2657
+ }
2658
+
2659
+ .popoverContent {
2660
+ width: auto;
2661
+ padding: 0;
2662
+ }
2663
+ ```
2664
+
2665
+ ---
2666
+
2667
+ ### Recipe 8: File Upload Area (with Progress)
2668
+
2669
+ **Drag-and-drop file upload with progress tracking.**
2670
+
2671
+ ```tsx
2672
+ import {Upload, X} from "lucide-react";
2673
+ import {useState} from "react";
2674
+
2675
+ import {Button} from "@arolariu/components/button";
2676
+ import {Card, CardContent, CardHeader, CardTitle} from "@arolariu/components/card";
2677
+ import {Progress} from "@arolariu/components/progress";
2678
+ import {toast} from "@arolariu/components/sonner";
2679
+ import styles from "./file-upload.module.css";
2680
+
2681
+ interface FileUpload {
2682
+ id: string;
2683
+ file: File;
2684
+ progress: number;
2685
+ status: "uploading" | "complete" | "error";
2686
+ }
2687
+
2688
+ export function FileUploadArea() {
2689
+ const [uploads, setUploads] = useState<FileUpload[]>([]);
2690
+ const [isDragging, setIsDragging] = useState(false);
2691
+
2692
+ const handleDragOver = (e: React.DragEvent) => {
2693
+ e.preventDefault();
2694
+ setIsDragging(true);
2695
+ };
2696
+
2697
+ const handleDragLeave = () => {
2698
+ setIsDragging(false);
2699
+ };
2700
+
2701
+ const handleDrop = (e: React.DragEvent) => {
2702
+ e.preventDefault();
2703
+ setIsDragging(false);
2704
+
2705
+ const files = Array.from(e.dataTransfer.files);
2706
+ handleFiles(files);
2707
+ };
2708
+
2709
+ const handleFileInput = (e: React.ChangeEvent<HTMLInputElement>) => {
2710
+ const files = e.target.files ? Array.from(e.target.files) : [];
2711
+ handleFiles(files);
2712
+ };
2713
+
2714
+ const handleFiles = (files: File[]) => {
2715
+ const newUploads: FileUpload[] = files.map((file) => ({
2716
+ id: Math.random().toString(36).substring(7),
2717
+ file,
2718
+ progress: 0,
2719
+ status: "uploading" as const,
2720
+ }));
2721
+
2722
+ setUploads((prev) => [...prev, ...newUploads]);
2723
+
2724
+ // Simulate upload progress
2725
+ newUploads.forEach((upload) => {
2726
+ simulateUpload(upload.id);
2727
+ });
2728
+ };
2729
+
2730
+ const simulateUpload = (id: string) => {
2731
+ const interval = setInterval(() => {
2732
+ setUploads((prev) =>
2733
+ prev.map((upload) => {
2734
+ if (upload.id === id) {
2735
+ const newProgress = Math.min(upload.progress + 10, 100);
2736
+ const newStatus = newProgress === 100 ? "complete" : upload.status;
2737
+
2738
+ if (newStatus === "complete") {
2739
+ clearInterval(interval);
2740
+ toast.success(`${upload.file.name} uploaded successfully`);
2741
+ }
2742
+
2743
+ return {...upload, progress: newProgress, status: newStatus};
2744
+ }
2745
+ return upload;
2746
+ })
2747
+ );
2748
+ }, 300);
2749
+ };
2750
+
2751
+ const removeUpload = (id: string) => {
2752
+ setUploads((prev) => prev.filter((upload) => upload.id !== id));
2753
+ };
2754
+
2755
+ return (
2756
+ <div className={styles.container}>
2757
+ <Card className={styles.card}>
2758
+ <CardHeader>
2759
+ <CardTitle>Upload Files</CardTitle>
2760
+ </CardHeader>
2761
+ <CardContent className={styles.content}>
2762
+ <div
2763
+ className={`${styles.dropZone} ${isDragging ? styles.dropZoneActive : ""}`}
2764
+ onDragOver={handleDragOver}
2765
+ onDragLeave={handleDragLeave}
2766
+ onDrop={handleDrop}
2767
+ >
2768
+ <Upload className={styles.uploadIcon} />
2769
+ <div className={styles.dropZoneText}>
2770
+ <p className={styles.dropZoneTitle}>Drop files here or click to upload</p>
2771
+ <p className={styles.dropZoneSubtitle}>
2772
+ Supports: Images, PDFs, Documents (Max 10MB)
2773
+ </p>
2774
+ </div>
2775
+ <input
2776
+ type="file"
2777
+ multiple
2778
+ className={styles.fileInput}
2779
+ onChange={handleFileInput}
2780
+ />
2781
+ </div>
2782
+
2783
+ {uploads.length > 0 ? (
2784
+ <div className={styles.uploadList}>
2785
+ {uploads.map((upload) => (
2786
+ <div key={upload.id} className={styles.uploadItem}>
2787
+ <div className={styles.uploadInfo}>
2788
+ <div className={styles.uploadName}>{upload.file.name}</div>
2789
+ <div className={styles.uploadSize}>
2790
+ {(upload.file.size / 1024 / 1024).toFixed(2)} MB
2791
+ </div>
2792
+ </div>
2793
+
2794
+ <div className={styles.uploadProgress}>
2795
+ <Progress value={upload.progress} className={styles.progressBar} />
2796
+ <span className={styles.uploadPercent}>{upload.progress}%</span>
2797
+ </div>
2798
+
2799
+ {upload.status === "complete" ? (
2800
+ <Button
2801
+ variant="ghost"
2802
+ size="icon"
2803
+ onClick={() => removeUpload(upload.id)}
2804
+ className={styles.removeButton}
2805
+ >
2806
+ <X />
2807
+ </Button>
2808
+ ) : null}
2809
+ </div>
2810
+ ))}
2811
+ </div>
2812
+ ) : null}
2813
+ </CardContent>
2814
+ </Card>
2815
+ </div>
2816
+ );
2817
+ }
2818
+ ```
2819
+
2820
+ ```css
2821
+ /* file-upload.module.css */
2822
+ .container {
2823
+ display: flex;
2824
+ align-items: center;
2825
+ justify-content: center;
2826
+ min-height: 100vh;
2827
+ padding: 1rem;
2828
+ }
2829
+
2830
+ .card {
2831
+ width: min(40rem, 100%);
2832
+ }
2833
+
2834
+ .content {
2835
+ display: grid;
2836
+ gap: 1.5rem;
2837
+ }
2838
+
2839
+ .dropZone {
2840
+ position: relative;
2841
+ display: flex;
2842
+ flex-direction: column;
2843
+ align-items: center;
2844
+ gap: 1rem;
2845
+ padding: 3rem 2rem;
2846
+ border: 2px dashed var(--ac-border);
2847
+ border-radius: var(--ac-radius-md);
2848
+ background-color: var(--ac-muted);
2849
+ cursor: pointer;
2850
+ transition: all 150ms;
2851
+ }
2852
+
2853
+ .dropZone:hover {
2854
+ border-color: var(--ac-primary);
2855
+ background-color: color-mix(in oklch, var(--ac-primary) 5%, var(--ac-muted));
2856
+ }
2857
+
2858
+ .dropZoneActive {
2859
+ border-color: var(--ac-primary);
2860
+ background-color: color-mix(in oklch, var(--ac-primary) 10%, var(--ac-muted));
2861
+ }
2862
+
2863
+ .uploadIcon {
2864
+ width: 3rem;
2865
+ height: 3rem;
2866
+ color: var(--ac-muted-foreground);
2867
+ }
2868
+
2869
+ .dropZoneText {
2870
+ text-align: center;
2871
+ }
2872
+
2873
+ .dropZoneTitle {
2874
+ font-weight: 600;
2875
+ }
2876
+
2877
+ .dropZoneSubtitle {
2878
+ margin-top: 0.25rem;
2879
+ font-size: 0.875rem;
2880
+ color: var(--ac-muted-foreground);
2881
+ }
2882
+
2883
+ .fileInput {
2884
+ position: absolute;
2885
+ inset: 0;
2886
+ width: 100%;
2887
+ height: 100%;
2888
+ opacity: 0;
2889
+ cursor: pointer;
2890
+ }
2891
+
2892
+ .uploadList {
2893
+ display: grid;
2894
+ gap: 1rem;
2895
+ }
2896
+
2897
+ .uploadItem {
2898
+ display: grid;
2899
+ grid-template-columns: 1fr auto;
2900
+ gap: 1rem;
2901
+ padding: 1rem;
2902
+ border: 1px solid var(--ac-border);
2903
+ border-radius: var(--ac-radius-md);
2904
+ }
2905
+
2906
+ .uploadInfo {
2907
+ display: grid;
2908
+ gap: 0.25rem;
2909
+ }
2910
+
2911
+ .uploadName {
2912
+ font-weight: 500;
2913
+ word-break: break-all;
2914
+ }
2915
+
2916
+ .uploadSize {
2917
+ font-size: 0.875rem;
2918
+ color: var(--ac-muted-foreground);
2919
+ }
2920
+
2921
+ .uploadProgress {
2922
+ grid-column: 1 / -1;
2923
+ display: flex;
2924
+ align-items: center;
2925
+ gap: 0.75rem;
2926
+ }
2927
+
2928
+ .progressBar {
2929
+ flex: 1;
2930
+ }
2931
+
2932
+ .uploadPercent {
2933
+ font-size: 0.875rem;
2934
+ font-weight: 500;
2935
+ color: var(--ac-muted-foreground);
2936
+ }
2937
+
2938
+ .removeButton {
2939
+ align-self: flex-start;
2940
+ }
2941
+ ```
2942
+
2943
+ ---
2944
+
2945
+ ### Recipe 9: Settings Page (Tabs + Form + Switch)
2946
+
2947
+ **Complete settings page with tabs and form controls.**
2948
+
2949
+ ```tsx
2950
+ import {zodResolver} from "@hookform/resolvers/zod";
2951
+ import {useForm} from "react-hook-form";
2952
+ import * as z from "zod";
2953
+
2954
+ import {Button} from "@arolariu/components/button";
2955
+ import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@arolariu/components/card";
2956
+ import {
2957
+ Form,
2958
+ FormControl,
2959
+ FormDescription,
2960
+ FormField,
2961
+ FormItem,
2962
+ FormLabel,
2963
+ FormMessage,
2964
+ } from "@arolariu/components/form";
2965
+ import {Input} from "@arolariu/components/input";
2966
+ import {
2967
+ Select,
2968
+ SelectContent,
2969
+ SelectItem,
2970
+ SelectTrigger,
2971
+ SelectValue,
2972
+ } from "@arolariu/components/select";
2973
+ import {Switch} from "@arolariu/components/switch";
2974
+ import {Tabs, TabsContent, TabsList, TabsTrigger} from "@arolariu/components/tabs";
2975
+ import {Textarea} from "@arolariu/components/textarea";
2976
+ import {toast} from "@arolariu/components/sonner";
2977
+ import styles from "./settings-page.module.css";
2978
+
2979
+ const profileSchema = z.object({
2980
+ username: z.string().min(3, "Username must be at least 3 characters"),
2981
+ email: z.string().email("Please enter a valid email address"),
2982
+ bio: z.string().max(500, "Bio must be less than 500 characters").optional(),
2983
+ });
2984
+
2985
+ const notificationSchema = z.object({
2986
+ emailNotifications: z.boolean(),
2987
+ pushNotifications: z.boolean(),
2988
+ weeklyDigest: z.boolean(),
2989
+ });
2990
+
2991
+ const appearanceSchema = z.object({
2992
+ theme: z.enum(["light", "dark", "system"]),
2993
+ language: z.string(),
2994
+ });
2995
+
2996
+ export function SettingsPage() {
2997
+ const profileForm = useForm<z.infer<typeof profileSchema>>({
2998
+ resolver: zodResolver(profileSchema),
2999
+ defaultValues: {
3000
+ username: "johndoe",
3001
+ email: "john@example.com",
3002
+ bio: "",
3003
+ },
3004
+ });
3005
+
3006
+ const notificationForm = useForm<z.infer<typeof notificationSchema>>({
3007
+ resolver: zodResolver(notificationSchema),
3008
+ defaultValues: {
3009
+ emailNotifications: true,
3010
+ pushNotifications: false,
3011
+ weeklyDigest: true,
3012
+ },
3013
+ });
3014
+
3015
+ const appearanceForm = useForm<z.infer<typeof appearanceSchema>>({
3016
+ resolver: zodResolver(appearanceSchema),
3017
+ defaultValues: {
3018
+ theme: "system",
3019
+ language: "en",
3020
+ },
3021
+ });
3022
+
3023
+ const onProfileSubmit = (values: z.infer<typeof profileSchema>) => {
3024
+ console.log("Profile updated:", values);
3025
+ toast.success("Profile updated successfully!");
3026
+ };
3027
+
3028
+ const onNotificationSubmit = (values: z.infer<typeof notificationSchema>) => {
3029
+ console.log("Notifications updated:", values);
3030
+ toast.success("Notification preferences updated!");
3031
+ };
3032
+
3033
+ const onAppearanceSubmit = (values: z.infer<typeof appearanceSchema>) => {
3034
+ console.log("Appearance updated:", values);
3035
+ toast.success("Appearance settings updated!");
3036
+ };
3037
+
3038
+ return (
3039
+ <div className={styles.container}>
3040
+ <div className={styles.header}>
3041
+ <h1 className={styles.title}>Settings</h1>
3042
+ <p className={styles.subtitle}>
3043
+ Manage your account settings and preferences.
3044
+ </p>
3045
+ </div>
3046
+
3047
+ <Tabs defaultValue="profile" className={styles.tabs}>
3048
+ <TabsList>
3049
+ <TabsTrigger value="profile">Profile</TabsTrigger>
3050
+ <TabsTrigger value="notifications">Notifications</TabsTrigger>
3051
+ <TabsTrigger value="appearance">Appearance</TabsTrigger>
3052
+ </TabsList>
3053
+
3054
+ <TabsContent value="profile" className={styles.tabContent}>
3055
+ <Card>
3056
+ <CardHeader>
3057
+ <CardTitle>Profile Information</CardTitle>
3058
+ <CardDescription>
3059
+ Update your profile details and public information.
3060
+ </CardDescription>
3061
+ </CardHeader>
3062
+ <CardContent>
3063
+ <Form {...profileForm}>
3064
+ <form
3065
+ onSubmit={profileForm.handleSubmit(onProfileSubmit)}
3066
+ className={styles.form}
3067
+ >
3068
+ <FormField
3069
+ control={profileForm.control}
3070
+ name="username"
3071
+ render={({field}) => (
3072
+ <FormItem>
3073
+ <FormLabel>Username</FormLabel>
3074
+ <FormControl>
3075
+ <Input placeholder="johndoe" {...field} />
3076
+ </FormControl>
3077
+ <FormDescription>
3078
+ This is your public display name.
3079
+ </FormDescription>
3080
+ <FormMessage />
3081
+ </FormItem>
3082
+ )}
3083
+ />
3084
+
3085
+ <FormField
3086
+ control={profileForm.control}
3087
+ name="email"
3088
+ render={({field}) => (
3089
+ <FormItem>
3090
+ <FormLabel>Email</FormLabel>
3091
+ <FormControl>
3092
+ <Input type="email" placeholder="john@example.com" {...field} />
3093
+ </FormControl>
3094
+ <FormDescription>
3095
+ Your email address for account notifications.
3096
+ </FormDescription>
3097
+ <FormMessage />
3098
+ </FormItem>
3099
+ )}
3100
+ />
3101
+
3102
+ <FormField
3103
+ control={profileForm.control}
3104
+ name="bio"
3105
+ render={({field}) => (
3106
+ <FormItem>
3107
+ <FormLabel>Bio</FormLabel>
3108
+ <FormControl>
3109
+ <Textarea
3110
+ placeholder="Tell us about yourself..."
3111
+ className={styles.textarea}
3112
+ {...field}
3113
+ />
3114
+ </FormControl>
3115
+ <FormDescription>
3116
+ Brief description for your profile. Max 500 characters.
3117
+ </FormDescription>
3118
+ <FormMessage />
3119
+ </FormItem>
3120
+ )}
3121
+ />
3122
+
3123
+ <Button type="submit">Save Changes</Button>
3124
+ </form>
3125
+ </Form>
3126
+ </CardContent>
3127
+ </Card>
3128
+ </TabsContent>
3129
+
3130
+ <TabsContent value="notifications" className={styles.tabContent}>
3131
+ <Card>
3132
+ <CardHeader>
3133
+ <CardTitle>Notification Preferences</CardTitle>
3134
+ <CardDescription>
3135
+ Choose how you want to receive notifications.
3136
+ </CardDescription>
3137
+ </CardHeader>
3138
+ <CardContent>
3139
+ <Form {...notificationForm}>
3140
+ <form
3141
+ onSubmit={notificationForm.handleSubmit(onNotificationSubmit)}
3142
+ className={styles.form}
3143
+ >
3144
+ <FormField
3145
+ control={notificationForm.control}
3146
+ name="emailNotifications"
3147
+ render={({field}) => (
3148
+ <FormItem className={styles.switchItem}>
3149
+ <div className={styles.switchContent}>
3150
+ <FormLabel>Email Notifications</FormLabel>
3151
+ <FormDescription>
3152
+ Receive email updates about your account activity.
3153
+ </FormDescription>
3154
+ </div>
3155
+ <FormControl>
3156
+ <Switch
3157
+ checked={field.value}
3158
+ onCheckedChange={field.onChange}
3159
+ />
3160
+ </FormControl>
3161
+ </FormItem>
3162
+ )}
3163
+ />
3164
+
3165
+ <FormField
3166
+ control={notificationForm.control}
3167
+ name="pushNotifications"
3168
+ render={({field}) => (
3169
+ <FormItem className={styles.switchItem}>
3170
+ <div className={styles.switchContent}>
3171
+ <FormLabel>Push Notifications</FormLabel>
3172
+ <FormDescription>
3173
+ Get push notifications on your devices.
3174
+ </FormDescription>
3175
+ </div>
3176
+ <FormControl>
3177
+ <Switch
3178
+ checked={field.value}
3179
+ onCheckedChange={field.onChange}
3180
+ />
3181
+ </FormControl>
3182
+ </FormItem>
3183
+ )}
3184
+ />
3185
+
3186
+ <FormField
3187
+ control={notificationForm.control}
3188
+ name="weeklyDigest"
3189
+ render={({field}) => (
3190
+ <FormItem className={styles.switchItem}>
3191
+ <div className={styles.switchContent}>
3192
+ <FormLabel>Weekly Digest</FormLabel>
3193
+ <FormDescription>
3194
+ Receive a weekly summary of your activity.
3195
+ </FormDescription>
3196
+ </div>
3197
+ <FormControl>
3198
+ <Switch
3199
+ checked={field.value}
3200
+ onCheckedChange={field.onChange}
3201
+ />
3202
+ </FormControl>
3203
+ </FormItem>
3204
+ )}
3205
+ />
3206
+
3207
+ <Button type="submit">Save Preferences</Button>
3208
+ </form>
3209
+ </Form>
3210
+ </CardContent>
3211
+ </Card>
3212
+ </TabsContent>
3213
+
3214
+ <TabsContent value="appearance" className={styles.tabContent}>
3215
+ <Card>
3216
+ <CardHeader>
3217
+ <CardTitle>Appearance Settings</CardTitle>
3218
+ <CardDescription>
3219
+ Customize how the application looks and feels.
3220
+ </CardDescription>
3221
+ </CardHeader>
3222
+ <CardContent>
3223
+ <Form {...appearanceForm}>
3224
+ <form
3225
+ onSubmit={appearanceForm.handleSubmit(onAppearanceSubmit)}
3226
+ className={styles.form}
3227
+ >
3228
+ <FormField
3229
+ control={appearanceForm.control}
3230
+ name="theme"
3231
+ render={({field}) => (
3232
+ <FormItem>
3233
+ <FormLabel>Theme</FormLabel>
3234
+ <Select
3235
+ onValueChange={field.onChange}
3236
+ defaultValue={field.value}
3237
+ >
3238
+ <FormControl>
3239
+ <SelectTrigger>
3240
+ <SelectValue placeholder="Select a theme" />
3241
+ </SelectTrigger>
3242
+ </FormControl>
3243
+ <SelectContent>
3244
+ <SelectItem value="light">Light</SelectItem>
3245
+ <SelectItem value="dark">Dark</SelectItem>
3246
+ <SelectItem value="system">System</SelectItem>
3247
+ </SelectContent>
3248
+ </Select>
3249
+ <FormDescription>
3250
+ Choose your preferred color scheme.
3251
+ </FormDescription>
3252
+ <FormMessage />
3253
+ </FormItem>
3254
+ )}
3255
+ />
3256
+
3257
+ <FormField
3258
+ control={appearanceForm.control}
3259
+ name="language"
3260
+ render={({field}) => (
3261
+ <FormItem>
3262
+ <FormLabel>Language</FormLabel>
3263
+ <Select
3264
+ onValueChange={field.onChange}
3265
+ defaultValue={field.value}
3266
+ >
3267
+ <FormControl>
3268
+ <SelectTrigger>
3269
+ <SelectValue placeholder="Select a language" />
3270
+ </SelectTrigger>
3271
+ </FormControl>
3272
+ <SelectContent>
3273
+ <SelectItem value="en">English</SelectItem>
3274
+ <SelectItem value="es">Español</SelectItem>
3275
+ <SelectItem value="fr">Français</SelectItem>
3276
+ <SelectItem value="de">Deutsch</SelectItem>
3277
+ </SelectContent>
3278
+ </Select>
3279
+ <FormDescription>
3280
+ Select your preferred language.
3281
+ </FormDescription>
3282
+ <FormMessage />
3283
+ </FormItem>
3284
+ )}
3285
+ />
3286
+
3287
+ <Button type="submit">Save Settings</Button>
3288
+ </form>
3289
+ </Form>
3290
+ </CardContent>
3291
+ </Card>
3292
+ </TabsContent>
3293
+ </Tabs>
3294
+ </div>
3295
+ );
3296
+ }
3297
+ ```
3298
+
3299
+ ```css
3300
+ /* settings-page.module.css */
3301
+ .container {
3302
+ max-width: 56rem;
3303
+ margin-inline: auto;
3304
+ padding: 2rem 1rem;
3305
+ }
3306
+
3307
+ .header {
3308
+ margin-bottom: 2rem;
3309
+ }
3310
+
3311
+ .title {
3312
+ font-size: 2rem;
3313
+ font-weight: 700;
3314
+ }
3315
+
3316
+ .subtitle {
3317
+ margin-top: 0.5rem;
3318
+ color: var(--ac-muted-foreground);
3319
+ }
3320
+
3321
+ .tabs {
3322
+ display: grid;
3323
+ gap: 1rem;
3324
+ }
3325
+
3326
+ .tabContent {
3327
+ margin-top: 1rem;
3328
+ }
3329
+
3330
+ .form {
3331
+ display: grid;
3332
+ gap: 1.5rem;
3333
+ }
3334
+
3335
+ .textarea {
3336
+ min-height: 6rem;
3337
+ resize: vertical;
3338
+ }
3339
+
3340
+ .switchItem {
3341
+ display: flex;
3342
+ flex-direction: row;
3343
+ align-items: center;
3344
+ justify-content: space-between;
3345
+ padding: 1rem;
3346
+ border: 1px solid var(--ac-border);
3347
+ border-radius: var(--ac-radius-md);
3348
+ }
3349
+
3350
+ .switchContent {
3351
+ display: grid;
3352
+ gap: 0.25rem;
3353
+ }
3354
+ ```
3355
+
3356
+ ---
3357
+
3358
+ ### Recipe 10: Error Handling (ErrorBoundary + AsyncBoundary + Toast)
3359
+
3360
+ **Comprehensive error handling pattern with boundaries and toast notifications.**
3361
+
3362
+ ```tsx
3363
+ import {AlertTriangle, RefreshCw} from "lucide-react";
3364
+ import {Component, Suspense, type ReactNode} from "react";
3365
+
3366
+ import {Alert, AlertDescription, AlertTitle} from "@arolariu/components/alert";
3367
+ import {AsyncBoundary} from "@arolariu/components/async-boundary";
3368
+ import {Button} from "@arolariu/components/button";
3369
+ import {Card, CardContent, CardHeader, CardTitle} from "@arolariu/components/card";
3370
+ import {ErrorBoundary} from "@arolariu/components/error-boundary";
3371
+ import {Skeleton} from "@arolariu/components/skeleton";
3372
+ import {toast} from "@arolariu/components/sonner";
3373
+ import styles from "./error-handling.module.css";
3374
+
3375
+ // Async data fetching component
3376
+ async function fetchUserData(userId: string) {
3377
+ await new Promise((resolve) => setTimeout(resolve, 1500));
3378
+
3379
+ // Simulate random error
3380
+ if (Math.random() > 0.7) {
3381
+ throw new Error("Failed to fetch user data");
3382
+ }
3383
+
3384
+ return {
3385
+ id: userId,
3386
+ name: "John Doe",
3387
+ email: "john@example.com",
3388
+ };
3389
+ }
3390
+
3391
+ function UserProfile({userId}: {userId: string}) {
3392
+ const user = use(fetchUserData(userId));
3393
+
3394
+ return (
3395
+ <Card>
3396
+ <CardHeader>
3397
+ <CardTitle>User Profile</CardTitle>
3398
+ </CardHeader>
3399
+ <CardContent className={styles.profile}>
3400
+ <div className={styles.profileField}>
3401
+ <span className={styles.profileLabel}>Name:</span>
3402
+ <span>{user.name}</span>
3403
+ </div>
3404
+ <div className={styles.profileField}>
3405
+ <span className={styles.profileLabel}>Email:</span>
3406
+ <span>{user.email}</span>
3407
+ </div>
3408
+ </CardContent>
3409
+ </Card>
3410
+ );
3411
+ }
3412
+
3413
+ // Loading fallback
3414
+ function ProfileSkeleton() {
3415
+ return (
3416
+ <Card>
3417
+ <CardHeader>
3418
+ <Skeleton className={styles.skeletonTitle} />
3419
+ </CardHeader>
3420
+ <CardContent className={styles.skeletonContent}>
3421
+ <Skeleton className={styles.skeletonField} />
3422
+ <Skeleton className={styles.skeletonField} />
3423
+ </CardContent>
3424
+ </Card>
3425
+ );
3426
+ }
3427
+
3428
+ // Error fallback
3429
+ function ProfileError({error, reset}: {error: Error; reset: () => void}) {
3430
+ return (
3431
+ <Alert variant="destructive">
3432
+ <AlertTriangle />
3433
+ <AlertTitle>Error Loading Profile</AlertTitle>
3434
+ <AlertDescription className={styles.errorDescription}>
3435
+ {error.message}
3436
+ <Button
3437
+ variant="outline"
3438
+ size="sm"
3439
+ onClick={reset}
3440
+ className={styles.retryButton}
3441
+ >
3442
+ <RefreshCw />
3443
+ Retry
3444
+ </Button>
3445
+ </AlertDescription>
3446
+ </Alert>
3447
+ );
3448
+ }
3449
+
3450
+ export function ErrorHandlingDemo() {
3451
+ const handleAPIError = async () => {
3452
+ try {
3453
+ // Simulate API call that fails
3454
+ await new Promise((_, reject) =>
3455
+ setTimeout(() => reject(new Error("API request failed")), 1000)
3456
+ );
3457
+ } catch (error) {
3458
+ toast.error("Failed to load data. Please try again.", {
3459
+ action: {
3460
+ label: "Retry",
3461
+ onClick: () => handleAPIError(),
3462
+ },
3463
+ });
3464
+ }
3465
+ };
3466
+
3467
+ const handleValidationError = () => {
3468
+ toast.error("Validation failed: Email is required");
3469
+ };
3470
+
3471
+ const handleNetworkError = () => {
3472
+ toast.error("Network error. Please check your connection.", {
3473
+ duration: 5000,
3474
+ });
3475
+ };
3476
+
3477
+ return (
3478
+ <div className={styles.container}>
3479
+ <div className={styles.header}>
3480
+ <h1 className={styles.title}>Error Handling Patterns</h1>
3481
+ <p className={styles.subtitle}>
3482
+ Comprehensive error handling with boundaries and toast notifications.
3483
+ </p>
3484
+ </div>
3485
+
3486
+ <div className={styles.grid}>
3487
+ {/* Pattern 1: AsyncBoundary (React 19 pattern) */}
3488
+ <div className={styles.section}>
3489
+ <h2 className={styles.sectionTitle}>1. AsyncBoundary (Suspense + ErrorBoundary)</h2>
3490
+ <AsyncBoundary
3491
+ suspenseFallback={<ProfileSkeleton />}
3492
+ errorFallback={({error, reset}) => <ProfileError error={error} reset={reset} />}
3493
+ >
3494
+ <UserProfile userId="123" />
3495
+ </AsyncBoundary>
3496
+ </div>
3497
+
3498
+ {/* Pattern 2: Toast for API errors */}
3499
+ <div className={styles.section}>
3500
+ <h2 className={styles.sectionTitle}>2. Toast Notifications for Errors</h2>
3501
+ <Card>
3502
+ <CardContent className={styles.buttonGroup}>
3503
+ <Button onClick={handleAPIError} variant="destructive">
3504
+ Trigger API Error
3505
+ </Button>
3506
+ <Button onClick={handleValidationError} variant="destructive">
3507
+ Trigger Validation Error
3508
+ </Button>
3509
+ <Button onClick={handleNetworkError} variant="destructive">
3510
+ Trigger Network Error
3511
+ </Button>
3512
+ </CardContent>
3513
+ </Card>
3514
+ </div>
3515
+
3516
+ {/* Pattern 3: Inline error display */}
3517
+ <div className={styles.section}>
3518
+ <h2 className={styles.sectionTitle}>3. Inline Error Display</h2>
3519
+ <Alert variant="destructive">
3520
+ <AlertTriangle />
3521
+ <AlertTitle>Authentication Error</AlertTitle>
3522
+ <AlertDescription>
3523
+ Your session has expired. Please log in again to continue.
3524
+ <Button
3525
+ variant="outline"
3526
+ size="sm"
3527
+ className={styles.loginButton}
3528
+ onClick={() => toast.info("Redirecting to login...")}
3529
+ >
3530
+ Log In
3531
+ </Button>
3532
+ </AlertDescription>
3533
+ </Alert>
3534
+ </div>
3535
+ </div>
3536
+ </div>
3537
+ );
3538
+ }
3539
+
3540
+ // React 19 use() hook polyfill (remove when React 19 is stable)
3541
+ function use<T>(promise: Promise<T>): T {
3542
+ if ((promise as any).status === "fulfilled") {
3543
+ return (promise as any).value;
3544
+ } else if ((promise as any).status === "rejected") {
3545
+ throw (promise as any).reason;
3546
+ } else {
3547
+ throw promise.then(
3548
+ (value) => {
3549
+ (promise as any).status = "fulfilled";
3550
+ (promise as any).value = value;
3551
+ },
3552
+ (reason) => {
3553
+ (promise as any).status = "rejected";
3554
+ (promise as any).reason = reason;
3555
+ }
3556
+ );
3557
+ }
3558
+ }
3559
+ ```
3560
+
3561
+ ```css
3562
+ /* error-handling.module.css */
3563
+ .container {
3564
+ max-width: 56rem;
3565
+ margin-inline: auto;
3566
+ padding: 2rem 1rem;
3567
+ }
3568
+
3569
+ .header {
3570
+ margin-bottom: 2rem;
3571
+ }
3572
+
3573
+ .title {
3574
+ font-size: 2rem;
3575
+ font-weight: 700;
3576
+ }
3577
+
3578
+ .subtitle {
3579
+ margin-top: 0.5rem;
3580
+ color: var(--ac-muted-foreground);
3581
+ }
3582
+
3583
+ .grid {
3584
+ display: grid;
3585
+ gap: 2rem;
3586
+ }
3587
+
3588
+ .section {
3589
+ display: grid;
3590
+ gap: 1rem;
3591
+ }
3592
+
3593
+ .sectionTitle {
3594
+ font-size: 1.25rem;
3595
+ font-weight: 600;
3596
+ }
3597
+
3598
+ .profile {
3599
+ display: grid;
3600
+ gap: 0.75rem;
3601
+ }
3602
+
3603
+ .profileField {
3604
+ display: flex;
3605
+ gap: 0.5rem;
3606
+ }
3607
+
3608
+ .profileLabel {
3609
+ font-weight: 600;
3610
+ }
3611
+
3612
+ .skeletonTitle {
3613
+ height: 1.5rem;
3614
+ width: 8rem;
3615
+ }
3616
+
3617
+ .skeletonContent {
3618
+ display: grid;
3619
+ gap: 0.75rem;
3620
+ }
3621
+
3622
+ .skeletonField {
3623
+ height: 1rem;
3624
+ }
3625
+
3626
+ .errorDescription {
3627
+ display: flex;
3628
+ align-items: center;
3629
+ gap: 1rem;
3630
+ margin-top: 0.5rem;
3631
+ }
3632
+
3633
+ .retryButton,
3634
+ .loginButton {
3635
+ margin-left: auto;
3636
+ }
3637
+
3638
+ .buttonGroup {
3639
+ display: grid;
3640
+ gap: 0.5rem;
3641
+ padding: 1.5rem;
3642
+ }
3643
+ ```
3644
+
3645
+ ---
3646
+
3647
+ ## 🎓 Key Takeaways from Pattern Recipes
3648
+
3649
+ ### ✅ Best Practices Demonstrated
3650
+
3651
+ 1. **Form Validation**: Always use `zod` + `react-hook-form` for type-safe validation
3652
+ 2. **Error Handling**: Combine boundaries, inline errors, and toast notifications
3653
+ 3. **Loading States**: Use `Skeleton` components and `AsyncBoundary` for async data
3654
+ 4. **Accessibility**: Keyboard navigation, ARIA attributes, and semantic HTML
3655
+ 5. **Responsive Design**: CSS Modules with container queries and media queries
3656
+ 6. **Type Safety**: Leverage namespace types (`Component.Props`, `Component.State`)
3657
+ 7. **Composition**: Use `render` prop for element composition (Base UI pattern)
3658
+ 8. **Toast Notifications**: Use `toast.promise()` for async operations
3659
+ 9. **State Management**: Keep form state close to components, lift when needed
3660
+ 10. **Progressive Enhancement**: Start with semantic HTML, enhance with JavaScript
3661
+
3662
+ ### 📚 Additional Resources
3663
+
3664
+ - [Base UI Documentation](https://base-ui.com/react/components)
3665
+ - [React Hook Form](https://react-hook-form.com/)
3666
+ - [Zod Validation](https://zod.dev/)
3667
+ - [TanStack Table](https://tanstack.com/table)
3668
+ - [Date-fns](https://date-fns.org/)
3669
+
1035
3670
  Ready to build something amazing? **[🚀 Start with our Quick Start Guide](./README.md#-quick-start)**