@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
@@ -1,17 +1,24 @@
1
1
  'use client';
2
2
 
3
- import type { ButtonHTMLAttributes, ReactNode } from 'react';
3
+ import { forwardRef } from 'react';
4
+ import type { ButtonHTMLAttributes, ReactNode, ElementType } from 'react';
4
5
  import { getColorClass } from '../../tokens/colors';
6
+ import Spinner from '../Spinner/Spinner';
5
7
 
6
- export type ButtonVariant = 'primary' | 'regular' | 'secondary' | 'error' | 'outline' | 'ghost';
8
+ export type ButtonVariant = 'primary' | 'regular' | 'secondary' | 'error' | 'outline' | 'ghost' | 'iconOnly';
7
9
  export type ButtonSize = 'sm' | 'md' | 'lg';
8
10
 
9
- export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
11
+ export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'as'> {
10
12
  variant?: ButtonVariant;
11
13
  size?: ButtonSize;
12
14
  isLoading?: boolean;
15
+ loadingText?: string;
16
+ loadingIcon?: ReactNode;
13
17
  leftIcon?: ReactNode;
14
18
  rightIcon?: ReactNode;
19
+ fullWidth?: boolean;
20
+ as?: ElementType;
21
+ href?: string;
15
22
  }
16
23
 
