@fabio.caffarello/react-design-system 1.7.0 → 1.8.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 (460) hide show
  1. package/README.md +48 -3
  2. package/dist/docs/components/ComponentStatusTable.d.ts +11 -0
  3. package/dist/ui/atoms/Accordion/Accordion.d.ts +34 -0
  4. package/dist/ui/atoms/Accordion/Accordion.stories.d.ts +11 -0
  5. package/dist/ui/atoms/Accordion/Accordion.test.d.ts +1 -0
  6. package/dist/ui/atoms/Accordion/index.d.ts +2 -0
  7. package/dist/ui/atoms/Avatar/Avatar.d.ts +30 -0
  8. package/dist/ui/atoms/Avatar/Avatar.stories.d.ts +13 -0
  9. package/dist/ui/atoms/Avatar/Avatar.test.d.ts +1 -0
  10. package/dist/ui/atoms/Avatar/AvatarGroup.d.ts +26 -0
  11. package/dist/ui/atoms/Avatar/index.d.ts +9 -0
  12. package/dist/ui/atoms/Badge/Badge.d.ts +14 -6
  13. package/dist/ui/atoms/Badge/Badge.stories.d.ts +8 -9
  14. package/dist/ui/atoms/BoxWrapper/BoxWrapper.d.ts +3 -3
  15. package/dist/ui/atoms/BoxWrapper/BoxWrapper.test.d.ts +1 -0
  16. package/dist/ui/atoms/Button/Button.d.ts +32 -10
  17. package/dist/ui/atoms/Button/Button.stories.d.ts +7 -0
  18. package/dist/ui/atoms/Button/Button.test.d.ts +1 -0
  19. package/dist/ui/atoms/Checkbox/Checkbox.d.ts +2 -1
  20. package/dist/ui/atoms/Collapsible/Collapsible.stories.d.ts +2 -0
  21. package/dist/ui/atoms/Info/Info.d.ts +2 -3
  22. package/dist/ui/atoms/Info/Info.test.d.ts +1 -0
  23. package/dist/ui/atoms/Input/Input.d.ts +14 -4
  24. package/dist/ui/atoms/Input/Input.stories.d.ts +6 -0
  25. package/dist/ui/atoms/Popover/Popover.d.ts +35 -0
  26. package/dist/ui/atoms/Popover/Popover.stories.d.ts +11 -0
  27. package/dist/ui/atoms/Popover/Popover.test.d.ts +1 -0
  28. package/dist/ui/atoms/Popover/index.d.ts +2 -0
  29. package/dist/ui/atoms/Progress/Progress.d.ts +33 -0
  30. package/dist/ui/atoms/Progress/Progress.stories.d.ts +12 -0
  31. package/dist/ui/atoms/Progress/Progress.test.d.ts +1 -0
  32. package/dist/ui/atoms/Select/Select.d.ts +18 -6
  33. package/dist/ui/atoms/Select/Select.stories.d.ts +11 -8
  34. package/dist/ui/atoms/Separator/Separator.d.ts +23 -0
  35. package/dist/ui/atoms/Separator/Separator.stories.d.ts +10 -0
  36. package/dist/ui/atoms/Separator/Separator.test.d.ts +1 -0
  37. package/dist/ui/atoms/Separator/index.d.ts +2 -0
  38. package/dist/ui/atoms/Skeleton/Skeleton.d.ts +1 -1
  39. package/dist/ui/atoms/Skeleton/Skeleton.stories.d.ts +24 -0
  40. package/dist/ui/atoms/Slider/Slider.d.ts +45 -0
  41. package/dist/ui/atoms/Slider/Slider.stories.d.ts +13 -0
  42. package/dist/ui/atoms/Slider/Slider.test.d.ts +1 -0
  43. package/dist/ui/atoms/Slider/index.d.ts +2 -0
  44. package/dist/ui/atoms/Spinner/Spinner.d.ts +22 -0
  45. package/dist/ui/atoms/Spinner/Spinner.stories.d.ts +9 -0
  46. package/dist/ui/atoms/Spinner/Spinner.test.d.ts +1 -0
  47. package/dist/ui/atoms/Switch/Switch.d.ts +28 -0
  48. package/dist/ui/atoms/Switch/Switch.stories.d.ts +11 -0
  49. package/dist/ui/atoms/Switch/Switch.test.d.ts +1 -0
  50. package/dist/ui/atoms/Switch/index.d.ts +2 -0
  51. package/dist/ui/atoms/Tooltip/Tooltip.d.ts +2 -1
  52. package/dist/ui/atoms/Tooltip/Tooltip.stories.d.ts +17 -0
  53. package/dist/ui/atoms/index.d.ts +20 -3
  54. package/dist/ui/index.d.ts +6 -1
  55. package/dist/ui/molecules/Card/Card.d.ts +6 -2
  56. package/dist/ui/molecules/Card/Card.stories.d.ts +2 -0
  57. package/dist/ui/molecules/ColorPicker/ColorPicker.d.ts +28 -0
  58. package/dist/ui/molecules/ColorPicker/ColorPicker.stories.d.ts +12 -0
  59. package/dist/ui/molecules/ColorPicker/ColorPicker.test.d.ts +1 -0
  60. package/dist/ui/molecules/ColorPicker/index.d.ts +2 -0
  61. package/dist/ui/molecules/DatePicker/DatePicker.d.ts +74 -0
  62. package/dist/ui/molecules/DatePicker/DatePicker.stories.d.ts +12 -0
  63. package/dist/ui/molecules/DatePicker/DatePicker.test.d.ts +1 -0
  64. package/dist/ui/molecules/DatePicker/DatePickerCalendar.d.ts +6 -0
  65. package/dist/ui/molecules/DatePicker/DatePickerContext.d.ts +28 -0
  66. package/dist/ui/molecules/DatePicker/DatePickerInput.d.ts +9 -0
  67. package/dist/ui/molecules/DatePicker/DatePickerProvider.d.ts +23 -0
  68. package/dist/ui/molecules/DatePicker/index.d.ts +14 -0
  69. package/dist/ui/molecules/Dropdown/Dropdown.d.ts +2 -1
  70. package/dist/ui/molecules/Dropdown/Dropdown.stories.d.ts +13 -0
  71. package/dist/ui/molecules/EmptyState/EmptyState.stories.d.ts +22 -0
  72. package/dist/ui/molecules/FileUpload/FileUpload.d.ts +37 -0
  73. package/dist/ui/molecules/FileUpload/FileUpload.stories.d.ts +12 -0
  74. package/dist/ui/molecules/FileUpload/FileUpload.test.d.ts +1 -0
  75. package/dist/ui/molecules/FileUpload/index.d.ts +2 -0
  76. package/dist/ui/molecules/Form/Form.d.ts +29 -4
  77. package/dist/ui/molecules/Form/Form.stories.d.ts +2 -0
  78. package/dist/ui/molecules/Form/FormContext.d.ts +17 -0
  79. package/dist/ui/molecules/Form/FormField.d.ts +36 -0
  80. package/dist/ui/molecules/Form/FormProvider.d.ts +14 -0
  81. package/dist/ui/molecules/Form/index.d.ts +13 -0
  82. package/dist/ui/molecules/Form/useFormFieldArray.d.ts +28 -0
  83. package/dist/ui/molecules/InputWithLabel/InputWithLabel.test.d.ts +1 -0
  84. package/dist/ui/molecules/Rating/Rating.d.ts +33 -0
  85. package/dist/ui/molecules/Rating/Rating.stories.d.ts +13 -0
  86. package/dist/ui/molecules/Rating/Rating.test.d.ts +1 -0
  87. package/dist/ui/molecules/Rating/index.d.ts +2 -0
  88. package/dist/ui/molecules/SearchInput/SearchInput.d.ts +24 -0
  89. package/dist/ui/molecules/SearchInput/SearchInput.stories.d.ts +10 -0
  90. package/dist/ui/molecules/SearchInput/SearchInput.test.d.ts +1 -0
  91. package/dist/ui/molecules/SearchInput/index.d.ts +2 -0
  92. package/dist/ui/molecules/SidebarHeader/SidebarHeader.test.d.ts +1 -0
  93. package/dist/ui/molecules/TableActions/TableActions.d.ts +31 -0
  94. package/dist/ui/molecules/TableActions/TableActions.stories.d.ts +7 -0
  95. package/dist/ui/molecules/TableActions/TableActions.test.d.ts +1 -0
  96. package/dist/ui/molecules/TableFilters/TableFilters.d.ts +37 -0
  97. package/dist/ui/molecules/TableFilters/TableFilters.stories.d.ts +7 -0
  98. package/dist/ui/molecules/TableFilters/TableFilters.test.d.ts +1 -0
  99. package/dist/ui/molecules/TablePagination/TablePagination.d.ts +29 -0
  100. package/dist/ui/molecules/TablePagination/TablePagination.stories.d.ts +8 -0
  101. package/dist/ui/molecules/TablePagination/TablePagination.test.d.ts +1 -0
  102. package/dist/ui/molecules/Tabs/Tabs.d.ts +15 -0
  103. package/dist/ui/molecules/Tabs/Tabs.stories.d.ts +10 -0
  104. package/dist/ui/molecules/Tabs/Tabs.test.d.ts +1 -0
  105. package/dist/ui/molecules/Tabs/TabsContent.d.ts +14 -0
  106. package/dist/ui/molecules/Tabs/TabsContext.d.ts +18 -0
  107. package/dist/ui/molecules/Tabs/TabsList.d.ts +12 -0
  108. package/dist/ui/molecules/Tabs/TabsProvider.d.ts +16 -0
  109. package/dist/ui/molecules/Tabs/TabsTrigger.d.ts +13 -0
  110. package/dist/ui/molecules/Tabs/index.d.ts +17 -0
  111. package/dist/ui/molecules/TimePicker/TimePicker.d.ts +29 -0
  112. package/dist/ui/molecules/TimePicker/TimePicker.stories.d.ts +12 -0
  113. package/dist/ui/molecules/TimePicker/TimePicker.test.d.ts +1 -0
  114. package/dist/ui/molecules/TimePicker/index.d.ts +2 -0
  115. package/dist/ui/molecules/index.d.ts +13 -5
  116. package/dist/ui/organisms/CommandPalette/CommandPalette.d.ts +37 -0
  117. package/dist/ui/organisms/CommandPalette/CommandPalette.stories.d.ts +11 -0
  118. package/dist/ui/organisms/CommandPalette/CommandPalette.test.d.ts +1 -0
  119. package/dist/ui/organisms/CommandPalette/index.d.ts +2 -0
  120. package/dist/ui/organisms/DataGrid/DataGrid.d.ts +84 -0
  121. package/dist/ui/organisms/DataGrid/DataGrid.stories.d.ts +14 -0
  122. package/dist/ui/organisms/DataGrid/DataGrid.test.d.ts +1 -0
  123. package/dist/ui/organisms/DataGrid/index.d.ts +2 -0
  124. package/dist/ui/organisms/Dialog/AlertDialog.d.ts +34 -0
  125. package/dist/ui/organisms/Dialog/Dialog.d.ts +58 -0
  126. package/dist/ui/organisms/Dialog/Dialog.stories.d.ts +13 -0
  127. package/dist/ui/organisms/Dialog/Dialog.test.d.ts +1 -0
  128. package/dist/ui/organisms/Dialog/DialogClose.d.ts +8 -0
  129. package/dist/ui/organisms/Dialog/DialogContent.d.ts +8 -0
  130. package/dist/ui/organisms/Dialog/DialogContext.d.ts +10 -0
  131. package/dist/ui/organisms/Dialog/DialogDescription.d.ts +4 -0
  132. package/dist/ui/organisms/Dialog/DialogFooter.d.ts +5 -0
  133. package/dist/ui/organisms/Dialog/DialogHeader.d.ts +5 -0
  134. package/dist/ui/organisms/Dialog/DialogProvider.d.ts +10 -0
  135. package/dist/ui/organisms/Dialog/DialogTitle.d.ts +5 -0
  136. package/dist/ui/organisms/Dialog/DialogTrigger.d.ts +6 -0
  137. package/dist/ui/organisms/Dialog/index.d.ts +22 -0
  138. package/dist/ui/organisms/Sidebar/Sidebar.d.ts +7 -4
  139. package/dist/ui/organisms/Sidebar/SidebarGroup/SidebarGroup.d.ts +27 -0
  140. package/dist/ui/organisms/Sidebar/SidebarGroup/SidebarGroup.stories.d.ts +11 -0
  141. package/dist/ui/organisms/Sidebar/SidebarGroup/SidebarGroup.test.d.ts +1 -0
  142. package/dist/ui/organisms/Sidebar/SidebarHeader/SidebarHeader.d.ts +19 -0
  143. package/dist/ui/organisms/Sidebar/SidebarHeader/SidebarHeader.test.d.ts +1 -0
  144. package/dist/ui/organisms/Sidebar/SidebarItem/SidebarItem.d.ts +23 -0
  145. package/dist/ui/organisms/Sidebar/SidebarItem/SidebarItem.stories.d.ts +10 -0
  146. package/dist/ui/organisms/Sidebar/SidebarItem/SidebarItem.test.d.ts +1 -0
  147. package/dist/ui/organisms/Sidebar/index.d.ts +8 -0
  148. package/dist/ui/organisms/Stepper/Stepper.d.ts +40 -0
  149. package/dist/ui/organisms/Stepper/Stepper.stories.d.ts +12 -0
  150. package/dist/ui/organisms/Stepper/Stepper.test.d.ts +1 -0
  151. package/dist/ui/organisms/Stepper/index.d.ts +2 -0
  152. package/dist/ui/organisms/Table/Table.d.ts +84 -16
  153. package/dist/ui/organisms/Table/Table.stories.d.ts +15 -0
  154. package/dist/ui/organisms/Table/TableActions/TableActions.d.ts +31 -0
  155. package/dist/ui/organisms/Table/TableActions/TableActions.stories.d.ts +7 -0
  156. package/dist/ui/organisms/Table/TableActions/TableActions.test.d.ts +1 -0
  157. package/dist/ui/organisms/Table/TableActions.d.ts +13 -0
  158. package/dist/ui/organisms/Table/TableBody.d.ts +12 -0
  159. package/dist/ui/organisms/Table/TableCell.d.ts +14 -0
  160. package/dist/ui/organisms/Table/TableContext.d.ts +75 -0
  161. package/dist/ui/organisms/Table/TableEmptyState.d.ts +11 -0
  162. package/dist/ui/organisms/Table/TableFilters/TableFilters.d.ts +37 -0
  163. package/dist/ui/organisms/Table/TableFilters/TableFilters.stories.d.ts +7 -0
  164. package/dist/ui/organisms/Table/TableFilters/TableFilters.test.d.ts +1 -0
  165. package/dist/ui/organisms/Table/TableFilters.d.ts +12 -0
  166. package/dist/ui/organisms/Table/TableHeader.d.ts +10 -0
  167. package/dist/ui/organisms/Table/TableHeaderCell.d.ts +18 -0
  168. package/dist/ui/organisms/Table/TableHeaderRow.d.ts +10 -0
  169. package/dist/ui/organisms/Table/TablePagination/TablePagination.d.ts +29 -0
  170. package/dist/ui/organisms/Table/TablePagination/TablePagination.stories.d.ts +8 -0
  171. package/dist/ui/organisms/Table/TablePagination/TablePagination.test.d.ts +1 -0
  172. package/dist/ui/organisms/Table/TablePagination.d.ts +14 -0
  173. package/dist/ui/organisms/Table/TableProvider.d.ts +55 -0
  174. package/dist/ui/organisms/Table/TableRow.d.ts +14 -0
  175. package/dist/ui/organisms/Table/TableTypes.d.ts +8 -0
  176. package/dist/ui/organisms/Table/index.d.ts +30 -0
  177. package/dist/ui/organisms/Table/useColumnResizing.d.ts +39 -0
  178. package/dist/ui/organisms/Table/useVirtualScrolling.d.ts +35 -0
  179. package/dist/ui/organisms/Timeline/Timeline.d.ts +34 -0
  180. package/dist/ui/organisms/Timeline/Timeline.stories.d.ts +12 -0
  181. package/dist/ui/organisms/Timeline/Timeline.test.d.ts +1 -0
  182. package/dist/ui/organisms/Timeline/index.d.ts +2 -0
  183. package/dist/ui/organisms/Toast/Toast.d.ts +8 -0
  184. package/dist/ui/organisms/Toast/Toast.stories.d.ts +14 -0
  185. package/dist/ui/organisms/Toast/Toast.test.d.ts +1 -0
  186. package/dist/ui/organisms/Toast/ToastContainer.d.ts +5 -0
  187. package/dist/ui/organisms/Toast/ToastContext.d.ts +21 -0
  188. package/dist/ui/organisms/Toast/ToastProvider.d.ts +7 -0
  189. package/dist/ui/organisms/Toast/index.d.ts +15 -0
  190. package/dist/ui/organisms/Toast/useToast.d.ts +35 -0
  191. package/dist/ui/organisms/index.d.ts +12 -2
  192. package/dist/ui/providers/AdvancedThemeProvider.d.ts +52 -0
  193. package/dist/ui/providers/index.d.ts +9 -0
  194. package/dist/ui/themes/ThemeBuilder.d.ts +28 -0
  195. package/dist/ui/themes/ThemeRegistry.d.ts +55 -0
  196. package/dist/ui/themes/index.d.ts +9 -0
  197. package/dist/ui/themes/types.d.ts +48 -0
  198. package/dist/ui/themes/utils.d.ts +21 -0
  199. package/dist/ui/tokens/TokenVisualizations.d.ts +41 -0
  200. package/dist/ui/tokens/animations.d.ts +65 -0
  201. package/dist/ui/tokens/borders.d.ts +61 -0
  202. package/dist/ui/tokens/gradients.d.ts +55 -0
  203. package/dist/ui/tokens/index.d.ts +31 -0
  204. package/dist/ui/tokens/opacity.d.ts +51 -0
  205. package/dist/ui/tokens/radius.d.ts +45 -0
  206. package/dist/ui/tokens/shadows.d.ts +42 -0
  207. package/dist/ui/tokens/themes/dark.d.ts +26 -26
  208. package/dist/ui/tokens/themes/light.d.ts +26 -26
  209. package/dist/ui/tokens/tokens.factory.d.ts +42 -0
  210. package/dist/ui/tokens/z-index.d.ts +44 -0
  211. package/dist/ui/utils/index.d.ts +6 -0
  212. package/package.json +50 -6
  213. package/src/docs/Accessibility.mdx +402 -0
  214. package/src/docs/BestPractices.mdx +315 -0
  215. package/src/docs/ComponentComposition.mdx +381 -0
  216. package/src/docs/ComponentStatus.mdx +177 -0
  217. package/src/docs/DesignSystem.mdx +121 -0
  218. package/src/docs/GettingStarted.mdx +284 -0
  219. package/src/docs/MigrationGuide.mdx +297 -0
  220. package/src/docs/Performance.mdx +206 -0
  221. package/src/docs/components/ComponentStatusTable.tsx +184 -0
  222. package/src/setupTests.ts +32 -0
  223. package/src/ui/atoms/Accordion/Accordion.stories.tsx +147 -0
  224. package/src/ui/atoms/Accordion/Accordion.test.tsx +86 -0
  225. package/src/ui/atoms/Accordion/Accordion.tsx +147 -0
  226. package/src/ui/atoms/Accordion/index.ts +2 -0
  227. package/src/ui/atoms/Avatar/Avatar.stories.tsx +226 -0
  228. package/src/ui/atoms/Avatar/Avatar.test.tsx +233 -0
  229. package/src/ui/atoms/Avatar/Avatar.tsx +128 -0
  230. package/src/ui/atoms/Avatar/AvatarGroup.tsx +96 -0
  231. package/src/ui/atoms/Avatar/index.ts +11 -0
  232. package/src/ui/atoms/Badge/Badge.stories.tsx +65 -56
  233. package/src/ui/atoms/Badge/Badge.test.tsx +27 -50
  234. package/src/ui/atoms/Badge/Badge.tsx +70 -27
  235. package/src/ui/atoms/BoxWrapper/BoxWrapper.stories.tsx +1 -1
  236. package/src/ui/atoms/BoxWrapper/BoxWrapper.test.tsx +27 -0
  237. package/src/ui/atoms/BoxWrapper/BoxWrapper.tsx +5 -2
  238. package/src/ui/atoms/Button/Button.stories.tsx +130 -1
  239. package/src/ui/atoms/Button/Button.test.tsx +233 -0
  240. package/src/ui/atoms/Button/Button.tsx +160 -53
  241. package/src/ui/atoms/Checkbox/Checkbox.tsx +14 -1
  242. package/src/ui/atoms/Collapsible/Collapsible.stories.tsx +47 -1
  243. package/src/ui/atoms/Collapsible/Collapsible.test.tsx +36 -24
  244. package/src/ui/atoms/Collapsible/Collapsible.tsx +9 -1
  245. package/src/ui/atoms/ErrorMessage/ErrorMessage.stories.tsx +1 -1
  246. package/src/ui/atoms/Info/Info.stories.tsx +1 -1
  247. package/src/ui/atoms/Info/Info.test.tsx +45 -0
  248. package/src/ui/atoms/Info/Info.tsx +2 -2
  249. package/src/ui/atoms/Input/Input.stories.tsx +80 -0
  250. package/src/ui/atoms/Input/Input.test.tsx +190 -36
  251. package/src/ui/atoms/Input/Input.tsx +144 -25
  252. package/src/ui/atoms/Label/Label.stories.tsx +1 -1
  253. package/src/ui/atoms/NavLink/NavLink.stories.tsx +1 -1
  254. package/src/ui/atoms/Popover/Popover.stories.tsx +157 -0
  255. package/src/ui/atoms/Popover/Popover.test.tsx +80 -0
  256. package/src/ui/atoms/Popover/Popover.tsx +256 -0
  257. package/src/ui/atoms/Popover/index.ts +2 -0
  258. package/src/ui/atoms/Progress/Progress.css +17 -0
  259. package/src/ui/atoms/Progress/Progress.stories.tsx +170 -0
  260. package/src/ui/atoms/Progress/Progress.test.tsx +134 -0
  261. package/src/ui/atoms/Progress/Progress.tsx +138 -0
  262. package/src/ui/atoms/Radio/Radio.tsx +1 -1
  263. package/src/ui/atoms/Select/Select.stories.tsx +93 -58
  264. package/src/ui/atoms/Select/Select.test.tsx +162 -46
  265. package/src/ui/atoms/Select/Select.tsx +142 -44
  266. package/src/ui/atoms/Separator/Separator.stories.tsx +88 -0
  267. package/src/ui/atoms/Separator/Separator.test.tsx +34 -0
  268. package/src/ui/atoms/Separator/Separator.tsx +81 -0
  269. package/src/ui/atoms/Separator/index.ts +2 -0
  270. package/src/ui/atoms/Skeleton/Skeleton.stories.tsx +62 -0
  271. package/src/ui/atoms/Skeleton/Skeleton.tsx +19 -2
  272. package/src/ui/atoms/Slider/Slider.stories.tsx +205 -0
  273. package/src/ui/atoms/Slider/Slider.test.tsx +53 -0
  274. package/src/ui/atoms/Slider/Slider.tsx +307 -0
  275. package/src/ui/atoms/Slider/index.ts +2 -0
  276. package/src/ui/atoms/Spinner/Spinner.stories.tsx +56 -0
  277. package/src/ui/atoms/Spinner/Spinner.test.tsx +35 -0
  278. package/src/ui/atoms/Spinner/Spinner.tsx +88 -0
  279. package/src/ui/atoms/Switch/Switch.stories.tsx +182 -0
  280. package/src/ui/atoms/Switch/Switch.test.tsx +90 -0
  281. package/src/ui/atoms/Switch/Switch.tsx +181 -0
  282. package/src/ui/atoms/Switch/index.ts +2 -0
  283. package/src/ui/atoms/Text/Text.stories.tsx +1 -1
  284. package/src/ui/atoms/Text/Text.test.tsx +48 -32
  285. package/src/ui/atoms/Textarea/Textarea.stories.tsx +1 -1
  286. package/src/ui/atoms/Tooltip/Tooltip.stories.tsx +44 -0
  287. package/src/ui/atoms/Tooltip/Tooltip.tsx +94 -6
  288. package/src/ui/atoms/index.ts +27 -4
  289. package/src/ui/index.ts +6 -1
  290. package/src/ui/molecules/Breadcrumb/Breadcrumb.stories.tsx +1 -1
  291. package/src/ui/molecules/Breadcrumb/Breadcrumb.tsx +1 -1
  292. package/src/ui/molecules/Card/Card.stories.tsx +49 -1
  293. package/src/ui/molecules/Card/Card.tsx +40 -5
  294. package/src/ui/molecules/ColorPicker/ColorPicker.stories.tsx +156 -0
  295. package/src/ui/molecules/ColorPicker/ColorPicker.test.tsx +47 -0
  296. package/src/ui/molecules/ColorPicker/ColorPicker.tsx +271 -0
  297. package/src/ui/molecules/ColorPicker/index.ts +2 -0
  298. package/src/ui/molecules/DatePicker/DatePicker.mdx +150 -0
  299. package/src/ui/molecules/DatePicker/DatePicker.stories.tsx +188 -0
  300. package/src/ui/molecules/DatePicker/DatePicker.test.tsx +381 -0
  301. package/src/ui/molecules/DatePicker/DatePicker.tsx +231 -0
  302. package/src/ui/molecules/DatePicker/DatePickerCalendar.tsx +277 -0
  303. package/src/ui/molecules/DatePicker/DatePickerContext.tsx +39 -0
  304. package/src/ui/molecules/DatePicker/DatePickerInput.tsx +147 -0
  305. package/src/ui/molecules/DatePicker/DatePickerProvider.tsx +100 -0
  306. package/src/ui/molecules/DatePicker/index.ts +16 -0
  307. package/src/ui/molecules/Dropdown/Dropdown.stories.tsx +50 -8
  308. package/src/ui/molecules/Dropdown/Dropdown.test.tsx +272 -12
  309. package/src/ui/molecules/Dropdown/Dropdown.tsx +176 -10
  310. package/src/ui/molecules/EmptyState/EmptyState.stories.tsx +24 -2
  311. package/src/ui/molecules/EmptyState/EmptyState.tsx +9 -3
  312. package/src/ui/molecules/FileUpload/FileUpload.stories.tsx +177 -0
  313. package/src/ui/molecules/FileUpload/FileUpload.test.tsx +114 -0
  314. package/src/ui/molecules/FileUpload/FileUpload.tsx +312 -0
  315. package/src/ui/molecules/FileUpload/index.ts +2 -0
  316. package/src/ui/molecules/Form/Form.mdx +145 -0
  317. package/src/ui/molecules/Form/Form.stories.tsx +121 -1
  318. package/src/ui/molecules/Form/Form.test.tsx +1 -3
  319. package/src/ui/molecules/Form/Form.tsx +95 -15
  320. package/src/ui/molecules/Form/FormContext.tsx +35 -0
  321. package/src/ui/molecules/Form/FormField.tsx +83 -0
  322. package/src/ui/molecules/Form/FormProvider.tsx +34 -0
  323. package/src/ui/molecules/Form/index.ts +21 -0
  324. package/src/ui/molecules/Form/useFormFieldArray.ts +46 -0
  325. package/src/ui/molecules/InputWithLabel/InputWithLabel.stories.tsx +1 -1
  326. package/src/ui/molecules/InputWithLabel/InputWithLabel.test.tsx +44 -0
  327. package/src/ui/molecules/InputWithLabel/InputWithLabel.tsx +3 -1
  328. package/src/ui/molecules/NavbarGroup/NavbarGroup.stories.tsx +1 -1
  329. package/src/ui/molecules/Pagination/Pagination.stories.tsx +1 -1
  330. package/src/ui/molecules/Rating/Rating.stories.tsx +206 -0
  331. package/src/ui/molecules/Rating/Rating.test.tsx +60 -0
  332. package/src/ui/molecules/Rating/Rating.tsx +173 -0
  333. package/src/ui/molecules/Rating/index.ts +2 -0
  334. package/src/ui/molecules/SearchInput/SearchInput.stories.tsx +146 -0
  335. package/src/ui/molecules/SearchInput/SearchInput.test.tsx +82 -0
  336. package/src/ui/molecules/SearchInput/SearchInput.tsx +133 -0
  337. package/src/ui/molecules/SearchInput/index.ts +2 -0
  338. package/src/ui/molecules/Tabs/Tabs.stories.tsx +229 -0
  339. package/src/ui/molecules/Tabs/Tabs.test.tsx +497 -0
  340. package/src/ui/molecules/Tabs/Tabs.tsx +58 -0
  341. package/src/ui/molecules/Tabs/TabsContent.tsx +50 -0
  342. package/src/ui/molecules/Tabs/TabsContext.tsx +36 -0
  343. package/src/ui/molecules/Tabs/TabsList.tsx +98 -0
  344. package/src/ui/molecules/Tabs/TabsProvider.tsx +53 -0
  345. package/src/ui/molecules/Tabs/TabsTrigger.tsx +111 -0
  346. package/src/ui/molecules/Tabs/index.ts +23 -0
  347. package/src/ui/molecules/TimePicker/TimePicker.stories.tsx +145 -0
  348. package/src/ui/molecules/TimePicker/TimePicker.test.tsx +41 -0
  349. package/src/ui/molecules/TimePicker/TimePicker.tsx +264 -0
  350. package/src/ui/molecules/TimePicker/index.ts +2 -0
  351. package/src/ui/molecules/index.ts +20 -7
  352. package/src/ui/organisms/CommandPalette/CommandPalette.stories.tsx +218 -0
  353. package/src/ui/organisms/CommandPalette/CommandPalette.test.tsx +85 -0
  354. package/src/ui/organisms/CommandPalette/CommandPalette.tsx +333 -0
  355. package/src/ui/organisms/CommandPalette/index.ts +2 -0
  356. package/src/ui/organisms/DataGrid/DataGrid.stories.tsx +196 -0
  357. package/src/ui/organisms/DataGrid/DataGrid.test.tsx +53 -0
  358. package/src/ui/organisms/DataGrid/DataGrid.tsx +294 -0
  359. package/src/ui/organisms/DataGrid/index.ts +2 -0
  360. package/src/ui/organisms/Dialog/AlertDialog.tsx +92 -0
  361. package/src/ui/organisms/Dialog/Dialog.mdx +200 -0
  362. package/src/ui/organisms/Dialog/Dialog.stories.tsx +226 -0
  363. package/src/ui/organisms/Dialog/Dialog.test.tsx +435 -0
  364. package/src/ui/organisms/Dialog/Dialog.tsx +79 -0
  365. package/src/ui/organisms/Dialog/DialogClose.tsx +45 -0
  366. package/src/ui/organisms/Dialog/DialogContent.tsx +149 -0
  367. package/src/ui/organisms/Dialog/DialogContext.tsx +25 -0
  368. package/src/ui/organisms/Dialog/DialogDescription.tsx +28 -0
  369. package/src/ui/organisms/Dialog/DialogFooter.tsx +18 -0
  370. package/src/ui/organisms/Dialog/DialogHeader.tsx +18 -0
  371. package/src/ui/organisms/Dialog/DialogProvider.tsx +73 -0
  372. package/src/ui/organisms/Dialog/DialogTitle.tsx +31 -0
  373. package/src/ui/organisms/Dialog/DialogTrigger.tsx +34 -0
  374. package/src/ui/organisms/Dialog/index.ts +24 -0
  375. package/src/ui/organisms/LoginBox/LoginBox.stories.tsx +1 -1
  376. package/src/ui/organisms/Modal/Modal.stories.tsx +2 -2
  377. package/src/ui/organisms/Modal/Modal.test.tsx +1 -1
  378. package/src/ui/organisms/Sidebar/Sidebar.stories.tsx +1 -1
  379. package/src/ui/organisms/Sidebar/Sidebar.test.tsx +5 -3
  380. package/src/ui/organisms/Sidebar/Sidebar.tsx +21 -6
  381. package/src/ui/{molecules → organisms/Sidebar}/SidebarGroup/SidebarGroup.stories.tsx +2 -2
  382. package/src/ui/{molecules → organisms/Sidebar}/SidebarGroup/SidebarGroup.test.tsx +32 -9
  383. package/src/ui/{molecules → organisms/Sidebar}/SidebarGroup/SidebarGroup.tsx +7 -7
  384. package/src/ui/organisms/Sidebar/SidebarHeader/SidebarHeader.test.tsx +66 -0
  385. package/src/ui/{molecules → organisms/Sidebar}/SidebarHeader/SidebarHeader.tsx +1 -2
  386. package/src/ui/{atoms → organisms/Sidebar}/SidebarItem/SidebarItem.stories.tsx +1 -1
  387. package/src/ui/{atoms → organisms/Sidebar}/SidebarItem/SidebarItem.test.tsx +9 -8
  388. package/src/ui/{atoms → organisms/Sidebar}/SidebarItem/SidebarItem.tsx +9 -3
  389. package/src/ui/organisms/Sidebar/index.ts +13 -0
  390. package/src/ui/organisms/Stepper/Stepper.stories.tsx +253 -0
  391. package/src/ui/organisms/Stepper/Stepper.test.tsx +76 -0
  392. package/src/ui/organisms/Stepper/Stepper.tsx +323 -0
  393. package/src/ui/organisms/Stepper/index.ts +2 -0
  394. package/src/ui/organisms/Table/Table.mdx +154 -0
  395. package/src/ui/organisms/Table/Table.stories.tsx +614 -4
  396. package/src/ui/organisms/Table/Table.test.tsx +86 -4
  397. package/src/ui/organisms/Table/Table.tsx +215 -99
  398. package/src/ui/organisms/Table/TableActions/TableActions.stories.tsx +88 -0
  399. package/src/ui/organisms/Table/TableActions/TableActions.test.tsx +64 -0
  400. package/src/ui/organisms/Table/TableActions/TableActions.tsx +71 -0
  401. package/src/ui/organisms/Table/TableActions.tsx +46 -0
  402. package/src/ui/organisms/Table/TableBody.tsx +137 -0
  403. package/src/ui/organisms/Table/TableCell.tsx +36 -0
  404. package/src/ui/organisms/Table/TableContext.tsx +111 -0
  405. package/src/ui/organisms/Table/TableEmptyState.tsx +51 -0
  406. package/src/ui/organisms/Table/TableFilters/TableFilters.stories.tsx +111 -0
  407. package/src/ui/organisms/Table/TableFilters/TableFilters.test.tsx +104 -0
  408. package/src/ui/organisms/Table/TableFilters/TableFilters.tsx +191 -0
  409. package/src/ui/organisms/Table/TableFilters.tsx +39 -0
  410. package/src/ui/organisms/Table/TableHeader.tsx +29 -0
  411. package/src/ui/organisms/Table/TableHeaderCell.tsx +142 -0
  412. package/src/ui/organisms/Table/TableHeaderRow.tsx +72 -0
  413. package/src/ui/organisms/Table/TablePagination/TablePagination.stories.tsx +87 -0
  414. package/src/ui/organisms/Table/TablePagination/TablePagination.test.tsx +90 -0
  415. package/src/ui/organisms/Table/TablePagination/TablePagination.tsx +207 -0
  416. package/src/ui/organisms/Table/TablePagination.tsx +48 -0
  417. package/src/ui/organisms/Table/TableProvider.tsx +429 -0
  418. package/src/ui/organisms/Table/TableRow.tsx +85 -0
  419. package/src/ui/organisms/Table/TableTypes.ts +11 -0
  420. package/src/ui/organisms/Table/index.ts +55 -0
  421. package/src/ui/organisms/Table/useColumnResizing.ts +134 -0
  422. package/src/ui/organisms/Table/useVirtualScrolling.ts +116 -0
  423. package/src/ui/organisms/Timeline/Timeline.stories.tsx +230 -0
  424. package/src/ui/organisms/Timeline/Timeline.test.tsx +47 -0
  425. package/src/ui/organisms/Timeline/Timeline.tsx +179 -0
  426. package/src/ui/organisms/Timeline/index.ts +2 -0
  427. package/src/ui/organisms/Toast/Toast.stories.tsx +169 -0
  428. package/src/ui/organisms/Toast/Toast.test.tsx +537 -0
  429. package/src/ui/organisms/Toast/Toast.tsx +144 -0
  430. package/src/ui/organisms/Toast/ToastContainer.tsx +54 -0
  431. package/src/ui/organisms/Toast/ToastContext.tsx +38 -0
  432. package/src/ui/organisms/Toast/ToastProvider.tsx +56 -0
  433. package/src/ui/organisms/Toast/index.ts +17 -0
  434. package/src/ui/organisms/Toast/useToast.ts +70 -0
  435. package/src/ui/organisms/index.ts +17 -2
  436. package/src/ui/providers/AdvancedThemeProvider.tsx +229 -0
  437. package/src/ui/providers/index.ts +14 -0
  438. package/src/ui/themes/README.md +281 -0
  439. package/src/ui/themes/ThemeBuilder.ts +149 -0
  440. package/src/ui/themes/ThemeRegistry.ts +187 -0
  441. package/src/ui/themes/index.ts +20 -0
  442. package/src/ui/themes/types.ts +53 -0
  443. package/src/ui/themes/utils.ts +70 -0
  444. package/src/ui/tokens/README.md +212 -0
  445. package/src/ui/tokens/TokenVisualizations.tsx +273 -0
  446. package/src/ui/tokens/Tokens.mdx +348 -0
  447. package/src/ui/tokens/animations.ts +157 -0
  448. package/src/ui/tokens/borders.ts +121 -0
  449. package/src/ui/tokens/gradients.ts +154 -0
  450. package/src/ui/tokens/index.ts +57 -0
  451. package/src/ui/tokens/opacity.ts +107 -0
  452. package/src/ui/tokens/radius.ts +107 -0
  453. package/src/ui/tokens/shadows.ts +92 -0
  454. package/src/ui/tokens/tokens.factory.ts +124 -0
  455. package/src/ui/tokens/z-index.ts +113 -0
  456. package/src/ui/utils/index.ts +10 -0
  457. package/src/App.css +0 -42
  458. package/src/App.tsx +0 -35
  459. package/src/index.css +0 -68
  460. package/src/main.tsx +0 -15
