@brcarddev/frontend-commons 1.0.2

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 (490) hide show
  1. package/README.md +241 -0
  2. package/eslint.config.js +190 -0
  3. package/package.json +161 -0
  4. package/src/components/atoms/AudioPlayer/audio-player.stories.tsx +36 -0
  5. package/src/components/atoms/AudioPlayer/audio-player.test.tsx +20 -0
  6. package/src/components/atoms/AudioPlayer/audio-player.tsx +13 -0
  7. package/src/components/atoms/AudioPlayer/index.ts +1 -0
  8. package/src/components/atoms/Badge/badge.stories.tsx +80 -0
  9. package/src/components/atoms/Badge/badge.test.tsx +59 -0
  10. package/src/components/atoms/Badge/badge.tsx +47 -0
  11. package/src/components/atoms/Badge/index.ts +1 -0
  12. package/src/components/atoms/Box/box.stories.tsx +37 -0
  13. package/src/components/atoms/Box/box.test.tsx +47 -0
  14. package/src/components/atoms/Box/box.tsx +7 -0
  15. package/src/components/atoms/Box/index.ts +1 -0
  16. package/src/components/atoms/Button/button.stories.tsx +108 -0
  17. package/src/components/atoms/Button/button.test.tsx +54 -0
  18. package/src/components/atoms/Button/button.tsx +96 -0
  19. package/src/components/atoms/Button/index.ts +1 -0
  20. package/src/components/atoms/ButtonUpload/button-upload.stories.tsx +137 -0
  21. package/src/components/atoms/ButtonUpload/button-upload.tsx +304 -0
  22. package/src/components/atoms/ButtonUpload/index.ts +1 -0
  23. package/src/components/atoms/Calendar/calendar.stories.tsx +51 -0
  24. package/src/components/atoms/Calendar/calendar.test.tsx +41 -0
  25. package/src/components/atoms/Calendar/calendar.tsx +107 -0
  26. package/src/components/atoms/Calendar/index.ts +1 -0
  27. package/src/components/atoms/CheckIcon/check-icon.stories.tsx +38 -0
  28. package/src/components/atoms/CheckIcon/check-icon.test.tsx +270 -0
  29. package/src/components/atoms/CheckIcon/check-icon.tsx +141 -0
  30. package/src/components/atoms/CheckIcon/index.ts +1 -0
  31. package/src/components/atoms/Checkbox/checkbox.stories.tsx +133 -0
  32. package/src/components/atoms/Checkbox/checkbox.test.tsx +70 -0
  33. package/src/components/atoms/Checkbox/checkbox.tsx +31 -0
  34. package/src/components/atoms/Checkbox/index.ts +1 -0
  35. package/src/components/atoms/Flex/flex.stories.tsx +33 -0
  36. package/src/components/atoms/Flex/flex.test.tsx +47 -0
  37. package/src/components/atoms/Flex/flex.tsx +7 -0
  38. package/src/components/atoms/Flex/index.ts +1 -0
  39. package/src/components/atoms/Grid/grid.stories.tsx +33 -0
  40. package/src/components/atoms/Grid/grid.test.tsx +47 -0
  41. package/src/components/atoms/Grid/grid.tsx +7 -0
  42. package/src/components/atoms/Grid/index.ts +1 -0
  43. package/src/components/atoms/Icon/icon.stories.tsx +169 -0
  44. package/src/components/atoms/Icon/icon.test.tsx +272 -0
  45. package/src/components/atoms/Icon/icon.tsx +119 -0
  46. package/src/components/atoms/Icon/index.ts +1 -0
  47. package/src/components/atoms/Input/index.ts +1 -0
  48. package/src/components/atoms/Input/input.stories.tsx +704 -0
  49. package/src/components/atoms/Input/input.test.tsx +86 -0
  50. package/src/components/atoms/Input/input.tsx +161 -0
  51. package/src/components/atoms/InputMoney/index.ts +2 -0
  52. package/src/components/atoms/InputMoney/input-money.stories.tsx +240 -0
  53. package/src/components/atoms/InputMoney/input-money.test.tsx +98 -0
  54. package/src/components/atoms/InputMoney/input-money.tsx +254 -0
  55. package/src/components/atoms/InputPhone/index.ts +2 -0
  56. package/src/components/atoms/InputPhone/input-phone.stories.tsx +447 -0
  57. package/src/components/atoms/InputPhone/input-phone.test.tsx +148 -0
  58. package/src/components/atoms/InputPhone/input-phone.tsx +267 -0
  59. package/src/components/atoms/InputSearch/index.ts +2 -0
  60. package/src/components/atoms/InputSearch/input-search.stories.tsx +360 -0
  61. package/src/components/atoms/InputSearch/input-search.test.tsx +239 -0
  62. package/src/components/atoms/InputSearch/input-search.tsx +210 -0
  63. package/src/components/atoms/InputUpload/index.ts +1 -0
  64. package/src/components/atoms/InputUpload/input-upload.stories.tsx +229 -0
  65. package/src/components/atoms/InputUpload/input-upload.test.tsx +556 -0
  66. package/src/components/atoms/InputUpload/input-upload.tsx +434 -0
  67. package/src/components/atoms/InputWithButton/index.ts +2 -0
  68. package/src/components/atoms/InputWithButton/input-with-button.stories.tsx +503 -0
  69. package/src/components/atoms/InputWithButton/input-with-button.test.tsx +128 -0
  70. package/src/components/atoms/InputWithButton/input-with-button.tsx +170 -0
  71. package/src/components/atoms/Label/index.ts +1 -0
  72. package/src/components/atoms/Label/label.stories.tsx +90 -0
  73. package/src/components/atoms/Label/label.test.tsx +59 -0
  74. package/src/components/atoms/Label/label.tsx +43 -0
  75. package/src/components/atoms/Progress/index.ts +1 -0
  76. package/src/components/atoms/Progress/progress.stories.tsx +30 -0
  77. package/src/components/atoms/Progress/progress.test.tsx +63 -0
  78. package/src/components/atoms/Progress/progress.tsx +32 -0
  79. package/src/components/atoms/RenderCondition/index.ts +1 -0
  80. package/src/components/atoms/RenderCondition/render-condition.stories.tsx +28 -0
  81. package/src/components/atoms/RenderCondition/render-condition.test.tsx +27 -0
  82. package/src/components/atoms/RenderCondition/render-condition.tsx +9 -0
  83. package/src/components/atoms/RichTextEditor/index.ts +1 -0
  84. package/src/components/atoms/RichTextEditor/rich-text-editor.stories.tsx +214 -0
  85. package/src/components/atoms/RichTextEditor/rich-text-editor.test.tsx +442 -0
  86. package/src/components/atoms/RichTextEditor/rich-text-editor.tsx +202 -0
  87. package/src/components/atoms/Separator/index.ts +1 -0
  88. package/src/components/atoms/Separator/separator.stories.tsx +117 -0
  89. package/src/components/atoms/Separator/separator.test.tsx +50 -0
  90. package/src/components/atoms/Separator/separator.tsx +28 -0
  91. package/src/components/atoms/Skeleton/index.ts +1 -0
  92. package/src/components/atoms/Skeleton/skeleton.stories.tsx +84 -0
  93. package/src/components/atoms/Skeleton/skeleton.test.tsx +39 -0
  94. package/src/components/atoms/Skeleton/skeleton.tsx +14 -0
  95. package/src/components/atoms/Slider/index.ts +1 -0
  96. package/src/components/atoms/Slider/slider.stories.tsx +28 -0
  97. package/src/components/atoms/Slider/slider.test.tsx +90 -0
  98. package/src/components/atoms/Slider/slider.tsx +54 -0
  99. package/src/components/atoms/Sonner/index.ts +1 -0
  100. package/src/components/atoms/Sonner/sonner.css +39 -0
  101. package/src/components/atoms/Sonner/sonner.stories.tsx +261 -0
  102. package/src/components/atoms/Sonner/sonner.test.tsx +24 -0
  103. package/src/components/atoms/Sonner/sonner.tsx +13 -0
  104. package/src/components/atoms/Switch/index.ts +1 -0
  105. package/src/components/atoms/Switch/switch.stories.tsx +128 -0
  106. package/src/components/atoms/Switch/switch.test.tsx +70 -0
  107. package/src/components/atoms/Switch/switch.tsx +61 -0
  108. package/src/components/atoms/Textarea/index.ts +1 -0
  109. package/src/components/atoms/Textarea/textarea.stories.tsx +169 -0
  110. package/src/components/atoms/Textarea/textarea.test.tsx +56 -0
  111. package/src/components/atoms/Textarea/textarea.tsx +26 -0
  112. package/src/components/atoms/Toggle/index.ts +1 -0
  113. package/src/components/atoms/Toggle/toggle.stories.tsx +170 -0
  114. package/src/components/atoms/Toggle/toggle.test.tsx +62 -0
  115. package/src/components/atoms/Toggle/toggle.tsx +47 -0
  116. package/src/components/atoms/Typography/index.ts +1 -0
  117. package/src/components/atoms/Typography/typography.stories.tsx +95 -0
  118. package/src/components/atoms/Typography/typography.test.tsx +66 -0
  119. package/src/components/atoms/Typography/typography.tsx +63 -0
  120. package/src/components/atoms/UploadImageField/index.ts +1 -0
  121. package/src/components/atoms/UploadImageField/upload-image-field.stories.tsx +249 -0
  122. package/src/components/atoms/UploadImageField/upload-image-field.test.tsx +348 -0
  123. package/src/components/atoms/UploadImageField/upload-image-field.tsx +362 -0
  124. package/src/components/atoms/VideoPlayer/index.ts +1 -0
  125. package/src/components/atoms/VideoPlayer/video-player.stories.tsx +37 -0
  126. package/src/components/atoms/VideoPlayer/video-player.test.tsx +20 -0
  127. package/src/components/atoms/VideoPlayer/video-player.tsx +26 -0
  128. package/src/components/atoms/index.ts +31 -0
  129. package/src/components/icons/alert-circle.tsx +22 -0
  130. package/src/components/icons/align-center.tsx +22 -0
  131. package/src/components/icons/align-left.tsx +22 -0
  132. package/src/components/icons/annotation-dots.tsx +16 -0
  133. package/src/components/icons/annotation-question.tsx +15 -0
  134. package/src/components/icons/annotation.tsx +22 -0
  135. package/src/components/icons/announcement-01.tsx +15 -0
  136. package/src/components/icons/announcement-02.tsx +15 -0
  137. package/src/components/icons/apple-logo.tsx +9 -0
  138. package/src/components/icons/arrow-circle-broken-right.tsx +16 -0
  139. package/src/components/icons/arrow-down.tsx +9 -0
  140. package/src/components/icons/arrow-up.tsx +9 -0
  141. package/src/components/icons/at-sign.tsx +21 -0
  142. package/src/components/icons/award-01.tsx +15 -0
  143. package/src/components/icons/award-03.tsx +16 -0
  144. package/src/components/icons/bank-note-01.tsx +15 -0
  145. package/src/components/icons/bar-chart-square-02.tsx +9 -0
  146. package/src/components/icons/bell-01.tsx +9 -0
  147. package/src/components/icons/bell-04.tsx +16 -0
  148. package/src/components/icons/bold-01.tsx +22 -0
  149. package/src/components/icons/book-open-01.tsx +15 -0
  150. package/src/components/icons/brackets-ellipses.tsx +22 -0
  151. package/src/components/icons/briefcase-01.tsx +9 -0
  152. package/src/components/icons/brush-01.tsx +22 -0
  153. package/src/components/icons/building-02.tsx +9 -0
  154. package/src/components/icons/building-06.tsx +9 -0
  155. package/src/components/icons/calendar-minus-02.tsx +15 -0
  156. package/src/components/icons/calendar.tsx +9 -0
  157. package/src/components/icons/certificate-01.tsx +16 -0
  158. package/src/components/icons/chart-breakout-square.tsx +16 -0
  159. package/src/components/icons/check-circle-02.tsx +16 -0
  160. package/src/components/icons/check-circle.tsx +15 -0
  161. package/src/components/icons/check.tsx +21 -0
  162. package/src/components/icons/chevron-down-double.tsx +16 -0
  163. package/src/components/icons/chevron-down.tsx +9 -0
  164. package/src/components/icons/chevron-left-double.tsx +22 -0
  165. package/src/components/icons/chevron-left.tsx +16 -0
  166. package/src/components/icons/chevron-right-double.tsx +22 -0
  167. package/src/components/icons/chevron-right.tsx +16 -0
  168. package/src/components/icons/chevron-up-double.tsx +16 -0
  169. package/src/components/icons/clock-rewind.tsx +15 -0
  170. package/src/components/icons/clock-stopwatch.tsx +15 -0
  171. package/src/components/icons/coins-hand.tsx +15 -0
  172. package/src/components/icons/coins-stacked-01.tsx +15 -0
  173. package/src/components/icons/coins-stacked-02.tsx +15 -0
  174. package/src/components/icons/container.tsx +9 -0
  175. package/src/components/icons/copy-02.tsx +16 -0
  176. package/src/components/icons/copy-04.tsx +21 -0
  177. package/src/components/icons/corner-down-right.tsx +9 -0
  178. package/src/components/icons/countries/br.tsx +20 -0
  179. package/src/components/icons/countries/es.tsx +19 -0
  180. package/src/components/icons/countries/index.ts +3 -0
  181. package/src/components/icons/countries/us.tsx +21 -0
  182. package/src/components/icons/dataflow-03.tsx +15 -0
  183. package/src/components/icons/dotpoints-01.tsx +22 -0
  184. package/src/components/icons/dots-vertical.tsx +35 -0
  185. package/src/components/icons/download-03.tsx +16 -0
  186. package/src/components/icons/download-cloud-02.tsx +15 -0
  187. package/src/components/icons/drag.tsx +14 -0
  188. package/src/components/icons/dropper.tsx +21 -0
  189. package/src/components/icons/edit-01.tsx +15 -0
  190. package/src/components/icons/edit-02.tsx +9 -0
  191. package/src/components/icons/edit-03.tsx +23 -0
  192. package/src/components/icons/eye.tsx +22 -0
  193. package/src/components/icons/face-frown.tsx +15 -0
  194. package/src/components/icons/face-happy.tsx +15 -0
  195. package/src/components/icons/file-06.tsx +15 -0
  196. package/src/components/icons/file-attachment-04.tsx +15 -0
  197. package/src/components/icons/file-download-02.tsx +16 -0
  198. package/src/components/icons/file-plus-02.tsx +16 -0
  199. package/src/components/icons/file-search-01.tsx +22 -0
  200. package/src/components/icons/file-search-03.tsx +15 -0
  201. package/src/components/icons/filter-lines.tsx +21 -0
  202. package/src/components/icons/first-category.tsx +16 -0
  203. package/src/components/icons/first-stage.tsx +19 -0
  204. package/src/components/icons/folder.tsx +15 -0
  205. package/src/components/icons/google.tsx +12 -0
  206. package/src/components/icons/graduation-hat-02.tsx +15 -0
  207. package/src/components/icons/grid-01.tsx +36 -0
  208. package/src/components/icons/help-circle.tsx +16 -0
  209. package/src/components/icons/help-square.tsx +16 -0
  210. package/src/components/icons/home-line.tsx +21 -0
  211. package/src/components/icons/icons.stories.tsx +199 -0
  212. package/src/components/icons/index.ts +140 -0
  213. package/src/components/icons/info-circle.tsx +15 -0
  214. package/src/components/icons/italic-01.tsx +22 -0
  215. package/src/components/icons/last-category.tsx +11 -0
  216. package/src/components/icons/last-stage.tsx +19 -0
  217. package/src/components/icons/layout-alt-04.tsx +9 -0
  218. package/src/components/icons/lightbulb-02.tsx +16 -0
  219. package/src/components/icons/link-01.tsx +16 -0
  220. package/src/components/icons/link-broken-01.tsx +16 -0
  221. package/src/components/icons/linkedin-logo.tsx +17 -0
  222. package/src/components/icons/lock-01.tsx +21 -0
  223. package/src/components/icons/log-out-01.tsx +9 -0
  224. package/src/components/icons/mail-01.tsx +16 -0
  225. package/src/components/icons/marker-pin-02.tsx +10 -0
  226. package/src/components/icons/menu-01.tsx +9 -0
  227. package/src/components/icons/middle-category.tsx +10 -0
  228. package/src/components/icons/middle-stage.tsx +19 -0
  229. package/src/components/icons/ms-outlook.tsx +47 -0
  230. package/src/components/icons/paragraph-spacing.tsx +15 -0
  231. package/src/components/icons/phone-01.tsx +21 -0
  232. package/src/components/icons/pie-chart-02.tsx +22 -0
  233. package/src/components/icons/plus-circle.tsx +15 -0
  234. package/src/components/icons/portal-logo.tsx +76 -0
  235. package/src/components/icons/presentation-chart-02.tsx +14 -0
  236. package/src/components/icons/route.tsx +22 -0
  237. package/src/components/icons/save-01.tsx +15 -0
  238. package/src/components/icons/search-lg.tsx +15 -0
  239. package/src/components/icons/search-sm.tsx +9 -0
  240. package/src/components/icons/send-03.tsx +15 -0
  241. package/src/components/icons/settings-01.tsx +17 -0
  242. package/src/components/icons/settings-03.tsx +14 -0
  243. package/src/components/icons/share-05.tsx +15 -0
  244. package/src/components/icons/share-06.tsx +15 -0
  245. package/src/components/icons/slash-circle-01.tsx +9 -0
  246. package/src/components/icons/star-01.tsx +9 -0
  247. package/src/components/icons/step-icon-active.tsx +11 -0
  248. package/src/components/icons/step-icon-checked.tsx +10 -0
  249. package/src/components/icons/step-icon-default.tsx +11 -0
  250. package/src/components/icons/switch-horizontal-01.tsx +9 -0
  251. package/src/components/icons/table-01.tsx +15 -0
  252. package/src/components/icons/tag-01.tsx +15 -0
  253. package/src/components/icons/tag-03.tsx +15 -0
  254. package/src/components/icons/tool-02.tsx +14 -0
  255. package/src/components/icons/trash-01.tsx +15 -0
  256. package/src/components/icons/underline-01.tsx +22 -0
  257. package/src/components/icons/upload-cloud-02.tsx +15 -0
  258. package/src/components/icons/user-01.tsx +9 -0
  259. package/src/components/icons/user-03.tsx +9 -0
  260. package/src/components/icons/user-check-01.tsx +14 -0
  261. package/src/components/icons/user-circle.tsx +14 -0
  262. package/src/components/icons/user-edit.tsx +16 -0
  263. package/src/components/icons/user-minus-02.tsx +15 -0
  264. package/src/components/icons/user-plus-01.tsx +22 -0
  265. package/src/components/icons/user-plus-02.tsx +15 -0
  266. package/src/components/icons/user-square.tsx +16 -0
  267. package/src/components/icons/users-01.tsx +14 -0
  268. package/src/components/icons/users-plus-01.tsx +21 -0
  269. package/src/components/icons/users-plus.tsx +16 -0
  270. package/src/components/icons/vertical-drag.tsx +21 -0
  271. package/src/components/icons/x-circle.tsx +15 -0
  272. package/src/components/icons/x-close.tsx +9 -0
  273. package/src/components/icons/zap-fast.tsx +16 -0
  274. package/src/components/icons/zap.tsx +9 -0
  275. package/src/components/index.ts +4 -0
  276. package/src/components/molecules/Accordion/accordion.stories.tsx +81 -0
  277. package/src/components/molecules/Accordion/accordion.test.tsx +91 -0
  278. package/src/components/molecules/Accordion/accordion.tsx +65 -0
  279. package/src/components/molecules/Accordion/index.ts +1 -0
  280. package/src/components/molecules/Alert/alert.stories.tsx +75 -0
  281. package/src/components/molecules/Alert/alert.test.tsx +58 -0
  282. package/src/components/molecules/Alert/alert.tsx +67 -0
  283. package/src/components/molecules/Alert/index.ts +1 -0
  284. package/src/components/molecules/AlertDialog/alert-dialog.stories.tsx +55 -0
  285. package/src/components/molecules/AlertDialog/alert-dialog.test.tsx +34 -0
  286. package/src/components/molecules/AlertDialog/alert-dialog.tsx +172 -0
  287. package/src/components/molecules/AlertDialog/index.ts +1 -0
  288. package/src/components/molecules/Avatar/avatar.stories.tsx +98 -0
  289. package/src/components/molecules/Avatar/avatar.test.tsx +55 -0
  290. package/src/components/molecules/Avatar/avatar.tsx +55 -0
  291. package/src/components/molecules/Avatar/index.ts +1 -0
  292. package/src/components/molecules/Breadcrumb/breadcrumb.stories.tsx +125 -0
  293. package/src/components/molecules/Breadcrumb/breadcrumb.test.tsx +118 -0
  294. package/src/components/molecules/Breadcrumb/breadcrumb.tsx +120 -0
  295. package/src/components/molecules/Breadcrumb/index.ts +1 -0
  296. package/src/components/molecules/Card/card.stories.tsx +109 -0
  297. package/src/components/molecules/Card/card.test.tsx +103 -0
  298. package/src/components/molecules/Card/card.tsx +78 -0
  299. package/src/components/molecules/Card/index.ts +1 -0
  300. package/src/components/molecules/Collapsible/collapsible.stories.tsx +28 -0
  301. package/src/components/molecules/Collapsible/collapsible.test.tsx +36 -0
  302. package/src/components/molecules/Collapsible/collapsible.tsx +31 -0
  303. package/src/components/molecules/Collapsible/index.ts +1 -0
  304. package/src/components/molecules/ColorPicker/color-picker.stories.tsx +40 -0
  305. package/src/components/molecules/ColorPicker/color-picker.tsx +106 -0
  306. package/src/components/molecules/ColorPicker/index.ts +1 -0
  307. package/src/components/molecules/ColorScale/color-scale.stories.tsx +31 -0
  308. package/src/components/molecules/ColorScale/color-scale.tsx +74 -0
  309. package/src/components/molecules/ColorScale/index.ts +1 -0
  310. package/src/components/molecules/Command/command.stories.tsx +71 -0
  311. package/src/components/molecules/Command/command.test.tsx +50 -0
  312. package/src/components/molecules/Command/command.tsx +177 -0
  313. package/src/components/molecules/Command/index.ts +1 -0
  314. package/src/components/molecules/ContextMenu/context-menu.stories.tsx +69 -0
  315. package/src/components/molecules/ContextMenu/context-menu.test.tsx +25 -0
  316. package/src/components/molecules/ContextMenu/context-menu.tsx +259 -0
  317. package/src/components/molecules/ContextMenu/index.ts +1 -0
  318. package/src/components/molecules/DatePicker/date-picker.stories.tsx +204 -0
  319. package/src/components/molecules/DatePicker/date-picker.test.tsx +27 -0
  320. package/src/components/molecules/DatePicker/date-picker.tsx +486 -0
  321. package/src/components/molecules/DatePicker/index.ts +1 -0
  322. package/src/components/molecules/Dialog/dialog.stories.tsx +48 -0
  323. package/src/components/molecules/Dialog/dialog.test.tsx +51 -0
  324. package/src/components/molecules/Dialog/dialog.tsx +150 -0
  325. package/src/components/molecules/Dialog/index.ts +1 -0
  326. package/src/components/molecules/Drawer/drawer.stories.tsx +182 -0
  327. package/src/components/molecules/Drawer/drawer.test.tsx +100 -0
  328. package/src/components/molecules/Drawer/drawer.tsx +206 -0
  329. package/src/components/molecules/Drawer/index.ts +1 -0
  330. package/src/components/molecules/Dropdown/dropdown-async.stories.tsx +15 -0
  331. package/src/components/molecules/Dropdown/dropdown.stories.tsx +112 -0
  332. package/src/components/molecules/Dropdown/dropdown.test.tsx +128 -0
  333. package/src/components/molecules/Dropdown/dropdown.tsx +322 -0
  334. package/src/components/molecules/Dropdown/index.ts +1 -0
  335. package/src/components/molecules/DropdownMenu/dropdown-menu.stories.tsx +154 -0
  336. package/src/components/molecules/DropdownMenu/dropdown-menu.test.tsx +163 -0
  337. package/src/components/molecules/DropdownMenu/dropdown-menu.tsx +313 -0
  338. package/src/components/molecules/DropdownMenu/index.ts +1 -0
  339. package/src/components/molecules/HoverCard/hover-card.stories.tsx +48 -0
  340. package/src/components/molecules/HoverCard/hover-card.test.tsx +42 -0
  341. package/src/components/molecules/HoverCard/hover-card.tsx +44 -0
  342. package/src/components/molecules/HoverCard/index.ts +1 -0
  343. package/src/components/molecules/InputOTP/index.ts +1 -0
  344. package/src/components/molecules/InputOTP/input-otp.stories.tsx +52 -0
  345. package/src/components/molecules/InputOTP/input-otp.test.tsx +28 -0
  346. package/src/components/molecules/InputOTP/input-otp.tsx +76 -0
  347. package/src/components/molecules/Menubar/index.ts +1 -0
  348. package/src/components/molecules/Menubar/menubar.stories.tsx +113 -0
  349. package/src/components/molecules/Menubar/menubar.test.tsx +42 -0
  350. package/src/components/molecules/Menubar/menubar.tsx +314 -0
  351. package/src/components/molecules/NavigationMenu/index.ts +1 -0
  352. package/src/components/molecules/NavigationMenu/navigation-menu.stories.tsx +143 -0
  353. package/src/components/molecules/NavigationMenu/navigation-menu.test.tsx +69 -0
  354. package/src/components/molecules/NavigationMenu/navigation-menu.tsx +174 -0
  355. package/src/components/molecules/PDFViewer/index.ts +1 -0
  356. package/src/components/molecules/PDFViewer/pdf-viewer.stories.tsx +34 -0
  357. package/src/components/molecules/PDFViewer/pdf-viewer.test.tsx +26 -0
  358. package/src/components/molecules/PDFViewer/pdf-viewer.tsx +358 -0
  359. package/src/components/molecules/Pagination/index.ts +1 -0
  360. package/src/components/molecules/Pagination/pagination.stories.tsx +193 -0
  361. package/src/components/molecules/Pagination/pagination.test.tsx +448 -0
  362. package/src/components/molecules/Pagination/pagination.tsx +206 -0
  363. package/src/components/molecules/PaginationDotGroup/index.ts +1 -0
  364. package/src/components/molecules/PaginationDotGroup/pagination-dot-group.stories.tsx +211 -0
  365. package/src/components/molecules/PaginationDotGroup/pagination-dot-group.test.tsx +385 -0
  366. package/src/components/molecules/PaginationDotGroup/pagination-dot-group.tsx +119 -0
  367. package/src/components/molecules/Popover/index.ts +1 -0
  368. package/src/components/molecules/Popover/popover-menu.stories.tsx +27 -0
  369. package/src/components/molecules/Popover/popover.test.tsx +50 -0
  370. package/src/components/molecules/Popover/popover.tsx +38 -0
  371. package/src/components/molecules/ProgressSteps/index.ts +1 -0
  372. package/src/components/molecules/ProgressSteps/progress-steps.stories.tsx +36 -0
  373. package/src/components/molecules/ProgressSteps/progress-steps.test.tsx +470 -0
  374. package/src/components/molecules/ProgressSteps/progress-steps.tsx +140 -0
  375. package/src/components/molecules/RadioGroup/index.ts +1 -0
  376. package/src/components/molecules/RadioGroup/radio-group.stories.tsx +42 -0
  377. package/src/components/molecules/RadioGroup/radio-group.test.tsx +22 -0
  378. package/src/components/molecules/RadioGroup/radio-group.tsx +55 -0
  379. package/src/components/molecules/Resizable/index.ts +1 -0
  380. package/src/components/molecules/Resizable/resizable.stories.tsx +52 -0
  381. package/src/components/molecules/Resizable/resizable.test.tsx +22 -0
  382. package/src/components/molecules/Resizable/resizable.tsx +55 -0
  383. package/src/components/molecules/ScrollArea/index.ts +1 -0
  384. package/src/components/molecules/ScrollArea/scroll-area.stories.tsx +93 -0
  385. package/src/components/molecules/ScrollArea/scroll-area.test.tsx +28 -0
  386. package/src/components/molecules/ScrollArea/scroll-area.tsx +57 -0
  387. package/src/components/molecules/Select/index.ts +1 -0
  388. package/src/components/molecules/Select/select.stories.tsx +63 -0
  389. package/src/components/molecules/Select/select.test.tsx +80 -0
  390. package/src/components/molecules/Select/select.tsx +172 -0
  391. package/src/components/molecules/Sheet/index.ts +1 -0
  392. package/src/components/molecules/Sheet/sheet.stories.tsx +141 -0
  393. package/src/components/molecules/Sheet/sheet.test.tsx +70 -0
  394. package/src/components/molecules/Sheet/sheet.tsx +133 -0
  395. package/src/components/molecules/Tabs/index.ts +1 -0
  396. package/src/components/molecules/Tabs/tabs.stories.tsx +222 -0
  397. package/src/components/molecules/Tabs/tabs.test.tsx +113 -0
  398. package/src/components/molecules/Tabs/tabs.tsx +102 -0
  399. package/src/components/molecules/ToggleGroup/index.ts +1 -0
  400. package/src/components/molecules/ToggleGroup/toggle-group.stories.tsx +117 -0
  401. package/src/components/molecules/ToggleGroup/toggle-group.test.tsx +100 -0
  402. package/src/components/molecules/ToggleGroup/toggle-group.tsx +70 -0
  403. package/src/components/molecules/Tooltip/index.ts +1 -0
  404. package/src/components/molecules/Tooltip/tooltip.stories.tsx +133 -0
  405. package/src/components/molecules/Tooltip/tooltip.test.tsx +58 -0
  406. package/src/components/molecules/Tooltip/tooltip.tsx +58 -0
  407. package/src/components/molecules/index.ts +33 -0
  408. package/src/components/organisms/Carousel/carousel.stories.tsx +94 -0
  409. package/src/components/organisms/Carousel/carousel.test.tsx +24 -0
  410. package/src/components/organisms/Carousel/carousel.tsx +383 -0
  411. package/src/components/organisms/Carousel/index.ts +1 -0
  412. package/src/components/organisms/Chart/chart.stories.tsx +102 -0
  413. package/src/components/organisms/Chart/chart.test.tsx +105 -0
  414. package/src/components/organisms/Chart/chart.tsx +294 -0
  415. package/src/components/organisms/Chart/index.ts +1 -0
  416. package/src/components/organisms/FileUpload/FilePreview/file-preview.tsx +55 -0
  417. package/src/components/organisms/FileUpload/FilePreview/index.ts +1 -0
  418. package/src/components/organisms/FileUpload/file-upload.stories.tsx +20 -0
  419. package/src/components/organisms/FileUpload/file-upload.test.tsx +59 -0
  420. package/src/components/organisms/FileUpload/file-upload.tsx +175 -0
  421. package/src/components/organisms/FileUpload/file.d.ts +21 -0
  422. package/src/components/organisms/FileUpload/index.ts +1 -0
  423. package/src/components/organisms/Form/form.stories.tsx +155 -0
  424. package/src/components/organisms/Form/form.test.tsx +49 -0
  425. package/src/components/organisms/Form/form.tsx +133 -0
  426. package/src/components/organisms/Form/index.ts +1 -0
  427. package/src/components/organisms/Sidebar/index.ts +1 -0
  428. package/src/components/organisms/Sidebar/sidebar.stories.tsx +86 -0
  429. package/src/components/organisms/Sidebar/sidebar.test.tsx +101 -0
  430. package/src/components/organisms/Sidebar/sidebar.tsx +666 -0
  431. package/src/components/organisms/Table/index.ts +1 -0
  432. package/src/components/organisms/Table/table.stories.tsx +86 -0
  433. package/src/components/organisms/Table/table.test.tsx +42 -0
  434. package/src/components/organisms/Table/table.tsx +120 -0
  435. package/src/components/organisms/index.ts +6 -0
  436. package/src/constants/brazilian-states.ts +29 -0
  437. package/src/constants/index.ts +1 -0
  438. package/src/hooks/index.ts +10 -0
  439. package/src/hooks/useEditorActiveMarks.ts +63 -0
  440. package/src/hooks/useForm.ts +8 -0
  441. package/src/hooks/useFormContext.ts +7 -0
  442. package/src/hooks/useFormField.ts +41 -0
  443. package/src/hooks/useMobile.ts +61 -0
  444. package/src/hooks/useOnToggle.ts +28 -0
  445. package/src/hooks/usePDFNavigation.ts +41 -0
  446. package/src/hooks/usePDFZoom.ts +35 -0
  447. package/src/hooks/useSidebar.ts +23 -0
  448. package/src/hooks/useToast.tsx +63 -0
  449. package/src/index.css +73 -0
  450. package/src/main.ts +6 -0
  451. package/src/theme.css +388 -0
  452. package/src/utils/api/api.test.ts +64 -0
  453. package/src/utils/api/api.ts +34 -0
  454. package/src/utils/api/index.ts +1 -0
  455. package/src/utils/array/array.test.ts +160 -0
  456. package/src/utils/array/array.ts +43 -0
  457. package/src/utils/array/index.ts +1 -0
  458. package/src/utils/clipboard/clipboard.test.ts +218 -0
  459. package/src/utils/clipboard/clipboard.ts +40 -0
  460. package/src/utils/clipboard/index.ts +1 -0
  461. package/src/utils/cn/cn.test.ts +43 -0
  462. package/src/utils/cn/cn.ts +6 -0
  463. package/src/utils/cn/index.ts +1 -0
  464. package/src/utils/color-utils/color-utils.test.ts +46 -0
  465. package/src/utils/color-utils/color-utils.ts +97 -0
  466. package/src/utils/color-utils/index.ts +1 -0
  467. package/src/utils/countries/countries.ts +69 -0
  468. package/src/utils/countries/index.ts +1 -0
  469. package/src/utils/currency/currency.test.ts +114 -0
  470. package/src/utils/currency/currency.ts +134 -0
  471. package/src/utils/currency/index.ts +1 -0
  472. package/src/utils/date/date.test.ts +167 -0
  473. package/src/utils/date/date.ts +83 -0
  474. package/src/utils/date/index.ts +1 -0
  475. package/src/utils/file/file.ts +45 -0
  476. package/src/utils/file/index.ts +1 -0
  477. package/src/utils/get-initials/get-initials.test.ts +40 -0
  478. package/src/utils/get-initials/get-initials.ts +13 -0
  479. package/src/utils/get-initials/index.ts +1 -0
  480. package/src/utils/index.ts +14 -0
  481. package/src/utils/masks/index.ts +1 -0
  482. package/src/utils/masks/masks.ts +180 -0
  483. package/src/utils/render-highlighted-text/index.ts +1 -0
  484. package/src/utils/render-highlighted-text/render-highlighted-text.tsx +25 -0
  485. package/src/utils/string/index.ts +1 -0
  486. package/src/utils/string/string.test.ts +171 -0
  487. package/src/utils/string/string.ts +155 -0
  488. package/src/utils/video/index.ts +1 -0
  489. package/src/utils/video/video.ts +9 -0
  490. package/src/vite-env.d.ts +3 -0