17
24
  /**
@@ -40,58 +47,95 @@ class ButtonClassBuilder {
40
47
 
41
48
  addVariant(variant: ButtonVariant): this {
42
49
  // Map 'regular' to 'primary' for backward compatibility
50
+ // TODO: Remove 'regular' in next major version
43
51
  const normalizedVariant = variant === 'regular' ? 'primary' : variant;
44
52
 
45
- const variantClasses: Record<'primary' | 'secondary' | 'error' | 'outline' | 'ghost', string[]> = {
53
+
54
+ if (variant === 'regular' && process.env.NODE_ENV === 'development') {
55
+ console.warn(
56
+ 'Button variant "regular" is deprecated. Use "primary" instead. ' +
57
+ 'This mapping will be removed in the next major version.'
58
+ );
59
+ }
60
+
61
+ type NormalizedVariant = Exclude<ButtonVariant, 'regular'>;
62
+
63
+ const variantClasses: Record<NormalizedVariant, string[]> = {
46
64
  primary: [
47
65
  getColorClass('primary', 'DEFAULT', 'bg'),
48
- getColorClass('primary', 'DEFAULT', 'text'),
66
+ 'text-white',
49
67
  'hover:opacity-90',
50
68
  'focus:ring-indigo-500',
51
69
  ],
52
70
  secondary: [
53
71
  getColorClass('secondary', 'DEFAULT', 'bg'),
54
- getColorClass('secondary', 'DEFAULT', 'text'),
72
+ 'text-white',
55
73
  'hover:opacity-90',
56
74
  'focus:ring-violet-500',
57
75
  ],
58
76
  error: [
59
77
  getColorClass('error', 'DEFAULT', 'bg'),
60
- getColorClass('error', 'DEFAULT', 'text'),
78
+ 'text-white',
61
79
  'hover:opacity-90',
62
80
  'focus:ring-red-500',
63
81
  ],
64
82
  outline: [
65
83
  'border-2',
66
- 'border-gray-300',
84
+ getColorClass('neutral', 'DEFAULT', 'border'),
67
85
  'bg-transparent',
68
- 'text-gray-700',
86
+ getColorClass('neutral', 'dark', 'text'),
69
87
  'hover:bg-gray-50',
70
88
  'focus:ring-gray-500',
71
89
  ],
72
90
  ghost: [
73
91
  'bg-transparent',
74
- 'text-gray-700',
92
+ getColorClass('neutral', 'dark', 'text'),
75
93
  'hover:bg-gray-100',
76
94
  'focus:ring-gray-500',
77
95
  ],
96
+ iconOnly: [
97
+ 'bg-transparent',
98
+ getColorClass('neutral', 'dark', 'text'),
99
+ 'hover:bg-gray-100',
100
+ 'focus:ring-gray-500',
101
+ 'p-0',
102
+ ],
78
103
  };
79
104
 
80
- this.classes.push(...variantClasses[normalizedVariant]);
105
+ this.classes.push(...variantClasses[normalizedVariant as NormalizedVariant]);
81
106
  return this;
82
107
  }
83
108
 
84
- addSize(size: ButtonSize): this {
109
+ addSize(size: ButtonSize, variant: ButtonVariant): this {
110
+ // Normalize variant for size calculation
111
+ const normalizedVariant = variant === 'regular' ? 'primary' : variant;
112
+
113
+ // IconOnly variant has different sizing
114
+ if (normalizedVariant === 'iconOnly') {
115
+ const iconSizeClasses: Record<ButtonSize, string[]> = {
116
+ sm: ['h-8', 'w-8', 'p-0'],
117
+ md: ['h-10', 'w-10', 'p-0'],
118
+ lg: ['h-12', 'w-12', 'p-0'],
119
+ };
120
+ this.classes.push(...iconSizeClasses[size]);
121
+ return this;
122
+ }
123
+
85
124
  const sizeClasses: Record<ButtonSize, string[]> = {
86
- sm: ['px-3', 'py-1.5', 'text-sm'],
87
- md: ['px-4', 'py-2', 'text-base'],
88
- lg: ['px-6', 'py-3', 'text-lg'],
125
+ sm: ['px-3', 'py-1.5', 'text-sm', 'gap-1.5'],
126
+ md: ['px-4', 'py-2', 'text-base', 'gap-2'],
127
+ lg: ['px-6', 'py-3', 'text-lg', 'gap-2.5'],
89
128
  };
90
129
 
91
130
  this.classes.push(...sizeClasses[size]);
92
131
  return this;
93
132
  }
94
133
 
134
+ addFullWidth(): this {
135
+ this.classes.push('w-full');
136
+ return this;
137
+ }
138
+
95
139
  addCustom(className: string): this {
96
140
  if (className) {
97
141
  this.classes.push(className);
@@ -104,80 +148,143 @@ class ButtonClassBuilder {
104
148
  }
105
149
  }
106
150
 
151
+ /**
152
+ * Icon Wrapper Component
153
+ * Handles icon spacing and alignment consistently
154
+ */
155
+ function IconWrapper({
156
+ children,
157
+ position
158
+ }: {
159
+ children: ReactNode;
160
+ position: 'left' | 'right';
161
+ }) {
162
+ if (!children) return null;
163
+
164
+ return (
165
+ <span className={`inline-flex items-center ${position === 'left' ? 'mr-0' : 'ml-0'}`}>
166
+ {children}
167
+ </span>
168
+ );
169
+ }
170
+
107
171
  /**
108
172
  * Button Component
109
173
  *
110
- * A styled button component with variants and sizes.
174
+ * A styled button component with variants, sizes, and loading states.
111
175
  * Follows Atomic Design principles as an Atom component.
112
176
  * Uses Builder Pattern for class construction.
177
+ * Supports polymorphic `as` prop for rendering as different elements (Link, NextLink, etc.).
113
178
  *
114
179
  * @example
115
180
  * ```tsx
116
- * <Button
117
- * variant="primary"
118
- * size="md"
119
- * onClick={handleClick}
120
- * >
181
+ * // Basic usage
182
+ * <Button variant="primary" size="md" onClick={handleClick}>
121
183
  * Click me
122
184
  * </Button>
185
+ *
186
+ * // With icons
187
+ * <Button leftIcon={<Icon />} rightIcon={<Icon />}>
188
+ * Action
189
+ * </Button>
190
+ *
191
+ * // Loading state
192
+ * <Button isLoading loadingText="Saving...">
193
+ * Save
194
+ * </Button>
195
+ *
196
+ * // As Link
197
+ * <Button as={Link} href="/page">
198
+ * Navigate
199
+ * </Button>
200
+ *
201
+ * // Icon only
202
+ * <Button variant="iconOnly" leftIcon={<Icon />} aria-label="Close" />
123
203
  * ```
124
204
  */