@@ -0,0 +1,497 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import Tabs from './Tabs';
5
+
6
+ describe('Tabs', () => {
7
+ describe('Rendering', () => {
8
+ it('renders tabs with triggers and content', () => {
9
+ render(
10
+ <Tabs defaultValue="tab1">
11
+ <Tabs.List>
12
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
13
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
14
+ </Tabs.List>
15
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
16
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
17
+ </Tabs>
18
+ );
19
+
20
+ expect(screen.getByText('Tab 1')).toBeInTheDocument();
21
+ expect(screen.getByText('Tab 2')).toBeInTheDocument();
22
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
23
+ });
24
+
25
+ it('shows only active tab content', () => {
26
+ render(
27
+ <Tabs defaultValue="tab1">
28
+ <Tabs.List>
29
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
30
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
31
+ </Tabs.List>
32
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
33
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
34
+ </Tabs>
35
+ );
36
+
37
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
38
+ expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
39
+ });
40
+
41
+ it('renders all content when forceMount is true', () => {
42
+ render(
43
+ <Tabs defaultValue="tab1">
44
+ <Tabs.List>
45
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
46
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
47
+ </Tabs.List>
48
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
49
+ <Tabs.Content value="tab2" forceMount>Content 2</Tabs.Content>
50
+ </Tabs>
51
+ );
52
+
53
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
54
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
55
+ });
56
+ });
57
+
58
+ describe('Tab Switching', () => {
59
+ it('switches to different tab when clicked', async () => {
60
+ const user = userEvent.setup();
61
+ render(
62
+ <Tabs defaultValue="tab1">
63
+ <Tabs.List>
64
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
65
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
66
+ </Tabs.List>
67
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
68
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
69
+ </Tabs>
70
+ );
71
+
72
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
73
+ expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
74
+
75
+ const tab2 = screen.getByText('Tab 2');
76
+ await user.click(tab2);
77
+
78
+ await waitFor(() => {
79
+ expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
80
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
81
+ });
82
+ });
83
+
84
+ it('calls onValueChange when tab is switched', async () => {
85
+ const user = userEvent.setup();
86
+ const handleChange = vi.fn();
87
+ render(
88
+ <Tabs defaultValue="tab1" onValueChange={handleChange}>
89
+ <Tabs.List>
90
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
91
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
92
+ </Tabs.List>
93
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
94
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
95
+ </Tabs>
96
+ );
97
+
98
+ const tab2 = screen.getByText('Tab 2');
99
+ await user.click(tab2);
100
+
101
+ await waitFor(() => {
102
+ expect(handleChange).toHaveBeenCalledWith('tab2');
103
+ });
104
+ });
105
+ });
106
+
107
+ describe('Keyboard Navigation', () => {
108
+ it('navigates with ArrowRight in horizontal mode', async () => {
109
+ render(
110
+ <Tabs defaultValue="tab1">
111
+ <Tabs.List>
112
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
113
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
114
+ <Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
115
+ </Tabs.List>
116
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
117
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
118
+ <Tabs.Content value="tab3">Content 3</Tabs.Content>
119
+ </Tabs>
120
+ );
121
+
122
+ const tab1 = screen.getByText('Tab 1');
123
+ tab1.focus();
124
+
125
+ fireEvent.keyDown(tab1, { key: 'ArrowRight' });
126
+
127
+ await waitFor(() => {
128
+ const tab2 = screen.getByText('Tab 2');
129
+ expect(document.activeElement).toBe(tab2);
130
+ });
131
+ });
132
+
133
+ it('navigates with ArrowLeft in horizontal mode', async () => {
134
+ render(
135
+ <Tabs defaultValue="tab2">
136
+ <Tabs.List>
137
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
138
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
139
+ <Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
140
+ </Tabs.List>
141
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
142
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
143
+ <Tabs.Content value="tab3">Content 3</Tabs.Content>
144
+ </Tabs>
145
+ );
146
+
147
+ const tab2 = screen.getByText('Tab 2');
148
+ tab2.focus();
149
+
150
+ fireEvent.keyDown(tab2, { key: 'ArrowLeft' });
151
+
152
+ await waitFor(() => {
153
+ const tab1 = screen.getByText('Tab 1');
154
+ expect(document.activeElement).toBe(tab1);
155
+ });
156
+ });
157
+
158
+ it('navigates with ArrowDown in vertical mode', async () => {
159
+ render(
160
+ <Tabs defaultValue="tab1" orientation="vertical">
161
+ <Tabs.List>
162
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
163
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
164
+ <Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
165
+ </Tabs.List>
166
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
167
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
168
+ <Tabs.Content value="tab3">Content 3</Tabs.Content>
169
+ </Tabs>
170
+ );
171
+
172
+ const tab1 = screen.getByText('Tab 1');
173
+ tab1.focus();
174
+
175
+ fireEvent.keyDown(tab1, { key: 'ArrowDown' });
176
+
177
+ await waitFor(() => {
178
+ const tab2 = screen.getByText('Tab 2');
179
+ expect(document.activeElement).toBe(tab2);
180
+ });
181
+ });
182
+
183
+ it('navigates with ArrowUp in vertical mode', async () => {
184
+ render(
185
+ <Tabs defaultValue="tab2" orientation="vertical">
186
+ <Tabs.List>
187
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
188
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
189
+ <Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
190
+ </Tabs.List>
191
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
192
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
193
+ <Tabs.Content value="tab3">Content 3</Tabs.Content>
194
+ </Tabs>
195
+ );
196
+
197
+ const tab2 = screen.getByText('Tab 2');
198
+ tab2.focus();
199
+
200
+ fireEvent.keyDown(tab2, { key: 'ArrowUp' });
201
+
202
+ await waitFor(() => {
203
+ const tab1 = screen.getByText('Tab 1');
204
+ expect(document.activeElement).toBe(tab1);
205
+ });
206
+ });
207
+
208
+ it('navigates to first tab with Home key', async () => {
209
+ render(
210
+ <Tabs defaultValue="tab2">
211
+ <Tabs.List>
212
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
213
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
214
+ <Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
215
+ </Tabs.List>
216
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
217
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
218
+ <Tabs.Content value="tab3">Content 3</Tabs.Content>
219
+ </Tabs>
220
+ );
221
+
222
+ const tab2 = screen.getByText('Tab 2');
223
+ tab2.focus();
224
+
225
+ fireEvent.keyDown(tab2, { key: 'Home' });
226
+
227
+ await waitFor(() => {
228
+ const tab1 = screen.getByText('Tab 1');
229
+ expect(document.activeElement).toBe(tab1);
230
+ });
231
+ });
232
+
233
+ it('navigates to last tab with End key', async () => {
234
+ render(
235
+ <Tabs defaultValue="tab1">
236
+ <Tabs.List>
237
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
238
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
239
+ <Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
240
+ </Tabs.List>
241
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
242
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
243
+ <Tabs.Content value="tab3">Content 3</Tabs.Content>
244
+ </Tabs>
245
+ );
246
+
247
+ const tab1 = screen.getByText('Tab 1');
248
+ tab1.focus();
249
+
250
+ fireEvent.keyDown(tab1, { key: 'End' });
251
+
252
+ await waitFor(() => {
253
+ const tab3 = screen.getByText('Tab 3');
254
+ expect(document.activeElement).toBe(tab3);
255
+ });
256
+ });
257
+ });
258
+
259
+ describe('Activation Modes', () => {
260
+ it('activates tab automatically on focus in automatic mode', async () => {
261
+ render(
262
+ <Tabs defaultValue="tab1" activationMode="automatic">
263
+ <Tabs.List>
264
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
265
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
266
+ </Tabs.List>
267
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
268
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
269
+ </Tabs>
270
+ );
271
+
272
+ const tab2 = screen.getByText('Tab 2');
273
+
274
+ await act(async () => {
275
+ tab2.focus();
276
+ });
277
+
278
+ await waitFor(() => {
279
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
280
+ expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
281
+ });
282
+ });
283
+
284
+ it('requires Enter or Space to activate in manual mode', async () => {
285
+ const _user = userEvent.setup();
286
+ render(
287
+ <Tabs defaultValue="tab1" activationMode="manual">
288
+ <Tabs.List>
289
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
290
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
291
+ </Tabs.List>
292
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
293
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
294
+ </Tabs>
295
+ );
296
+
297
+ const tab2 = screen.getByText('Tab 2');
298
+ tab2.focus();
299
+
300
+ // Content should not change on focus
301
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
302
+ expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
303
+
304
+ // Press Enter to activate
305
+ fireEvent.keyDown(tab2, { key: 'Enter' });
306
+
307
+ await waitFor(() => {
308
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
309
+ expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
310
+ });
311
+ });
312
+ });
313
+
314
+ describe('Controlled vs Uncontrolled', () => {
315
+ it('works in uncontrolled mode', async () => {
316
+ const user = userEvent.setup();
317
+ render(
318
+ <Tabs defaultValue="tab1">
319
+ <Tabs.List>
320
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
321
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
322
+ </Tabs.List>
323
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
324
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
325
+ </Tabs>
326
+ );
327
+
328
+ const tab2 = screen.getByText('Tab 2');
329
+ await user.click(tab2);
330
+
331
+ await waitFor(() => {
332
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
333
+ });
334
+ });
335
+
336
+ it('works in controlled mode', () => {
337
+ const { rerender } = render(
338
+ <Tabs value="tab1">
339
+ <Tabs.List>
340
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
341
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
342
+ </Tabs.List>
343
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
344
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
345
+ </Tabs>
346
+ );
347
+
348
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
349
+
350
+ rerender(
351
+ <Tabs value="tab2">
352
+ <Tabs.List>
353
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
354
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
355
+ </Tabs.List>
356
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
357
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
358
+ </Tabs>
359
+ );
360
+
361
+ expect(screen.getByText('Content 2')).toBeInTheDocument();
362
+ });
363
+ });
364
+
365
+ describe('Disabled Tabs', () => {
366
+ it('does not switch when disabled tab is clicked', async () => {
367
+ const user = userEvent.setup();
368
+ render(
369
+ <Tabs defaultValue="tab1">
370
+ <Tabs.List>
371
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
372
+ <Tabs.Trigger value="tab2" disabled>Tab 2</Tabs.Trigger>
373
+ </Tabs.List>
374
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
375
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
376
+ </Tabs>
377
+ );
378
+
379
+ const tab2 = screen.getByText('Tab 2');
380
+ expect(tab2).toBeDisabled();
381
+
382
+ await user.click(tab2);
383
+
384
+ // Content should not change
385
+ expect(screen.getByText('Content 1')).toBeInTheDocument();
386
+ expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
387
+ });
388
+
389
+ it('skips disabled tabs in keyboard navigation', async () => {
390
+ render(
391
+ <Tabs defaultValue="tab1">
392
+ <Tabs.List>
393
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
394
+ <Tabs.Trigger value="tab2" disabled>Tab 2</Tabs.Trigger>
395
+ <Tabs.Trigger value="tab3">Tab 3</Tabs.Trigger>
396
+ </Tabs.List>
397
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
398
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
399
+ <Tabs.Content value="tab3">Content 3</Tabs.Content>
400
+ </Tabs>
401
+ );
402
+
403
+ const tab1 = screen.getByText('Tab 1');
404
+ tab1.focus();
405
+
406
+ fireEvent.keyDown(tab1, { key: 'ArrowRight' });
407
+
408
+ await waitFor(() => {
409
+ const tab3 = screen.getByText('Tab 3');
410
+ expect(document.activeElement).toBe(tab3);
411
+ });
412
+ });
413
+ });
414
+
415
+ describe('Accessibility', () => {
416
+ it('has correct ARIA attributes on tablist', () => {
417
+ render(
418
+ <Tabs defaultValue="tab1">
419
+ <Tabs.List>
420
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
421
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
422
+ </Tabs.List>
423
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
424
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
425
+ </Tabs>
426
+ );
427
+
428
+ const tablist = screen.getByRole('tablist');
429
+ expect(tablist).toHaveAttribute('aria-orientation', 'horizontal');
430
+ });
431
+
432
+ it('has correct ARIA attributes on triggers', () => {
433
+ render(
434
+ <Tabs defaultValue="tab1">
435
+ <Tabs.List>
436
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
437
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
438
+ </Tabs.List>
439
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
440
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
441
+ </Tabs>
442
+ );
443
+
444
+ const tab1 = screen.getByRole('tab', { name: 'Tab 1' });
445
+ expect(tab1).toHaveAttribute('aria-selected', 'true');
446
+ expect(tab1).toHaveAttribute('aria-controls', 'tabpanel-tab1');
447
+ expect(tab1).toHaveAttribute('id', 'tab-tab1');
448
+
449
+ const tab2 = screen.getByRole('tab', { name: 'Tab 2' });
450
+ expect(tab2).toHaveAttribute('aria-selected', 'false');
451
+ expect(tab2).toHaveAttribute('aria-controls', 'tabpanel-tab2');
452
+ });
453
+
454
+ it('has correct ARIA attributes on content', () => {
455
+ render(
456
+ <Tabs defaultValue="tab1">
457
+ <Tabs.List>
458
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
459
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
460
+ </Tabs.List>
461
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
462
+ <Tabs.Content value="tab2" forceMount>Content 2</Tabs.Content>
463
+ </Tabs>
464
+ );
465
+
466
+ const content1 = screen.getByRole('tabpanel', { name: 'Tab 1' });
467
+ expect(content1).toHaveAttribute('id', 'tabpanel-tab1');
468
+ expect(content1).toHaveAttribute('aria-labelledby', 'tab-tab1');
469
+ expect(content1).not.toHaveAttribute('hidden');
470
+
471
+ // Tab 2 content should be hidden (using forceMount to render it)
472
+ // When hidden, we need to query by text or id since getByRole may not find hidden elements
473
+ const content2 = screen.getByText('Content 2').closest('[role="tabpanel"]');
474
+ expect(content2).toBeInTheDocument();
475
+ expect(content2).toHaveAttribute('hidden');
476
+ });
477
+
478
+ it('has correct tabIndex on triggers', () => {
479
+ render(
480
+ <Tabs defaultValue="tab1">
481
+ <Tabs.List>
482
+ <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
483
+ <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
484
+ </Tabs.List>
485
+ <Tabs.Content value="tab1">Content 1</Tabs.Content>
486
+ <Tabs.Content value="tab2">Content 2</Tabs.Content>
487
+ </Tabs>
488
+ );
489
+
490
+ const tab1 = screen.getByRole('tab', { name: 'Tab 1' });
491
+ expect(tab1).toHaveAttribute('tabIndex', '0');
492
+
493
+ const tab2 = screen.getByRole('tab', { name: 'Tab 2' });
494
+ expect(tab2).toHaveAttribute('tabIndex', '-1');
495
+ });
496
+ });
497
+ });
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+
3
+ import React, { type ReactNode } from 'react';
4
+ import { TabsProvider, type TabsProviderProps } from './TabsProvider';
5
+ import { TabsList } from './TabsList';
6
+ import { TabsTrigger } from './TabsTrigger';
7
+ import { TabsContent } from './TabsContent';
8
+
9
+ export interface TabsProps extends Omit<TabsProviderProps, 'children'> {
10
+ children: ReactNode;
11
+ }
12
+
13
+ /**
14
+ * Tabs Component
15
+ *
16
+ * A flexible tabs component with compound components pattern.
17
+ * Supports horizontal and vertical orientations, automatic and manual activation modes.
18
+ * Fully accessible with ARIA attributes and keyboard navigation.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <Tabs defaultValue="tab1">
23
+ * <Tabs.List>
24
+ * <Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
25
+ * <Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
26
+ * </Tabs.List>
27
+ * <Tabs.Content value="tab1">Content 1</Tabs.Content>
28
+ * <Tabs.Content value="tab2">Content 2</Tabs.Content>
29
+ * </Tabs>
30
+ * ```
31
+ */
32
+ function TabsComponent({
33
+ children,
34
+ ...providerProps
35
+ }: TabsProps) {
36
+ return (
37
+ <TabsProvider {...providerProps}>
38
+ {children}
39
+ </TabsProvider>
40
+ );
41
+ }
42
+
43
+ // Compound components
44
+ TabsComponent.List = TabsList;
45
+ TabsComponent.Trigger = TabsTrigger;
46
+ TabsComponent.Content = TabsContent;
47
+
48
+ // Type declaration for compound components
49
+ export interface TabsComponentType extends React.FC<TabsProps> {
50
+ List: typeof TabsList;
51
+ Trigger: typeof TabsTrigger;
52
+ Content: typeof TabsContent;
53
+ }
54
+
55
+ // Cast to include compound components
56
+ const Tabs: TabsComponentType = TabsComponent as TabsComponentType;
57
+
58
+ export default Tabs;
@@ -0,0 +1,50 @@
1
+ 'use client';
2
+
3
+ import { useTabsContext } from './TabsContext';
4
+ import type { HTMLAttributes, ReactNode } from 'react';
5
+
6
+ export interface TabsContentProps extends HTMLAttributes<HTMLDivElement> {
7
+ value: string;
8
+ children: ReactNode;
9
+ forceMount?: boolean;
10
+ }
11
+
12
+ /**
13
+ * TabsContent Component
14
+ *
15
+ * Content panel for a tab.
16
+ * Only renders when the tab is active (unless forceMount is true).
17
+ * Must be used within a Tabs component.
18
+ */
19
+ export function TabsContent({
20
+ value,
21
+ children,
22
+ forceMount = false,
23
+ className = '',
24
+ ...props
25
+ }: TabsContentProps) {
26
+ const { value: activeValue } = useTabsContext();
27
+
28
+ const isActive = activeValue === value;
29
+
30
+ if (!isActive && !forceMount) {
31
+ return null;
32
+ }
33
+
34
+ return (
35
+ <div
36
+ role="tabpanel"
37
+ id={`tabpanel-${value}`}
38
+ aria-labelledby={`tab-${value}`}
39
+ hidden={!isActive}
40
+ className={`
41
+ mt-2
42
+ focus:outline-none
43
+ ${className}
44
+ `}
45
+ {...props}
46
+ >
47
+ {children}
48
+ </div>
49
+ );
50
+ }
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+
3
+ import { createContext, useContext } from 'react';
4
+
5
+ export interface TabsContextValue {
6
+ value: string;
7
+ onValueChange: (value: string) => void;
8
+ orientation?: 'horizontal' | 'vertical';
9
+ activationMode?: 'automatic' | 'manual';
10
+ }
11
+
12
+ const TabsContext = createContext<TabsContextValue | undefined>(undefined);
13
+
14
+ /**
15
+ * Hook to access Tabs context
16
+ *
17
+ * @throws Error if used outside of Tabs component
18
+ */
19
+ export function useTabsContext(): TabsContextValue {
20
+ const context = useContext(TabsContext);
21
+
22
+ if (context === undefined) {
23
+ throw new Error('useTabsContext must be used within a Tabs component');
24
+ }
25
+
26
+ return context;
27
+ }
28
+
29
+ /**
30
+ * Hook to access Tabs context (optional, returns undefined if not in Tabs)
31
+ */
32
+ export function useTabsContextOptional(): TabsContextValue | undefined {
33
+ return useContext(TabsContext);
34
+ }
35
+
36
+ export { TabsContext };