@@ -0,0 +1,222 @@
1
+ import { Settings, User, Bell } from 'lucide-react';
2
+
3
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from './tabs';
4
+
5
+ import type { Meta, StoryObj } from '@storybook/react';
6
+
7
+ const meta: Meta<typeof Tabs> = {
8
+ title: 'Components/Navigation/Tabs',
9
+ component: Tabs,
10
+ tags: [ 'autodocs' ],
11
+ parameters: {
12
+ layout: 'centered',
13
+ docs: {
14
+ description: {
15
+ component: `
16
+ The Tabs component organizes content into separate sections, accessible through tab navigation.
17
+ It is ideal for displaying different groups of related information in the same space, improving the user experience with clear and accessible navigation.
18
+
19
+ Internally, it is built on \`@radix-ui/react-tabs\`, ensuring keyboard accessibility, automatic focus, and responsive behavior.
20
+ `,
21
+ },
22
+ },
23
+ },
24
+ };
25
+
26
+ export default meta;
27
+ type Story = StoryObj<typeof Tabs>;
28
+
29
+ export const Default: Story = {
30
+ name: 'Default',
31
+ parameters: {
32
+ docs: {
33
+ description: {
34
+ story:
35
+ 'Basic example with three tabs, each displaying simple textual content.',
36
+ },
37
+ },
38
+ },
39
+ render: () => (
40
+ <div className='w-[500px]'>
41
+ <Tabs defaultValue="perfil">
42
+ <TabsList>
43
+ <TabsTrigger value="perfil">Profile</TabsTrigger>
44
+ <TabsTrigger value="notification">Notifications</TabsTrigger>
45
+ <TabsTrigger value="configs">Settings</TabsTrigger>
46
+ </TabsList>
47
+ <TabsContent value="perfil">
48
+ <div className="mt-4 text-sm">
49
+ User information, photo and personal preferences.
50
+ </div>
51
+ </TabsContent>
52
+ <TabsContent value="notification">
53
+ <div className="mt-4 text-sm">
54
+ Recent alerts, email status and permissions.
55
+ </div>
56
+ </TabsContent>
57
+ <TabsContent value="configs">
58
+ <div className="mt-4 text-sm">
59
+ Account preferences, authentication and app integration.
60
+ </div>
61
+ </TabsContent>
62
+ </Tabs>
63
+ </div>
64
+ ),
65
+ };
66
+
67
+ export const DisabledTabs: Story = {
68
+ name: 'Disabled tabs',
69
+ parameters: {
70
+ docs: {
71
+ description: {
72
+ story:
73
+ 'Demonstration of how a tab can be disabled to prevent user interaction.',
74
+ },
75
+ },
76
+ },
77
+ render: () => (
78
+ <Tabs defaultValue="perfil">
79
+ <TabsList>
80
+ <TabsTrigger value="perfil">Perfil</TabsTrigger>
81
+ <TabsTrigger value="notification" disabled>
82
+ Notifications
83
+ </TabsTrigger>
84
+ <TabsTrigger value="configs">Settings</TabsTrigger>
85
+ </TabsList>
86
+ <TabsContent value="perfil">
87
+ <div className="mt-4 text-sm">
88
+ Disabled tabs cannot be clicked or focused.
89
+ </div>
90
+ </TabsContent>
91
+ <TabsContent value="configs">
92
+ <div className="mt-4 text-sm">This tab remains active by default.</div>
93
+ </TabsContent>
94
+ </Tabs>
95
+ ),
96
+ };
97
+
98
+ export const WithIcons: Story = {
99
+ name: 'With icons',
100
+ parameters: {
101
+ docs: {
102
+ description: {
103
+ story:
104
+ 'Tabs can contain icons to visually reinforce the content they represent.',
105
+ },
106
+ },
107
+ },
108
+ render: () => (
109
+ <Tabs defaultValue="perfil">
110
+ <TabsList>
111
+ <TabsTrigger value="perfil">
112
+ <User />
113
+ Profile
114
+ </TabsTrigger>
115
+ <TabsTrigger value="notification">
116
+ <Bell />
117
+ Notifications
118
+ </TabsTrigger>
119
+ <TabsTrigger value="configs">
120
+ <Settings />
121
+ Settings
122
+ </TabsTrigger>
123
+ </TabsList>
124
+ <TabsContent value="perfil">
125
+ <div className="mt-4 text-sm">Details of the profile with a representative icon.</div>
126
+ </TabsContent>
127
+ <TabsContent value="notification">
128
+ <div className="mt-4 text-sm">Section of recent alerts and activities.</div>
129
+ </TabsContent>
130
+ <TabsContent value="configs">
131
+ <div className="mt-4 text-sm">Advanced technical settings and preferences.</div>
132
+ </TabsContent>
133
+ </Tabs>
134
+ ),
135
+ };
136
+
137
+ export const WithOutlinedVariant: Story = {
138
+ name: 'With outlined variant',
139
+ parameters: {
140
+ docs: {
141
+ description: {
142
+ story:
143
+ 'Tabs can have a outlined variant with a different style.',
144
+ },
145
+ },
146
+ },
147
+ render: () => (
148
+ <Tabs defaultValue="perfil" variant="outlined" >
149
+ <TabsList>
150
+ <TabsTrigger value="perfil"> Perfil</TabsTrigger>
151
+ <TabsTrigger value="notification">Notifications</TabsTrigger>
152
+ <TabsTrigger value="configs">Settings</TabsTrigger>
153
+ </TabsList>
154
+ <TabsContent value="perfil">
155
+ <div className="mt-4 text-sm">
156
+ Disabled tabs cannot be clicked or focused.
157
+ </div>
158
+ </TabsContent>
159
+ <TabsContent value="configs">
160
+ <div className="mt-4 text-sm">This tab remains active by default.</div>
161
+ </TabsContent>
162
+ </Tabs>
163
+ ),
164
+ };
165
+
166
+ export const WithSecondaryVariant: Story = {
167
+ name: 'With secondary variant',
168
+ parameters: {
169
+ docs: {
170
+ description: {
171
+ story:
172
+ 'Tabs can have a secondary variant with a different style.',
173
+ },
174
+ },
175
+ },
176
+ render: () => (
177
+ <Tabs defaultValue="perfil" variant="secondary" >
178
+ <TabsList>
179
+ <TabsTrigger value="perfil"> Perfil</TabsTrigger>
180
+ <TabsTrigger value="notification">Notifications</TabsTrigger>
181
+ <TabsTrigger value="configs">Settings</TabsTrigger>
182
+ </TabsList>
183
+ <TabsContent value="perfil">
184
+ <div className="mt-4 text-sm">
185
+ Disabled tabs cannot be clicked or focused.
186
+ </div>
187
+ </TabsContent>
188
+ <TabsContent value="configs">
189
+ <div className="mt-4 text-sm">This tab remains active by default.</div>
190
+ </TabsContent>
191
+ </Tabs>
192
+ ),
193
+ };
194
+
195
+ export const WithSquareVariant: Story = {
196
+ name: 'With square variant',
197
+ parameters: {
198
+ docs: {
199
+ description: {
200
+ story:
201
+ 'Tabs can have a square variant with a different style.',
202
+ },
203
+ },
204
+ },
205
+ render: () => (
206
+ <Tabs defaultValue="perfil" variant="square">
207
+ <TabsList>
208
+ <TabsTrigger value="perfil">Perfil</TabsTrigger>
209
+ <TabsTrigger value="notification">Notifications</TabsTrigger>
210
+ <TabsTrigger value="configs">Settings</TabsTrigger>
211
+ </TabsList>
212
+ <TabsContent value="perfil">
213
+ <div className="mt-4 text-sm">
214
+ Disabled tabs cannot be clicked or focused.
215
+ </div>
216
+ </TabsContent>
217
+ <TabsContent value="configs">
218
+ <div className="mt-4 text-sm">This tab remains active by default.</div>
219
+ </TabsContent>
220
+ </Tabs>
221
+ ),
222
+ };
@@ -0,0 +1,113 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from './tabs';
6
+
7
+ function renderTabs(variant?: 'primary' | 'secondary') {
8
+ render(
9
+ <Tabs variant={variant}>
10
+ <TabsList>
11
+ <TabsTrigger value="tab-1">Tab 1</TabsTrigger>
12
+ <TabsTrigger value="tab-2">Tab 2</TabsTrigger>
13
+ </TabsList>
14
+ <TabsContent value="tab-1" data-testid="tab-1-content">
15
+ Tab 1 Content
16
+ </TabsContent>
17
+ <TabsContent value="tab-2" data-testid="tab-2-content">
18
+ Tab 2 Content
19
+ </TabsContent>
20
+ </Tabs>
21
+ );
22
+ }
23
+
24
+ describe('<Tabs />', () => {
25
+ const user = userEvent.setup();
26
+
27
+ it('should render the tabs component', () => {
28
+ renderTabs();
29
+
30
+ expect(screen.getByRole('tablist')).toBeInTheDocument();
31
+ });
32
+
33
+ it('should render the tab content', () => {
34
+ renderTabs();
35
+
36
+ expect(screen.getByTestId('tab-1-content')).toBeInTheDocument();
37
+ expect(screen.getByTestId('tab-2-content')).toBeInTheDocument();
38
+ });
39
+
40
+ it('should switch between tabs', async () => {
41
+ renderTabs();
42
+
43
+ await user.click(screen.getByText(/tab 1/i));
44
+ expect(screen.getByText(/tab 1 content/i)).toBeInTheDocument();
45
+ });
46
+
47
+ it('should be focusable and switch with keyboard (tab)', async () => {
48
+ renderTabs();
49
+
50
+ await user.tab();
51
+ expect(screen.getByText(/tab 1 content/i)).toBeInTheDocument();
52
+ });
53
+
54
+ it('should be focusable and switch with keyboard (shift + tab)', async () => {
55
+ renderTabs();
56
+
57
+ await user.tab();
58
+ await user.tab({ shift: true });
59
+
60
+ expect(screen.getByText(/tab 1 content/i)).toBeInTheDocument();
61
+ });
62
+
63
+ it('should be focusable and switch with keyboard (enter)', async () => {
64
+ renderTabs();
65
+
66
+ await user.tab();
67
+ await user.keyboard('{Enter}');
68
+
69
+ expect(screen.getByText(/tab 1 content/i)).toBeInTheDocument();
70
+ });
71
+
72
+ it('should be focusable and switch with keyboard (space)', async () => {
73
+ renderTabs();
74
+
75
+ await user.tab();
76
+ await user.keyboard('{Space}');
77
+
78
+ expect(screen.getByText(/tab 1 content/i)).toBeInTheDocument();
79
+ });
80
+
81
+ it('should be focusable and switch with keyboard (arrow keys)', async () => {
82
+ renderTabs();
83
+
84
+ await user.tab();
85
+ await user.keyboard('{ArrowRight}');
86
+
87
+ expect(screen.getByText(/tab 2 content/i)).toBeInTheDocument();
88
+ });
89
+
90
+ it('should apply primary variant styles by default', () => {
91
+ renderTabs();
92
+
93
+ const tabsRoot = screen.getByRole('tablist').parentElement;
94
+ expect(tabsRoot).toHaveAttribute('data-variant', 'primary');
95
+ });
96
+
97
+ it('should apply secondary variant styles when variant is secondary', () => {
98
+ renderTabs('secondary');
99
+
100
+ const tabsRoot = screen.getByRole('tablist').parentElement;
101
+ expect(tabsRoot).toHaveAttribute('data-variant', 'secondary');
102
+ });
103
+
104
+ it('should match snapshot', () => {
105
+ const { container } = render(<Tabs />);
106
+ expect(container).toMatchSnapshot();
107
+ });
108
+
109
+ it('should match snapshot with secondary variant', () => {
110
+ const { container } = render(<Tabs variant="secondary" />);
111
+ expect(container).toMatchSnapshot();
112
+ });
113
+ });
@@ -0,0 +1,102 @@
1
+ import * as React from 'react';
2
+
3
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
4
+
5
+ import { cn } from '@/utils';
6
+
7
+ interface TabsProps extends React.ComponentProps<typeof TabsPrimitive.Root> {
8
+ variant?: 'primary' | 'secondary' | 'square' | 'outlined';
9
+ }
10
+
11
+ function Tabs({ className, variant = 'primary', ...props }: TabsProps) {
12
+ return (
13
+ <TabsPrimitive.Root
14
+ data-slot="tabs"
15
+ data-variant={variant}
16
+ className={cn('flex flex-col gap-2 group', className)}
17
+ {...props}
18
+ />
19
+ );
20
+ }
21
+
22
+ function TabsList({
23
+ className,
24
+ ...props
25
+ }: React.ComponentProps<typeof TabsPrimitive.List>) {
26
+ return (
27
+ <TabsPrimitive.List
28
+ data-slot="tabs-list"
29
+ className={cn(
30
+ 'w-full flex',
31
+ 'group-data-[variant=outlined]:bg-gray-50',
32
+ 'group-data-[variant=outlined]:rounded-lg group-data-[variant=outlined]:border group-data-[variant=outlined]:border-gray-200',
33
+ 'group-data-[variant=secondary]:bg-gray-50',
34
+ 'group-data-[variant=secondary]:p-1 group-data-[variant=secondary]:gap-1',
35
+ 'group-data-[variant=secondary]:rounded-lg group-data-[variant=secondary]:border group-data-[variant=secondary]:border-gray-200',
36
+ className
37
+ )}
38
+ {...props}
39
+ />
40
+ );
41
+ }
42
+
43
+ function TabsTrigger({
44
+ className,
45
+ ...props
46
+ }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
47
+ return (
48
+ <TabsPrimitive.Trigger
49
+ data-slot="tabs-trigger"
50
+ className={cn(
51
+ 'border border-gray-200 data-[state=active]:border-b-primary data-[state=active]:border-b-2',
52
+ 'bg-gray-100 text-gray-500 data-[state=active]:bg-white data-[state=active]:text-primary',
53
+ 'cursor-pointer flex flex-1 items-center justify-center gap-2 p-3 text-md font-medium whitespace-nowrap transition-[color,box-shadow]',
54
+ 'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:outline-1',
55
+ 'disabled:pointer-events-none disabled:opacity-50',
56
+ 'hover:bg-gray-50',
57
+ '[&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
58
+ 'first:rounded-tl-lg last:rounded-tr-lg',
59
+ 'min-w-fit',
60
+
61
+ 'group-data-[variant=secondary]:text-gray-700',
62
+ 'group-data-[variant=secondary]:rounded-sm',
63
+ 'group-data-[variant=secondary]:py-2 group-data-[variant=secondary]:px-3',
64
+ 'group-data-[variant=secondary]:border-0 group-data-[variant=secondary]:bg-transparent',
65
+ 'group-data-[variant=secondary]:data-[state=active]:bg-white group-data-[variant=secondary]:data-[state=active]:text-gray-700 group-data-[variant=secondary]:data-[state=active]:border-b-0',
66
+ 'group-data-[variant=secondary]:data-[state=active]:shadow-sm',
67
+ 'group-data-[variant=secondary]:bg-transparent',
68
+ 'group-data-[variant=secondary]:hover:bg-white group-data-[variant=secondary]:hover:shadow-sm',
69
+
70
+ 'group-data-[variant=outlined]:text-gray-700',
71
+ 'group-data-[variant=outlined]:rounded-sm',
72
+ 'group-data-[variant=outlined]:border-0 group-data-[variant=outlined]:bg-transparent',
73
+ 'group-data-[variant=outlined]:data-[state=active]:bg-white group-data-[variant=outlined]:data-[state=active]:text-gray-700 group-data-[variant=outlined]:data-[state=active]:border-b-0',
74
+ 'group-data-[variant=outlined]:data-[state=active]:shadow-sm',
75
+ 'group-data-[variant=outlined]:bg-transparent',
76
+
77
+ 'group-data-[variant=square]:rounded-none!',
78
+ 'group-data-[variant=square]:text-sm! group-data-[variant=square]:leading-none!',
79
+ 'group-data-[variant=square]:p-3!',
80
+ 'group-data-[variant=square]:data-[state=active]:border-t-0! group-data-[variant=square]:data-[state=active]:border-l-0! group-data-[variant=square]:data-[state=active]:border-r-0! ',
81
+ className
82
+ )}
83
+ {...props}
84
+ />
85
+ );
86
+ }
87
+
88
+ function TabsContent({
89
+ className,
90
+ ...props
91
+ }: React.ComponentProps<typeof TabsPrimitive.Content>) {
92
+ return (
93
+ <TabsPrimitive.Content
94
+ data-slot="tabs-content"
95
+ className={cn('flex-1 outline-none', className)}
96
+ {...props}
97
+ />
98
+ );
99
+ }
100
+
101
+ export type { TabsProps };
102
+ export { Tabs, TabsContent, TabsList, TabsTrigger };
@@ -0,0 +1 @@
1
+ export * from './toggle-group';
@@ -0,0 +1,117 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { ToggleGroup, ToggleGroupItem } from './toggle-group';
4
+
5
+ const meta: Meta<typeof ToggleGroup> = {
6
+ title: 'Components/Data Entry/ToggleGroup',
7
+ component: ToggleGroup,
8
+ subcomponents: { ToggleGroupItem },
9
+ tags: [ 'autodocs' ],
10
+ parameters: {
11
+ layout: 'centered',
12
+ docs: {
13
+ description: {
14
+ component:
15
+ 'Button group component (toggle) based on Radix UI. Ideal for selecting one or multiple options. Supports variations in style and size.',
16
+ },
17
+ },
18
+ },
19
+ argTypes: {
20
+ type: {
21
+ control: 'select',
22
+ options: [ 'single', 'multiple' ],
23
+ description: 'Selection type: single or multiple.',
24
+ defaultValue: 'single',
25
+ },
26
+ size: {
27
+ control: 'select',
28
+ options: [ 'sm', 'default', 'lg' ],
29
+ description: 'Button size.',
30
+ },
31
+ variant: {
32
+ control: 'select',
33
+ options: [ 'default', 'outline' ],
34
+ description: 'Button style.',
35
+ },
36
+ disabled: {
37
+ control: 'boolean',
38
+ description: 'Disable the entire group.',
39
+ },
40
+ orientation: {
41
+ control: 'select',
42
+ options: [ 'horizontal', 'vertical' ],
43
+ description: 'Group orientation.',
44
+ },
45
+ value: {
46
+ control: 'text',
47
+ description: 'Selected value (controlled).',
48
+ },
49
+ onValueChange: {
50
+ action: 'onValueChange',
51
+ description: 'Callback when a value is selected.',
52
+ },
53
+ },
54
+ };
55
+
56
+ export default meta;
57
+
58
+ type Story = StoryObj<typeof ToggleGroup>;
59
+
60
+ export const Default: Story = {
61
+ args: {
62
+ type: 'single',
63
+ size: 'default',
64
+ variant: 'default',
65
+ orientation: 'horizontal',
66
+ children: (
67
+ <>
68
+ <ToggleGroupItem value="left">Left</ToggleGroupItem>
69
+ <ToggleGroupItem value="center">Center</ToggleGroupItem>
70
+ <ToggleGroupItem value="right">Right</ToggleGroupItem>
71
+ </>
72
+ ),
73
+ },
74
+ };
75
+
76
+ export const Disabled: Story = {
77
+ args: {
78
+ ...Default.args,
79
+ disabled: true,
80
+ },
81
+ };
82
+
83
+ export const LargeSize: Story = {
84
+ args: {
85
+ ...Default.args,
86
+ size: 'lg',
87
+ },
88
+ };
89
+
90
+ export const MultipleSelection: Story = {
91
+ args: {
92
+ type: 'multiple',
93
+ size: 'default',
94
+ variant: 'default',
95
+ children: (
96
+ <>
97
+ <ToggleGroupItem value="bold">Bold</ToggleGroupItem>
98
+ <ToggleGroupItem value="italic">Italic</ToggleGroupItem>
99
+ <ToggleGroupItem value="underline">Underline</ToggleGroupItem>
100
+ </>
101
+ ),
102
+ },
103
+ };
104
+
105
+ export const OutlineVariant: Story = {
106
+ args: {
107
+ ...Default.args,
108
+ variant: 'outline',
109
+ },
110
+ };
111
+
112
+ export const VerticalOrientation: Story = {
113
+ args: {
114
+ ...Default.args,
115
+ orientation: 'vertical',
116
+ },
117
+ };
@@ -0,0 +1,100 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ import { ToggleGroup, ToggleGroupItem } from './toggle-group';
6
+
7
+ function renderToggleGroup(
8
+ props: React.ComponentProps<typeof ToggleGroup> & {
9
+ items?: string[];
10
+ }
11
+ ) {
12
+ const { items = [ 'one', 'two' ], ...rest } = props;
13
+
14
+ return render(
15
+ <ToggleGroup {...rest} data-testid="toggle-group">
16
+ {items.map((item, i) => (
17
+ <ToggleGroupItem key={item} value={item} data-testid={`toggle-item-${i}`}>
18
+ {item}
19
+ </ToggleGroupItem>
20
+ ))}
21
+ </ToggleGroup>
22
+ );
23
+ }
24
+
25
+ describe('<ToggleGroup />', () => {
26
+ it('renders the toggle group and items', () => {
27
+ renderToggleGroup({ type: 'single' });
28
+ expect(screen.getByTestId('toggle-group')).toBeInTheDocument();
29
+ expect(screen.getByTestId('toggle-item-0')).toBeInTheDocument();
30
+ expect(screen.getByTestId('toggle-item-1')).toBeInTheDocument();
31
+ });
32
+
33
+ it('selects a single item and toggles state', async () => {
34
+ const { getByTestId } = renderToggleGroup({
35
+ type: 'single',
36
+ defaultValue: 'B',
37
+ items: [ 'A', 'B', 'C' ],
38
+ });
39
+
40
+ const itemA = getByTestId('toggle-item-0');
41
+ const itemB = getByTestId('toggle-item-1');
42
+ const itemC = getByTestId('toggle-item-2');
43
+
44
+ expect(itemB).toHaveAttribute('data-state', 'on');
45
+ expect(itemA).not.toHaveAttribute('data-state', 'on');
46
+ expect(itemC).not.toHaveAttribute('data-state', 'on');
47
+
48
+ await userEvent.click(itemC);
49
+ expect(itemC).toHaveAttribute('data-state', 'on');
50
+ expect(itemB).not.toHaveAttribute('data-state', 'on');
51
+ });
52
+ it('selects multiple items when type is multiple', async () => {
53
+ const user = userEvent.setup();
54
+ renderToggleGroup({
55
+ type: 'multiple',
56
+ defaultValue: [ 'one' ],
57
+ });
58
+
59
+ const item0 = screen.getByTestId('toggle-item-0');
60
+ const item1 = screen.getByTestId('toggle-item-1');
61
+
62
+ await user.click(item1);
63
+ expect(item0.getAttribute('aria-pressed')).toBe('true');
64
+ expect(item1.getAttribute('aria-pressed')).toBe('true');
65
+ });
66
+
67
+ it('applies variant and size via context', () => {
68
+ renderToggleGroup({ type: 'single', variant: 'outline', size: 'lg' });
69
+
70
+ const item0 = screen.getByTestId('toggle-item-0');
71
+ expect(item0.dataset.variant).toBe('outline');
72
+ expect(item0.dataset.size).toBe('lg');
73
+ });
74
+
75
+ it('is keyboard accessible and allows arrow key navigation', async () => {
76
+ const user = userEvent.setup();
77
+ renderToggleGroup({ type: 'single' });
78
+
79
+ const item0 = screen.getByTestId('toggle-item-0');
80
+ const item1 = screen.getByTestId('toggle-item-1');
81
+
82
+ await user.tab();
83
+ expect(item0).toHaveFocus();
84
+
85
+ await user.keyboard('[ArrowRight]');
86
+ expect(item1).toHaveFocus();
87
+ });
88
+
89
+ it('accepts and applies extra className', () => {
90
+ renderToggleGroup({ type: 'single', className: 'custom-class' });
91
+
92
+ const group = screen.getByTestId('toggle-group');
93
+ expect(group.className).toContain('custom-class');
94
+ });
95
+
96
+ it('should match snapshot', () => {
97
+ const { container } = renderToggleGroup({ type: 'single' });
98
+ expect(container).toMatchSnapshot();
99
+ });
100
+ });