125
- export default function Button({
205
+ const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button({
126
206
  variant = 'primary',
127
207
  size = 'md',
128
208
  isLoading = false,
209
+ loadingText,
210
+ loadingIcon,
129
211
  leftIcon,
130
212
  rightIcon,
213
+ fullWidth = false,
214
+ as: Component = 'button',
131
215
  className = '',
132
216
  disabled = false,
133
217
  children,
218
+ 'aria-label': ariaLabel,
134
219
  ...props
135
- }: ButtonProps) {
220
+ }, ref) {
136
221
  const builder = new ButtonClassBuilder();
137
222
  const classes = builder
138
223
  .addBase()
139
224
  .addVariant(variant)
140
- .addSize(size)
225
+ .addSize(size, variant)
226
+ .addFullWidth(fullWidth)
141
227
  .addCustom(className)
142
228
  .build();
143
229
 
230
+ // Determine if button is icon-only (no children, only icons)
231
+ const isIconOnly = variant === 'iconOnly' || (!children && (leftIcon || rightIcon));
232
+
233
+ // Aria label is required for icon-only buttons
234
+ const finalAriaLabel = isIconOnly && !ariaLabel && !children
235
+ ? 'Button' // Fallback, but should be provided
236
+ : ariaLabel;
237
+
238
+ // Normalize variant for spinner
239
+ const normalizedVariant = variant === 'regular' ? 'primary' : variant;
240
+
241
+ // Determine spinner variant based on button variant
242
+ const getSpinnerVariant = (): 'primary' | 'secondary' | 'neutral' => {
243
+ if (normalizedVariant === 'error') return 'primary'; // Red buttons use primary spinner (white)
244
+ if (normalizedVariant === 'primary' || normalizedVariant === 'secondary') return 'neutral'; // Colored buttons use neutral spinner
245
+ return 'primary'; // Default
246
+ };
247
+
248
+ // Loading state
249
+ const displayLoadingIcon = loadingIcon || (
250
+ <Spinner
251
+ size={size === 'sm' ? 'sm' : size === 'lg' ? 'lg' : 'md'}
252
+ variant={getSpinnerVariant()}
253
+ />
254
+ );
255
+
256
+ const buttonProps = {
257
+ className: classes,
258
+ disabled: disabled || isLoading,
259
+ 'aria-busy': isLoading,
260
+ 'aria-label': finalAriaLabel,
261
+ 'aria-disabled': disabled || isLoading,
262
+ ...(Component === 'button' ? { type: 'button' as const } : {}),
263
+ ...props,
264
+ };
265
+
144
266
  return (
145
- <button
146
- className={classes}
147
- disabled={disabled || isLoading}
148
- {...props}
267
+ <Component
268
+ ref={ref}
269
+ {...buttonProps}
149
270
  >
150
271
  {isLoading ? (
151
272
  <>
152
- <svg
153
- className="animate-spin -ml-1 mr-2 h-4 w-4"
154
- xmlns="http://www.w3.org/2000/svg"
155
- fill="none"
156
- viewBox="0 0 24 24"
157
- >
158
- <circle
159
- className="opacity-25"
160
- cx="12"
161
- cy="12"
162
- r="10"
163
- stroke="currentColor"
164
- strokeWidth="4"
165
- />
166
- <path
167
- className="opacity-75"
168
- fill="currentColor"
169
- d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
170
- />
171
- </svg>
172
- Loading...
273
+ {displayLoadingIcon}
274
+ {loadingText && <span className="ml-2">{loadingText}</span>}
275
+ {!loadingText && children && <span className="ml-2 opacity-0">{children}</span>}
173
276
  </>
174
277
  ) : (
175
278
  <>
176
- {leftIcon && <span className="mr-2">{leftIcon}</span>}
279
+ {leftIcon && <IconWrapper position="left">{leftIcon}</IconWrapper>}
177
280
  {children}
178
- {rightIcon && <span className="ml-2">{rightIcon}</span>}
281
+ {rightIcon && <IconWrapper position="right">{rightIcon}</IconWrapper>}
179
282
  </>
180
283
  )}
181
- </button>
284
+ </Component>
182
285
  );
183
- }
286
+ });
287
+
288
+ Button.displayName = 'Button';
289
+
290
+ export default Button;
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { useRef, useEffect } from 'react';
3
4
  import type { InputHTMLAttributes, ReactNode } from 'react';
4
5
  import { getTypographyClasses } from '../../tokens/typography';
5
6
 
@@ -7,6 +8,7 @@ export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement
7
8
  label?: ReactNode;
8
9
  error?: boolean;
9
10
  helperText?: string;
11
+ indeterminate?: boolean;
10
12
  }
11
13
 
