@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,147 @@
1
+ 'use client';
2
+
3
+ import { useState, type ReactNode } from 'react';
4
+ import { ChevronDown } from 'lucide-react';
5
+ import { getColorClass } from '../../tokens/colors';
6
+ import { getSpacingClass } from '../../tokens/spacing';
7
+ import { getAnimationClass } from '../../tokens/animations';
8
+ import { getTypographyClasses } from '../../tokens/typography';
9
+
10
+ export type AccordionType = 'single' | 'multiple';
11
+
12
+ export interface AccordionItem {
13
+ id: string;
14
+ title: string;
15
+ content: ReactNode;
16
+ disabled?: boolean;
17
+ }
18
+
19
+ export interface AccordionProps {
20
+ items: AccordionItem[];
21
+ type?: AccordionType;
22
+ defaultOpen?: string | string[];
23
+ onValueChange?: (value: string | string[]) => void;
24
+ className?: string;
25
+ }
26
+
27
+ /**
28
+ * Accordion Component
29
+ *
30
+ * A collapsible content component that can display multiple items.
31
+ * Supports single and multiple selection modes.
32
+ * Follows Atomic Design principles as an Atom component.
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * <Accordion
37
+ * type="single"
38
+ * items={[
39
+ * { id: '1', title: 'Item 1', content: 'Content 1' },
40
+ * { id: '2', title: 'Item 2', content: 'Content 2' },
41
+ * ]}
42
+ * />
43
+ * ```
44
+ */
45
+ export default function Accordion({
46
+ items,
47
+ type = 'single',
48
+ defaultOpen,
49
+ onValueChange,
50
+ className = '',
51
+ }: AccordionProps) {
52
+ const getInitialOpen = (): string[] => {
53
+ if (defaultOpen === undefined) return [];
54
+ return Array.isArray(defaultOpen) ? defaultOpen : [defaultOpen];
55
+ };
56
+
57
+ const [openItems, setOpenItems] = useState<string[]>(getInitialOpen);
58
+
59
+ const handleToggle = (itemId: string) => {
60
+ if (items.find(item => item.id === itemId)?.disabled) return;
61
+
62
+ let newOpenItems: string[];
63
+
64
+ if (type === 'single') {
65
+ newOpenItems = openItems.includes(itemId) ? [] : [itemId];
66
+ } else {
67
+ newOpenItems = openItems.includes(itemId)
68
+ ? openItems.filter(id => id !== itemId)
69
+ : [...openItems, itemId];
70
+ }
71
+
72
+ setOpenItems(newOpenItems);
73
+ onValueChange?.(type === 'single' ? newOpenItems[0] || '' : newOpenItems);
74
+ };
75
+
76
+ return (
77
+ <div className={`space-y-1 ${className}`}>
78
+ {items.map((item) => {
79
+ const isOpen = openItems.includes(item.id);
80
+ const isDisabled = item.disabled;
81
+
82
+ return (
83
+ <div
84
+ key={item.id}
85
+ className="border border-gray-200 rounded-md overflow-hidden"
86
+ >
87
+ <button
88
+ type="button"
89
+ onClick={() => handleToggle(item.id)}
90
+ disabled={isDisabled}
91
+ className={`
92
+ w-full
93
+ flex
94
+ items-center
95
+ justify-between
96
+ ${getSpacingClass('base', 'px')}
97
+ ${getSpacingClass('md', 'py')}
98
+ ${getTypographyClasses('label')}
99
+ text-left
100
+ ${getColorClass('neutral', 'dark', 'text')}
101
+ bg-white
102
+ hover:bg-gray-50
103
+ focus:outline-none
104
+ focus:ring-2
105
+ focus:ring-offset-2
106
+ ${getColorClass('primary', 'DEFAULT', 'focus:ring')}
107
+ ${getAnimationClass('base')}
108
+ ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
109
+ `}
110
+ aria-expanded={isOpen}
111
+ aria-controls={`accordion-content-${item.id}`}
112
+ aria-disabled={isDisabled}
113
+ >
114
+ <span>{item.title}</span>
115
+ <ChevronDown
116
+ className={`
117
+ ${getSpacingClass('sm', 'ml')}
118
+ ${getAnimationClass('base')}
119
+ ${isOpen ? 'transform rotate-180' : ''}
120
+ ${isDisabled ? 'opacity-50' : ''}
121
+ `}
122
+ aria-hidden="true"
123
+ />
124
+ </button>
125
+ <div
126
+ id={`accordion-content-${item.id}`}
127
+ className={`
128
+ overflow-hidden
129
+ ${getAnimationClass('base')}
130
+ ${isOpen ? 'max-h-[1000px] opacity-100' : 'max-h-0 opacity-0'}
131
+ `}
132
+ aria-hidden={!isOpen}
133
+ >
134
+ <div className={`
135
+ ${getSpacingClass('base', 'px')}
136
+ ${getSpacingClass('md', 'py')}
137
+ ${getColorClass('neutral', 'DEFAULT', 'text')}
138
+ `}>
139
+ {item.content}
140
+ </div>
141
+ </div>
142
+ </div>
143
+ );
144
+ })}
145
+ </div>
146
+ );
147
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from './Accordion';
2
+ export type { AccordionProps, AccordionItem, AccordionType } from './Accordion';
@@ -0,0 +1,226 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import Avatar from './Avatar';
3
+ import { AvatarGroup } from './AvatarGroup';
4
+
5
+ const meta: Meta<typeof Avatar> = {
6
+ title: 'Atoms/Avatar',
7
+ component: Avatar,
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: 'A versatile avatar component for displaying user profile images or initials. Supports fallback display when image fails to load or is not provided. Fully accessible with ARIA attributes.',
12
+ },
13
+ },
14
+ },
15
+ tags: ['autodocs'],
16
+ argTypes: {
17
+ src: {
18
+ control: 'text',
19
+ description: 'Image source URL',
20
+ },
21
+ alt: {
22
+ control: 'text',
23
+ description: 'Alt text for the image',
24
+ },
25
+ fallback: {
26
+ control: 'text',
27
+ description: 'Fallback text or element when image is not available',
28
+ },
29
+ size: {
30
+ control: 'select',
31
+ options: ['xs', 'sm', 'md', 'lg', 'xl'],
32
+ description: 'Size of the avatar',
33
+ },
34
+ variant: {
35
+ control: 'select',
36
+ options: ['circle', 'square', 'rounded'],
37
+ description: 'Shape variant of the avatar',
38
+ },
39
+ },
40
+ };
41
+
42
+ export default meta;
43
+ type Story = StoryObj<typeof Avatar>;
44
+
45
+ export const Default: Story = {
46
+ args: {
47
+ fallback: 'JD',
48
+ alt: 'John Doe',
49
+ size: 'md',
50
+ },
51
+ };
52
+
53
+ export const WithImage: Story = {
54
+ args: {
55
+ src: 'https://i.pravatar.cc/150?img=1',
56
+ alt: 'User avatar',
57
+ fallback: 'JD',
58
+ size: 'md',
59
+ },
60
+ };
61
+
62
+ export const Sizes: Story = {
63
+ render: () => (
64
+ <div className="flex items-center gap-4">
65
+ <Avatar fallback="XS" size="xs" alt="Extra small" />
66
+ <Avatar fallback="SM" size="sm" alt="Small" />
67
+ <Avatar fallback="MD" size="md" alt="Medium" />
68
+ <Avatar fallback="LG" size="lg" alt="Large" />
69
+ <Avatar fallback="XL" size="xl" alt="Extra large" />
70
+ </div>
71
+ ),
72
+ parameters: {
73
+ docs: {
74
+ description: {
75
+ story: 'All available sizes of the avatar component.',
76
+ },
77
+ },
78
+ },
79
+ };
80
+
81
+ export const Variants: Story = {
82
+ render: () => (
83
+ <div className="flex items-center gap-4">
84
+ <Avatar fallback="C" variant="circle" alt="Circle" />
85
+ <Avatar fallback="R" variant="rounded" alt="Rounded" />
86
+ <Avatar fallback="S" variant="square" alt="Square" />
87
+ </div>
88
+ ),
89
+ parameters: {
90
+ docs: {
91
+ description: {
92
+ story: 'Different shape variants: circle, rounded, and square.',
93
+ },
94
+ },
95
+ },
96
+ };
97
+
98
+ export const WithFallback: Story = {
99
+ render: () => (
100
+ <div className="flex items-center gap-4">
101
+ <Avatar fallback="JD" alt="John Doe" />
102
+ <Avatar fallback="AB" alt="Alice Brown" />
103
+ <Avatar fallback="CD" alt="Charlie Davis" />
104
+ <Avatar fallback="EF" alt="Emma Foster" />
105
+ </div>
106
+ ),
107
+ parameters: {
108
+ docs: {
109
+ description: {
110
+ story: 'Avatars with fallback initials when no image is provided.',
111
+ },
112
+ },
113
+ },
114
+ };
115
+
116
+ export const ImageError: Story = {
117
+ render: () => (
118
+ <div className="flex items-center gap-4">
119
+ <Avatar
120
+ src="https://invalid-url.com/image.jpg"
121
+ fallback="JD"
122
+ alt="John Doe"
123
+ />
124
+ <Avatar
125
+ src=""
126
+ fallback="AB"
127
+ alt="Alice Brown"
128
+ />
129
+ </div>
130
+ ),
131
+ parameters: {
132
+ docs: {
133
+ description: {
134
+ story: 'Avatars automatically fall back to initials when image fails to load or is not provided.',
135
+ },
136
+ },
137
+ },
138
+ };
139
+
140
+ export const Group: Story = {
141
+ render: () => (
142
+ <div className="space-y-4">
143
+ <div>
144
+ <p className="text-sm text-gray-600 mb-2">Small group (3 avatars)</p>
145
+ <AvatarGroup max={3} size="md">
146
+ <Avatar src="https://i.pravatar.cc/150?img=1" alt="User 1" fallback="U1" />
147
+ <Avatar src="https://i.pravatar.cc/150?img=2" alt="User 2" fallback="U2" />
148
+ <Avatar src="https://i.pravatar.cc/150?img=3" alt="User 3" fallback="U3" />
149
+ </AvatarGroup>
150
+ </div>
151
+ <div>
152
+ <p className="text-sm text-gray-600 mb-2">Large group with overflow (max 3)</p>
153
+ <AvatarGroup max={3} size="md">
154
+ <Avatar src="https://i.pravatar.cc/150?img=1" alt="User 1" fallback="U1" />
155
+ <Avatar src="https://i.pravatar.cc/150?img=2" alt="User 2" fallback="U2" />
156
+ <Avatar src="https://i.pravatar.cc/150?img=3" alt="User 3" fallback="U3" />
157
+ <Avatar src="https://i.pravatar.cc/150?img=4" alt="User 4" fallback="U4" />
158
+ <Avatar src="https://i.pravatar.cc/150?img=5" alt="User 5" fallback="U5" />
159
+ </AvatarGroup>
160
+ </div>
161
+ <div>
162
+ <p className="text-sm text-gray-600 mb-2">Group with fallbacks only</p>
163
+ <AvatarGroup max={4} size="md">
164
+ <Avatar fallback="JD" alt="John Doe" />
165
+ <Avatar fallback="AB" alt="Alice Brown" />
166
+ <Avatar fallback="CD" alt="Charlie Davis" />
167
+ <Avatar fallback="EF" alt="Emma Foster" />
168
+ <Avatar fallback="GH" alt="George Hill" />
169
+ </AvatarGroup>
170
+ </div>
171
+ </div>
172
+ ),
173
+ parameters: {
174
+ docs: {
175
+ description: {
176
+ story: 'AvatarGroup displays multiple avatars with automatic overflow handling. Shows a "+N" avatar when there are more than the max number.',
177
+ },
178
+ },
179
+ },
180
+ };
181
+
182
+ export const GroupSpacing: Story = {
183
+ render: () => (
184
+ <div className="space-y-4">
185
+ <div>
186
+ <p className="text-sm text-gray-600 mb-2">No spacing</p>
187
+ <AvatarGroup max={5} spacing="none">
188
+ <Avatar fallback="1" />
189
+ <Avatar fallback="2" />
190
+ <Avatar fallback="3" />
191
+ </AvatarGroup>
192
+ </div>
193
+ <div>
194
+ <p className="text-sm text-gray-600 mb-2">Small spacing</p>
195
+ <AvatarGroup max={5} spacing="sm">
196
+ <Avatar fallback="1" />
197
+ <Avatar fallback="2" />
198
+ <Avatar fallback="3" />
199
+ </AvatarGroup>
200
+ </div>
201
+ <div>
202
+ <p className="text-sm text-gray-600 mb-2">Medium spacing (default)</p>
203
+ <AvatarGroup max={5} spacing="md">
204
+ <Avatar fallback="1" />
205
+ <Avatar fallback="2" />
206
+ <Avatar fallback="3" />
207
+ </AvatarGroup>
208
+ </div>
209
+ <div>
210
+ <p className="text-sm text-gray-600 mb-2">Large spacing</p>
211
+ <AvatarGroup max={5} spacing="lg">
212
+ <Avatar fallback="1" />
213
+ <Avatar fallback="2" />
214
+ <Avatar fallback="3" />
215
+ </AvatarGroup>
216
+ </div>
217
+ </div>
218
+ ),
219
+ parameters: {
220
+ docs: {
221
+ description: {
222
+ story: 'Different spacing options for AvatarGroup.',
223
+ },
224
+ },
225
+ },
226
+ };
@@ -0,0 +1,233 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { render, screen, waitFor, fireEvent } from '@testing-library/react';
3
+ import Avatar from './Avatar';
4
+ import { AvatarGroup } from './AvatarGroup';
5
+
6
+ describe('Avatar', () => {
7
+ it('renders avatar with fallback text', () => {
8
+ render(<Avatar fallback="JD" alt="John Doe" />);
9
+ expect(screen.getByText('JD')).toBeInTheDocument();
10
+ });
11
+
12
+ it('renders avatar with image when src is provided', () => {
13
+ render(<Avatar src="/test.jpg" alt="Test User" />);
14
+ const img = screen.getByAltText('Test User');
15
+ expect(img).toBeInTheDocument();
16
+ expect(img).toHaveAttribute('src', '/test.jpg');
17
+ });
18
+
19
+ it('shows fallback when image fails to load', async () => {
20
+ const { container } = render(
21
+ <Avatar src="/invalid.jpg" fallback="JD" alt="John Doe" />
22
+ );
23
+
24
+ const img = container.querySelector('img');
25
+ expect(img).toBeInTheDocument();
26
+
27
+ // Simulate image error
28
+ if (img) {
29
+ fireEvent.error(img);
30
+ }
31
+
32
+ await waitFor(() => {
33
+ expect(screen.getByText('JD')).toBeInTheDocument();
34
+ });
35
+ });
36
+
37
+ it('applies correct size classes', () => {
38
+ const { container, rerender } = render(<Avatar fallback="JD" size="xs" />);
39
+ let avatar = container.querySelector('div[role="img"]');
40
+ expect(avatar).toHaveClass('h-6', 'w-6', 'text-xs');
41
+
42
+ rerender(<Avatar fallback="JD" size="sm" />);
43
+ avatar = container.querySelector('div[role="img"]');
44
+ expect(avatar).toHaveClass('h-8', 'w-8', 'text-sm');
45
+
46
+ rerender(<Avatar fallback="JD" size="md" />);
47
+ avatar = container.querySelector('div[role="img"]');
48
+ expect(avatar).toHaveClass('h-10', 'w-10', 'text-base');
49
+
50
+ rerender(<Avatar fallback="JD" size="lg" />);
51
+ avatar = container.querySelector('div[role="img"]');
52
+ expect(avatar).toHaveClass('h-12', 'w-12', 'text-lg');
53
+
54
+ rerender(<Avatar fallback="JD" size="xl" />);
55
+ avatar = container.querySelector('div[role="img"]');
56
+ expect(avatar).toHaveClass('h-16', 'w-16', 'text-xl');
57
+ });
58
+
59
+ it('applies correct variant classes', () => {
60
+ const { container, rerender } = render(<Avatar fallback="JD" variant="circle" />);
61
+ let avatar = container.querySelector('div[role="img"]');
62
+ expect(avatar).toHaveClass('rounded-full');
63
+
64
+ rerender(<Avatar fallback="JD" variant="square" />);
65
+ avatar = container.querySelector('div[role="img"]');
66
+ expect(avatar).toHaveClass('rounded-none');
67
+
68
+ rerender(<Avatar fallback="JD" variant="rounded" />);
69
+ avatar = container.querySelector('div[role="img"]');
70
+ expect(avatar).toHaveClass('rounded-md');
71
+ });
72
+
73
+ it('truncates fallback text to 2 characters', () => {
74
+ render(<Avatar fallback="John Doe" />);
75
+ expect(screen.getByText('JO')).toBeInTheDocument();
76
+ });
77
+
78
+ it('shows question mark when no fallback is provided', () => {
79
+ render(<Avatar alt="User" />);
80
+ expect(screen.getByText('?')).toBeInTheDocument();
81
+ });
82
+
83
+ it('has correct aria-label', () => {
84
+ render(<Avatar fallback="JD" alt="John Doe" />);
85
+ const avatar = screen.getByLabelText('John Doe');
86
+ expect(avatar).toBeInTheDocument();
87
+ expect(avatar).toHaveAttribute('role', 'img');
88
+ });
89
+
90
+ it('uses custom aria-label when provided', () => {
91
+ render(<Avatar fallback="JD" aria-label="Custom label" />);
92
+ const avatar = screen.getByLabelText('Custom label');
93
+ expect(avatar).toBeInTheDocument();
94
+ });
95
+
96
+ it('uses default aria-label when neither alt nor aria-label is provided', () => {
97
+ render(<Avatar fallback="JD" />);
98
+ const avatar = screen.getByLabelText('User avatar');
99
+ expect(avatar).toBeInTheDocument();
100
+ });
101
+
102
+ it('handles ReactNode fallback', () => {
103
+ render(<Avatar fallback={<span data-testid="custom-fallback">Custom</span>} />);
104
+ expect(screen.getByTestId('custom-fallback')).toBeInTheDocument();
105
+ });
106
+
107
+ it('applies custom className', () => {
108
+ const { container } = render(<Avatar fallback="JD" className="custom-class" />);
109
+ const avatar = container.querySelector('div[role="img"]');
110
+ expect(avatar).toHaveClass('custom-class');
111
+ });
112
+
113
+ it('passes through HTML attributes', () => {
114
+ const { container } = render(<Avatar fallback="JD" data-testid="avatar" />);
115
+ const avatar = container.querySelector('[data-testid="avatar"]');
116
+ expect(avatar).toBeInTheDocument();
117
+ });
118
+ });
119
+
120
+ describe('AvatarGroup', () => {
121
+ it('renders multiple avatars', () => {
122
+ render(
123
+ <AvatarGroup>
124
+ <Avatar fallback="U1" alt="User 1" />
125
+ <Avatar fallback="U2" alt="User 2" />
126
+ <Avatar fallback="U3" alt="User 3" />
127
+ </AvatarGroup>
128
+ );
129
+
130
+ expect(screen.getByText('U1')).toBeInTheDocument();
131
+ expect(screen.getByText('U2')).toBeInTheDocument();
132
+ expect(screen.getByText('U3')).toBeInTheDocument();
133
+ });
134
+
135
+ it('shows overflow indicator when max is exceeded', () => {
136
+ render(
137
+ <AvatarGroup max={2}>
138
+ <Avatar fallback="U1" alt="User 1" />
139
+ <Avatar fallback="U2" alt="User 2" />
140
+ <Avatar fallback="U3" alt="User 3" />
141
+ <Avatar fallback="U4" alt="User 4" />
142
+ </AvatarGroup>
143
+ );
144
+
145
+ expect(screen.getByText('U1')).toBeInTheDocument();
146
+ expect(screen.getByText('U2')).toBeInTheDocument();
147
+ expect(screen.getByText('+2')).toBeInTheDocument();
148
+ expect(screen.queryByText('U3')).not.toBeInTheDocument();
149
+ expect(screen.queryByText('U4')).not.toBeInTheDocument();
150
+ });
151
+
152
+ it('applies correct spacing classes', () => {
153
+ const { container, rerender } = render(
154
+ <AvatarGroup spacing="none">
155
+ <Avatar fallback="U1" />
156
+ <Avatar fallback="U2" />
157
+ </AvatarGroup>
158
+ );
159
+ let group = container.querySelector('div[role="group"]');
160
+ expect(group).not.toHaveClass('-space-x-1', '-space-x-2', '-space-x-3');
161
+
162
+ rerender(
163
+ <AvatarGroup spacing="sm">
164
+ <Avatar fallback="U1" />
165
+ <Avatar fallback="U2" />
166
+ </AvatarGroup>
167
+ );
168
+ group = container.querySelector('div[role="group"]');
169
+ expect(group).toHaveClass('-space-x-1');
170
+
171
+ rerender(
172
+ <AvatarGroup spacing="md">
173
+ <Avatar fallback="U1" />
174
+ <Avatar fallback="U2" />
175
+ </AvatarGroup>
176
+ );
177
+ group = container.querySelector('div[role="group"]');
178
+ expect(group).toHaveClass('-space-x-2');
179
+
180
+ rerender(
181
+ <AvatarGroup spacing="lg">
182
+ <Avatar fallback="U1" />
183
+ <Avatar fallback="U2" />
184
+ </AvatarGroup>
185
+ );
186
+ group = container.querySelector('div[role="group"]');
187
+ expect(group).toHaveClass('-space-x-3');
188
+ });
189
+
190
+ it('has correct aria-label with avatar count', () => {
191
+ render(
192
+ <AvatarGroup>
193
+ <Avatar fallback="U1" />
194
+ <Avatar fallback="U2" />
195
+ <Avatar fallback="U3" />
196
+ </AvatarGroup>
197
+ );
198
+
199
+ const group = screen.getByLabelText('3 avatars');
200
+ expect(group).toBeInTheDocument();
201
+ expect(group).toHaveAttribute('role', 'group');
202
+ });
203
+
204
+ it('applies size and variant to overflow avatar', () => {
205
+ render(
206
+ <AvatarGroup max={1} size="lg" variant="square">
207
+ <Avatar fallback="U1" />
208
+ <Avatar fallback="U2" />
209
+ </AvatarGroup>
210
+ );
211
+
212
+ const overflowAvatar = screen.getByText('+1');
213
+ const overflowContainer = overflowAvatar.closest('div[role="img"]');
214
+ expect(overflowContainer).toHaveClass('h-12', 'w-12', 'text-lg', 'rounded-none');
215
+ });
216
+
217
+ it('handles empty children gracefully', () => {
218
+ const { container } = render(<AvatarGroup>{null}</AvatarGroup>);
219
+ const group = container.querySelector('div[role="group"]');
220
+ expect(group).toBeInTheDocument();
221
+ expect(group?.children.length).toBe(0);
222
+ });
223
+
224
+ it('applies custom className', () => {
225
+ const { container } = render(
226
+ <AvatarGroup className="custom-group">
227
+ <Avatar fallback="U1" />
228
+ </AvatarGroup>
229
+ );
230
+ const group = container.querySelector('div[role="group"]');
231
+ expect(group).toHaveClass('custom-group');
232
+ });
233
+ });