12
14
  /**
@@ -33,6 +35,7 @@ export default function Checkbox({
33
35
  helperText,
34
36
  className = '',
35
37
  disabled = false,
38
+ indeterminate = false,
36
39
  ...props
37
40
  }: CheckboxProps) {
38
41
  const checkboxId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
@@ -68,12 +71,22 @@ export default function Checkbox({
68
71
  disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',
69
72
  ].filter(Boolean).join(' ');
70
73
 
74
+ // Set indeterminate state via ref
75
+ const checkboxRef = useRef<HTMLInputElement>(null);
76
+
77
+ useEffect(() => {
78
+ if (checkboxRef.current) {
79
+ checkboxRef.current.indeterminate = indeterminate;
80
+ }
81
+ }, [indeterminate]);
82
+
71
83
  return (
72
84
  <div className={`flex flex-col my-2 ${className}`}>
73
85
  <div className="flex items-center">
74
86
  <input
75
87
  type="checkbox"
76
88
  id={checkboxId}
89
+ ref={checkboxRef}
77
90
  className={checkboxClasses}
78
91
  disabled={disabled}
79
92
  aria-invalid={error}
@@ -95,7 +108,7 @@ export default function Checkbox({
95
108
  className={`mt-1 ${getTypographyClasses('caption')} ${error ? 'text-red-600' : 'text-gray-500'}`}
96
109
  role={error ? 'alert' : undefined}
97
110
  >
98
- {error || helperText}
111
+ {helperText || (error ? 'Error' : '')}
99
112
  </div>
100
113
  )}
101
114
  </div>
@@ -4,7 +4,7 @@ import Collapsible from "./Collapsible";
4
4
  import { Button, Text } from "../../atoms";
5
5
 
6
6
  const meta: Meta<typeof Collapsible> = {
7
- title: "UI/Atoms/Collapsible",
7
+ title: "Atoms/Collapsible",
8
8
  component: Collapsible,
9
9
  parameters: {
10
10
  docs: {
@@ -121,4 +121,50 @@ export const Disabled: StoryObj<typeof Collapsible> = {
121
121
  },
122
122
  };
123
123
 
124
+ export const Accessibility: StoryObj<typeof Collapsible> = {
125
+ args: {
126
+ defaultOpen: false,
127
+ trigger: (
128
+ <div className="px-4 py-2 bg-gray-100 rounded-md">
129
+ <Text as="span" className="font-medium">Accessible Collapsible</Text>
130
+ </div>
131
+ ),
132
+ children: (
133
+ <div className="px-4 py-2">
134
+ <Text>This collapsible has proper ARIA attributes: aria-expanded, aria-controls, and keyboard support (Enter/Space).</Text>
135
+ </div>
136
+ ),
137
+ },
138
+ parameters: {
139
+ docs: {
140
+ description: {
141
+ story: 'Demonstrates accessibility features: aria-expanded indicates state, aria-controls links trigger to content, and keyboard support (Enter/Space to toggle).',
142
+ },
143
+ },
144
+ },
145
+ };
146
+
147
+ export const KeyboardNavigation: StoryObj<typeof Collapsible> = {
148
+ args: {
149
+ defaultOpen: false,
150
+ trigger: (
151
+ <div className="px-4 py-2 bg-gray-100 rounded-md">
152
+ <Text as="span" className="font-medium">Try Keyboard Navigation</Text>
153
+ </div>
154
+ ),
155
+ children: (
156
+ <div className="px-4 py-2">
157
+ <Text>Tab to focus, then press Enter or Space to toggle. The aria-expanded attribute updates automatically.</Text>
158
+ </div>
159
+ ),
160
+ },
161
+ parameters: {
162
+ docs: {
163
+ description: {
164
+ story: 'Use Tab to focus the trigger, then Enter or Space to toggle. Screen readers will announce the state change.',
165
+ },
166
+ },
167
+ },
168
+ };
169
+
124
170
  export default meta;
@@ -5,17 +5,28 @@ import Collapsible from './Collapsible';
5
5
  describe('Collapsible', () => {
6
6
  beforeEach(() => {
7
7
  // Clear localStorage before each test
8
- localStorage.clear();
8
+ try {
9
+ localStorage.clear();
10
+ } catch {
11
+ // If clear is not available, remove items manually
12
+ Object.keys(localStorage).forEach(key => localStorage.removeItem(key));
13
+ }
9
14
  });
10
15
 
11
16
  afterEach(() => {
12
- localStorage.clear();
17
+ // Clear localStorage after each test
18
+ try {
19
+ localStorage.clear();
20
+ } catch {
21
+ // If clear is not available, remove items manually
22
+ Object.keys(localStorage).forEach(key => localStorage.removeItem(key));
23
+ }
13
24
  });
14
25
 
15
26
  it('renders trigger and children', () => {
16
27
  render(
17
28
  <Collapsible
18
- trigger={<button>Toggle</button>}
29
+ trigger={<span>Toggle</span>}
19
30
  defaultOpen={true}
20
31
  >
21
32
  <div>Content</div>
@@ -29,43 +40,43 @@ describe('Collapsible', () => {
29
40
  it('starts open when defaultOpen is true', () => {
30
41
  render(
31
42
  <Collapsible
32
- trigger={<button>Toggle</button>}
43
+ trigger={<span>Toggle</span>}
33
44
  defaultOpen={true}
34
45
  >
35
46
  <div>Content</div>
36
47
  </Collapsible>
37
48
  );
38
49
 
39
- const content = screen.getByText('Content').parentElement;
50
+ const content = screen.getByText('Content').parentElement?.parentElement;
40
51
  expect(content).toHaveAttribute('aria-hidden', 'false');
41
52
  });
42
53
 
43
54
  it('starts closed when defaultOpen is false', () => {
44
55
  render(
45
56
  <Collapsible
46
- trigger={<button>Toggle</button>}
57
+ trigger={<span>Toggle</span>}
47
58
  defaultOpen={false}
48
59
  >
49
60
  <div>Content</div>
50
61
  </Collapsible>
51
62
  );
52
63
 
53
- const content = screen.getByText('Content').parentElement;
64
+ const content = screen.getByText('Content').parentElement?.parentElement;
54
65
  expect(content).toHaveAttribute('aria-hidden', 'true');
55
66
  });
56
67
 
57
68
  it('toggles content when trigger is clicked', async () => {
58
69
  render(
59
70
  <Collapsible
60
- trigger={<button>Toggle</button>}
71
+ trigger={<span>Toggle</span>}
61
72
  defaultOpen={true}
62
73
  >
63
74
  <div>Content</div>
64
75
  </Collapsible>
65
76
  );
66
77
 
67
- const button = screen.getByText('Toggle');
68
- const content = screen.getByText('Content').parentElement;
78
+ const button = screen.getByText('Toggle').closest('button');
79
+ const content = screen.getByText('Content').parentElement?.parentElement;
69
80
 
70
81
  expect(content).toHaveAttribute('aria-hidden', 'false');
71
82
 
@@ -80,7 +91,7 @@ describe('Collapsible', () => {
80
91
  const handleOpenChange = vi.fn();
81
92
  render(
82
93
  <Collapsible
83
- trigger={<button>Toggle</button>}
94
+ trigger={<span>Toggle</span>}
84
95
  open={true}
85
96
  onOpenChange={handleOpenChange}
86
97
  >
@@ -88,8 +99,8 @@ describe('Collapsible', () => {
88
99
  </Collapsible>
89
100
  );
90
101
 
91
- const button = screen.getByText('Toggle');
92
- fireEvent.click(button);
102
+ const button = screen.getByText('Toggle').closest('button');
103
+ fireEvent.click(button!);
93
104
 
94
105
  expect(handleOpenChange).toHaveBeenCalledWith(false);
95
106
  });
@@ -99,7 +110,7 @@ describe('Collapsible', () => {
99
110
 
100
111
  const { rerender } = render(
101
112
  <Collapsible
102
- trigger={<button>Toggle</button>}
113
+ trigger={<span>Toggle</span>}
103
114
  defaultOpen={true}
104
115
  storageKey={storageKey}
105
116
  >
@@ -107,8 +118,8 @@ describe('Collapsible', () => {
107
118
  </Collapsible>
108
119
  );
109
120
 
110
- const button = screen.getByText('Toggle');
111
- fireEvent.click(button);
121
+ const button = screen.getByText('Toggle').closest('button');
122
+ fireEvent.click(button!);
112
123
 
113
124
  await waitFor(() => {
114
125
  expect(localStorage.getItem(storageKey)).toBe('false');
@@ -117,7 +128,7 @@ describe('Collapsible', () => {
117
128
  // Re-render and check state is restored
118
129
  rerender(
119
130
  <Collapsible
120
- trigger={<button>Toggle</button>}
131
+ trigger={<span>Toggle</span>}
121
132
  defaultOpen={true}
122
133
  storageKey={storageKey}
123
134
  >
@@ -125,14 +136,14 @@ describe('Collapsible', () => {
125
136
  </Collapsible>
126
137
  );
127
138
 
128
- const content = screen.getByText('Content').parentElement;
139
+ const content = screen.getByText('Content').parentElement?.parentElement;
129
140
  expect(content).toHaveAttribute('aria-hidden', 'true');
130
141
  });
131
142
 
132
143
  it('does not toggle when disabled', async () => {
133
144
  render(
134
145
  <Collapsible
135
- trigger={<button>Toggle</button>}
146
+ trigger={<span>Toggle</span>}
136
147
  defaultOpen={true}
137
148
  disabled={true}
138
149
  >
@@ -140,13 +151,13 @@ describe('Collapsible', () => {
140
151
  </Collapsible>
141
152
  );
142
153
 
143
- const button = screen.getByText('Toggle');
144
- const content = screen.getByText('Content').parentElement;
154
+ const button = screen.getByText('Toggle').closest('button');
155
+ const content = screen.getByText('Content').parentElement?.parentElement;
145
156
 
146
157
  expect(button).toBeDisabled();
147
158
  expect(content).toHaveAttribute('aria-hidden', 'false');
148
159
 
149
- fireEvent.click(button);
160
+ fireEvent.click(button!);
150
161
 
151
162
  // State should not change
152
163
  await waitFor(() => {
@@ -157,18 +168,19 @@ describe('Collapsible', () => {
157
168
  it('has correct ARIA attributes', () => {
158
169
  render(
159
170
  <Collapsible
160
- trigger={<button>Toggle</button>}
171
+ trigger={<span>Toggle</span>}
161
172
  defaultOpen={true}
162
173
  >
163
174
  <div>Content</div>
164
175
  </Collapsible>
165
176
  );
166
177
 
167
- const button = screen.getByText('Toggle');
178
+ const button = screen.getByText('Toggle').closest('button');
168
179
  const content = screen.getByText('Content').parentElement?.parentElement;
169
180
 
170
181
  expect(button).toHaveAttribute('aria-expanded', 'true');
171
182
  expect(button).toHaveAttribute('aria-controls');
172
183
  expect(content).toHaveAttribute('id');
184
+ expect(content).toHaveAttribute('aria-hidden', 'false');
173
185
  });
174
186
  });
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useEffect, useRef, useState, type HTMLAttributes, type ReactNode } from 'react';
3
+ import { useEffect, useRef, useState, type HTMLAttributes, type ReactNode, type KeyboardEvent } from 'react';
4
4
  import { useCollapsible, type UseCollapsibleOptions } from '../../hooks/useCollapsible';
5
5
 
6
6
  export interface CollapsibleProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
@@ -90,6 +90,14 @@ export default function Collapsible({
90
90
  <button
91
91
  type="button"
92
92
  onClick={toggle}
93
+ onKeyDown={(e: KeyboardEvent<HTMLButtonElement>) => {
94
+ if (e.key === 'Enter' || e.key === ' ') {
95
+ e.preventDefault();
96
+ if (!disabled) {
97
+ toggle();
98
+ }
99
+ }
100
+ }}
93
101
  disabled={disabled}
94
102
  aria-expanded={isOpen}
95
103
  aria-controls={contentId}
@@ -3,7 +3,7 @@ import ErrorMessage from "./ErrorMessage";
3
3
  import { Input, Label } from "../../atoms";
4
4
 
5
5
  const meta: Meta<typeof ErrorMessage> = {
6
- title: "UI/Atoms/ErrorMessage",
6
+ title: "Atoms/ErrorMessage",
7
7
  component: ErrorMessage,
8
8
  parameters: {
9
9
  docs: {
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react";
2
2
  import Info from "./Info";
3
3
 
4
4
  const meta: Meta<typeof Info> = {
5
- title: "UI/Atoms/Info",
5
+ title: "Atoms/Info",
6
6
  component: Info,
7
7
  };
8
8