@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,226 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { useState } from 'react';
3
+ import Dialog from './Dialog';
4
+ import AlertDialog from './AlertDialog';
5
+ import { Button } from '../../atoms';
6
+ import { Input, Label } from '../../atoms';
7
+
8
+ const meta: Meta<typeof Dialog> = {
9
+ title: 'Organisms/Dialog',
10
+ component: Dialog,
11
+ parameters: {
12
+ docs: {
13
+ description: {
14
+ component: 'A flexible dialog component using compound components pattern. Supports both controlled and uncontrolled modes. Includes portal rendering, focus trap, and full accessibility.',
15
+ },
16
+ },
17
+ },
18
+ };
19
+
20
+ export default meta;
21
+ type Story = StoryObj<typeof Dialog>;
22
+
23
+ export const Default: Story = {
24
+ render: () => {
25
+ const [isOpen, setIsOpen] = useState(false);
26
+ return (
27
+ <>
28
+ <Button onClick={() => setIsOpen(true)}>Open Dialog</Button>
29
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
30
+ <Dialog.Content>
31
+ <Dialog.Header>
32
+ <Dialog.Title>Dialog Title</Dialog.Title>
33
+ <Dialog.Description>
34
+ This is a dialog description. It provides additional context about the dialog.
35
+ </Dialog.Description>
36
+ </Dialog.Header>
37
+ <div className="p-6 pt-0">
38
+ <p>Dialog content goes here.</p>
39
+ </div>
40
+ <Dialog.Footer>
41
+ <Button variant="outline" onClick={() => setIsOpen(false)}>
42
+ Cancel
43
+ </Button>
44
+ <Button onClick={() => setIsOpen(false)}>Confirm</Button>
45
+ </Dialog.Footer>
46
+ </Dialog.Content>
47
+ </Dialog>
48
+ </>
49
+ );
50
+ },
51
+ };
52
+
53
+ export const Uncontrolled: Story = {
54
+ render: () => (
55
+ <Dialog>
56
+ <Dialog.Trigger asChild>
57
+ <Button>Open Dialog</Button>
58
+ </Dialog.Trigger>
59
+ <Dialog.Content>
60
+ <Dialog.Close />
61
+ <Dialog.Header>
62
+ <Dialog.Title>Uncontrolled Dialog</Dialog.Title>
63
+ <Dialog.Description>
64
+ This dialog uses uncontrolled mode with Dialog.Trigger.
65
+ </Dialog.Description>
66
+ </Dialog.Header>
67
+ <div className="p-6 pt-0">
68
+ <p>Click outside or press Escape to close.</p>
69
+ </div>
70
+ </Dialog.Content>
71
+ </Dialog>
72
+ ),
73
+ };
74
+
75
+ export const WithForm: Story = {
76
+ render: () => {
77
+ const [isOpen, setIsOpen] = useState(false);
78
+ return (
79
+ <>
80
+ <Button onClick={() => setIsOpen(true)}>Open Form Dialog</Button>
81
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
82
+ <Dialog.Content size="lg">
83
+ <Dialog.Header>
84
+ <Dialog.Title>Create New Item</Dialog.Title>
85
+ <Dialog.Description>
86
+ Fill in the form below to create a new item.
87
+ </Dialog.Description>
88
+ </Dialog.Header>
89
+ <div className="p-6 pt-0 space-y-4">
90
+ <div>
91
+ <Label htmlFor="name">Name</Label>
92
+ <Input id="name" placeholder="Enter name" />
93
+ </div>
94
+ <div>
95
+ <Label htmlFor="email">Email</Label>
96
+ <Input id="email" type="email" placeholder="Enter email" />
97
+ </div>
98
+ </div>
99
+ <Dialog.Footer>
100
+ <Button variant="outline" onClick={() => setIsOpen(false)}>
101
+ Cancel
102
+ </Button>
103
+ <Button onClick={() => setIsOpen(false)}>Create</Button>
104
+ </Dialog.Footer>
105
+ </Dialog.Content>
106
+ </Dialog>
107
+ </>
108
+ );
109
+ },
110
+ };
111
+
112
+ export const Sizes: Story = {
113
+ render: () => {
114
+ const [size, setSize] = useState<'sm' | 'md' | 'lg' | 'xl' | 'fullscreen'>('md');
115
+ const [isOpen, setIsOpen] = useState(false);
116
+ return (
117
+ <>
118
+ <div className="space-x-2 mb-4">
119
+ {(['sm', 'md', 'lg', 'xl', 'fullscreen'] as const).map((s) => (
120
+ <Button key={s} variant={size === s ? 'primary' : 'outline'} onClick={() => { setSize(s); setIsOpen(true); }}>
121
+ {s}
122
+ </Button>
123
+ ))}
124
+ </div>
125
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
126
+ <Dialog.Content size={size}>
127
+ <Dialog.Header>
128
+ <Dialog.Title>Dialog Size: {size}</Dialog.Title>
129
+ <Dialog.Description>
130
+ This dialog demonstrates the {size} size variant.
131
+ </Dialog.Description>
132
+ </Dialog.Header>
133
+ <div className="p-6 pt-0">
134
+ <p>Content area for {size} dialog.</p>
135
+ </div>
136
+ <Dialog.Footer>
137
+ <Button variant="outline" onClick={() => setIsOpen(false)}>
138
+ Close
139
+ </Button>
140
+ </Dialog.Footer>
141
+ </Dialog.Content>
142
+ </Dialog>
143
+ </>
144
+ );
145
+ },
146
+ };
147
+
148
+ export const WithoutOverlayClose: Story = {
149
+ render: () => {
150
+ const [isOpen, setIsOpen] = useState(false);
151
+ return (
152
+ <>
153
+ <Button onClick={() => setIsOpen(true)}>Open Dialog</Button>
154
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
155
+ <Dialog.Content closeOnOverlayClick={false}>
156
+ <Dialog.Header>
157
+ <Dialog.Title>Important Dialog</Dialog.Title>
158
+ <Dialog.Description>
159
+ This dialog cannot be closed by clicking the overlay. You must use the close button or Escape key.
160
+ </Dialog.Description>
161
+ </Dialog.Header>
162
+ <div className="p-6 pt-0">
163
+ <p>Click outside won't close this dialog.</p>
164
+ </div>
165
+ <Dialog.Footer>
166
+ <Button onClick={() => setIsOpen(false)}>Close</Button>
167
+ </Dialog.Footer>
168
+ </Dialog.Content>
169
+ </Dialog>
170
+ </>
171
+ );
172
+ },
173
+ };
174
+
175
+ // AlertDialog Stories
176
+ const _alertDialogMeta: Meta<typeof AlertDialog> = {
177
+ title: 'Organisms/Dialog/AlertDialog',
178
+ component: AlertDialog,
179
+ parameters: {
180
+ docs: {
181
+ description: {
182
+ component: 'A specialized dialog for confirmations and alerts. Built on top of Dialog with pre-configured layout.',
183
+ },
184
+ },
185
+ },
186
+ tags: ['autodocs'],
187
+ };
188
+
189
+ export const AlertDialogDefault: StoryObj<typeof AlertDialog> = {
190
+ render: () => {
191
+ const [isOpen, setIsOpen] = useState(false);
192
+ return (
193
+ <>
194
+ <Button onClick={() => setIsOpen(true)}>Open Alert</Button>
195
+ <AlertDialog
196
+ open={isOpen}
197
+ onOpenChange={setIsOpen}
198
+ title="Confirm Action"
199
+ description="Are you sure you want to proceed with this action?"
200
+ onConfirm={() => alert('Confirmed!')}
201
+ />
202
+ </>
203
+ );
204
+ },
205
+ };
206
+
207
+ export const AlertDialogDestructive: StoryObj<typeof AlertDialog> = {
208
+ render: () => {
209
+ const [isOpen, setIsOpen] = useState(false);
210
+ return (
211
+ <>
212
+ <Button variant="error" onClick={() => setIsOpen(true)}>Delete Item</Button>
213
+ <AlertDialog
214
+ open={isOpen}
215
+ onOpenChange={setIsOpen}
216
+ title="Delete Item"
217
+ description="Are you sure? This action cannot be undone."
218
+ variant="destructive"
219
+ confirmLabel="Delete"
220
+ cancelLabel="Cancel"
221
+ onConfirm={() => alert('Deleted!')}
222
+ />
223
+ </>
224
+ );
225
+ },
226
+ };
@@ -0,0 +1,435 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import Dialog from './Dialog';
5
+ import Button from '../../atoms/Button/Button';
6
+
7
+ describe('Dialog', () => {
8
+ beforeEach(() => {
9
+ document.body.innerHTML = '';
10
+ });
11
+
12
+ afterEach(() => {
13
+ vi.clearAllTimers();
14
+ // Restore body overflow
15
+ document.body.style.overflow = '';
16
+ });
17
+
18
+ describe('Rendering', () => {
19
+ it('renders dialog trigger', () => {
20
+ render(
21
+ <Dialog>
22
+ <Dialog.Trigger>Open Dialog</Dialog.Trigger>
23
+ <Dialog.Content>
24
+ <Dialog.Title>Test Dialog</Dialog.Title>
25
+ </Dialog.Content>
26
+ </Dialog>
27
+ );
28
+
29
+ expect(screen.getByText('Open Dialog')).toBeInTheDocument();
30
+ });
31
+
32
+ it('does not render content when closed', () => {
33
+ render(
34
+ <Dialog defaultOpen={false}>
35
+ <Dialog.Trigger>Open</Dialog.Trigger>
36
+ <Dialog.Content>
37
+ <Dialog.Title>Test Dialog</Dialog.Title>
38
+ </Dialog.Content>
39
+ </Dialog>
40
+ );
41
+
42
+ expect(screen.queryByText('Test Dialog')).not.toBeInTheDocument();
43
+ });
44
+
45
+ it('renders content when open', () => {
46
+ render(
47
+ <Dialog defaultOpen>
48
+ <Dialog.Content>
49
+ <Dialog.Title>Test Dialog</Dialog.Title>
50
+ </Dialog.Content>
51
+ </Dialog>
52
+ );
53
+
54
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
55
+ });
56
+ });
57
+
58
+ describe('Opening and Closing', () => {
59
+ it('opens dialog when trigger is clicked', async () => {
60
+ const user = userEvent.setup();
61
+ render(
62
+ <Dialog>
63
+ <Dialog.Trigger>Open Dialog</Dialog.Trigger>
64
+ <Dialog.Content>
65
+ <Dialog.Title>Test Dialog</Dialog.Title>
66
+ </Dialog.Content>
67
+ </Dialog>
68
+ );
69
+
70
+ const trigger = screen.getByText('Open Dialog');
71
+ await user.click(trigger);
72
+
73
+ await waitFor(() => {
74
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
75
+ });
76
+ });
77
+
78
+ it('closes dialog when overlay is clicked', async () => {
79
+ const user = userEvent.setup();
80
+ render(
81
+ <Dialog defaultOpen>
82
+ <Dialog.Content closeOnOverlayClick>
83
+ <Dialog.Title>Test Dialog</Dialog.Title>
84
+ </Dialog.Content>
85
+ </Dialog>
86
+ );
87
+
88
+ await waitFor(() => {
89
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
90
+ });
91
+
92
+ // Find the overlay (the div with aria-hidden="true" and bg-black)
93
+ const overlay = document.querySelector('[aria-hidden="true"].bg-black');
94
+ if (overlay) {
95
+ // Click directly on the overlay
96
+ await user.click(overlay as HTMLElement);
97
+
98
+ await waitFor(() => {
99
+ expect(screen.queryByText('Test Dialog')).not.toBeInTheDocument();
100
+ }, { timeout: 2000 });
101
+ }
102
+ });
103
+
104
+ it('does not close dialog when content is clicked', async () => {
105
+ const user = userEvent.setup();
106
+ render(
107
+ <Dialog defaultOpen>
108
+ <Dialog.Content closeOnOverlayClick>
109
+ <Dialog.Title>Test Dialog</Dialog.Title>
110
+ </Dialog.Content>
111
+ </Dialog>
112
+ );
113
+
114
+ const dialog = screen.getByRole('dialog');
115
+ await user.click(dialog);
116
+
117
+ // Dialog should still be open
118
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
119
+ });
120
+
121
+ it('closes dialog on Escape key', async () => {
122
+ render(
123
+ <Dialog defaultOpen>
124
+ <Dialog.Content closeOnEscape>
125
+ <Dialog.Title>Test Dialog</Dialog.Title>
126
+ </Dialog.Content>
127
+ </Dialog>
128
+ );
129
+
130
+ fireEvent.keyDown(document, { key: 'Escape' });
131
+
132
+ await waitFor(() => {
133
+ expect(screen.queryByText('Test Dialog')).not.toBeInTheDocument();
134
+ });
135
+ });
136
+
137
+ it('closes dialog when close button is clicked', async () => {
138
+ const user = userEvent.setup();
139
+ render(
140
+ <Dialog defaultOpen>
141
+ <Dialog.Content>
142
+ <Dialog.Title>Test Dialog</Dialog.Title>
143
+ <Dialog.Close />
144
+ </Dialog.Content>
145
+ </Dialog>
146
+ );
147
+
148
+ // DialogClose renders a button with aria-label="Close dialog"
149
+ const closeButton = screen.getByLabelText('Close dialog');
150
+ await user.click(closeButton);
151
+
152
+ await waitFor(() => {
153
+ expect(screen.queryByText('Test Dialog')).not.toBeInTheDocument();
154
+ });
155
+ });
156
+ });
157
+
158
+ describe('Focus Management', () => {
159
+ it('traps focus within dialog', async () => {
160
+ render(
161
+ <Dialog defaultOpen>
162
+ <Dialog.Content>
163
+ <Dialog.Title>Test Dialog</Dialog.Title>
164
+ <Button>First Button</Button>
165
+ <Button>Last Button</Button>
166
+ </Dialog.Content>
167
+ </Dialog>
168
+ );
169
+
170
+ await waitFor(() => {
171
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
172
+ });
173
+
174
+ const firstButton = screen.getByText('First Button');
175
+ const lastButton = screen.getByText('Last Button');
176
+
177
+ // Focus should be on first focusable element (or dialog itself)
178
+ await waitFor(() => {
179
+ const activeElement = document.activeElement;
180
+ expect(activeElement === firstButton || activeElement === screen.getByRole('dialog') || activeElement?.closest('[role="dialog"]')).toBeTruthy();
181
+ });
182
+
183
+ // Tab should move to next element
184
+ firstButton.focus();
185
+ // Use userEvent for more realistic keyboard events
186
+ const user = userEvent.setup();
187
+ await user.tab();
188
+ // After tab, focus should be on lastButton or still within dialog
189
+ await waitFor(() => {
190
+ const activeElement = document.activeElement;
191
+ expect(activeElement === lastButton || activeElement === firstButton || activeElement?.closest('[role="dialog"]')).toBeTruthy();
192
+ }, { timeout: 1000 });
193
+ });
194
+
195
+ it('restores focus to previous element when closed', async () => {
196
+ const user = userEvent.setup();
197
+ const triggerButton = document.createElement('button');
198
+ triggerButton.textContent = 'Trigger';
199
+ document.body.appendChild(triggerButton);
200
+ triggerButton.focus();
201
+
202
+ render(
203
+ <Dialog>
204
+ <Dialog.Trigger>Open Dialog</Dialog.Trigger>
205
+ <Dialog.Content>
206
+ <Dialog.Title>Test Dialog</Dialog.Title>
207
+ </Dialog.Content>
208
+ </Dialog>
209
+ );
210
+
211
+ const trigger = screen.getByText('Open Dialog');
212
+ await user.click(trigger);
213
+
214
+ await waitFor(() => {
215
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
216
+ });
217
+
218
+ fireEvent.keyDown(document, { key: 'Escape' });
219
+
220
+ await waitFor(() => {
221
+ expect(screen.queryByText('Test Dialog')).not.toBeInTheDocument();
222
+ });
223
+
224
+ // Focus should be restored (this is tested via the implementation)
225
+ });
226
+ });
227
+
228
+ describe('Portal Rendering', () => {
229
+ it('renders dialog in portal', () => {
230
+ render(
231
+ <Dialog defaultOpen>
232
+ <Dialog.Content>
233
+ <Dialog.Title>Test Dialog</Dialog.Title>
234
+ </Dialog.Content>
235
+ </Dialog>
236
+ );
237
+
238
+ const dialog = screen.getByRole('dialog');
239
+ // Dialog should be in document.body, not in the root
240
+ expect(document.body.contains(dialog)).toBe(true);
241
+ });
242
+ });
243
+
244
+ describe('Accessibility', () => {
245
+ it('has correct ARIA attributes', () => {
246
+ render(
247
+ <Dialog defaultOpen>
248
+ <Dialog.Content>
249
+ <Dialog.Title>Test Dialog</Dialog.Title>
250
+ <Dialog.Description>Dialog description</Dialog.Description>
251
+ </Dialog.Content>
252
+ </Dialog>
253
+ );
254
+
255
+ const dialog = screen.getByRole('dialog');
256
+ expect(dialog).toHaveAttribute('aria-modal', 'true');
257
+ expect(dialog).toHaveAttribute('aria-labelledby');
258
+ expect(dialog).toHaveAttribute('aria-describedby');
259
+ });
260
+
261
+ it('associates title with dialog', () => {
262
+ render(
263
+ <Dialog defaultOpen>
264
+ <Dialog.Content>
265
+ <Dialog.Header>
266
+ <Dialog.Title>Test Dialog</Dialog.Title>
267
+ </Dialog.Header>
268
+ </Dialog.Content>
269
+ </Dialog>
270
+ );
271
+
272
+ const dialog = screen.getByRole('dialog');
273
+ const title = screen.getByText('Test Dialog');
274
+ const titleId = title.id;
275
+
276
+ expect(dialog).toHaveAttribute('aria-labelledby', titleId);
277
+ });
278
+
279
+ it('associates description with dialog', () => {
280
+ render(
281
+ <Dialog defaultOpen>
282
+ <Dialog.Content>
283
+ <Dialog.Header>
284
+ <Dialog.Title>Test Dialog</Dialog.Title>
285
+ <Dialog.Description>Dialog description</Dialog.Description>
286
+ </Dialog.Header>
287
+ </Dialog.Content>
288
+ </Dialog>
289
+ );
290
+
291
+ const dialog = screen.getByRole('dialog');
292
+ const description = screen.getByText('Dialog description');
293
+ const descriptionId = description.id;
294
+
295
+ expect(dialog).toHaveAttribute('aria-describedby', descriptionId);
296
+ });
297
+ });
298
+
299
+ describe('Controlled vs Uncontrolled', () => {
300
+ it('works in uncontrolled mode', async () => {
301
+ const user = userEvent.setup();
302
+ render(
303
+ <Dialog defaultOpen={false}>
304
+ <Dialog.Trigger>Open</Dialog.Trigger>
305
+ <Dialog.Content>
306
+ <Dialog.Title>Test Dialog</Dialog.Title>
307
+ </Dialog.Content>
308
+ </Dialog>
309
+ );
310
+
311
+ const trigger = screen.getByText('Open');
312
+ await user.click(trigger);
313
+
314
+ await waitFor(() => {
315
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
316
+ });
317
+ });
318
+
319
+ it('works in controlled mode', () => {
320
+ const { rerender } = render(
321
+ <Dialog open={false}>
322
+ <Dialog.Content>
323
+ <Dialog.Title>Test Dialog</Dialog.Title>
324
+ </Dialog.Content>
325
+ </Dialog>
326
+ );
327
+
328
+ expect(screen.queryByText('Test Dialog')).not.toBeInTheDocument();
329
+
330
+ rerender(
331
+ <Dialog open>
332
+ <Dialog.Content>
333
+ <Dialog.Title>Test Dialog</Dialog.Title>
334
+ </Dialog.Content>
335
+ </Dialog>
336
+ );
337
+
338
+ expect(screen.getByText('Test Dialog')).toBeInTheDocument();
339
+ });
340
+
341
+ it('calls onOpenChange in controlled mode', async () => {
342
+ const handleOpenChange = vi.fn();
343
+ render(
344
+ <Dialog open onOpenChange={handleOpenChange}>
345
+ <Dialog.Content>
346
+ <Dialog.Title>Test Dialog</Dialog.Title>
347
+ </Dialog.Content>
348
+ </Dialog>
349
+ );
350
+
351
+ fireEvent.keyDown(document, { key: 'Escape' });
352
+
353
+ await waitFor(() => {
354
+ expect(handleOpenChange).toHaveBeenCalledWith(false);
355
+ });
356
+ });
357
+ });
358
+
359
+ describe('Sizes', () => {
360
+ it('applies correct size classes', async () => {
361
+ const { rerender } = render(
362
+ <Dialog defaultOpen>
363
+ <Dialog.Content size="sm">
364
+ <Dialog.Title>Small Dialog</Dialog.Title>
365
+ </Dialog.Content>
366
+ </Dialog>
367
+ );
368
+
369
+ await waitFor(() => {
370
+ expect(screen.getByText('Small Dialog')).toBeInTheDocument();
371
+ });
372
+
373
+ // Dialog is rendered in portal, so query from document.body
374
+ let dialog = document.querySelector('[role="dialog"]');
375
+ expect(dialog).toHaveClass('max-w-sm');
376
+
377
+ rerender(
378
+ <Dialog defaultOpen>
379
+ <Dialog.Content size="lg">
380
+ <Dialog.Title>Large Dialog</Dialog.Title>
381
+ </Dialog.Content>
382
+ </Dialog>
383
+ );
384
+
385
+ await waitFor(() => {
386
+ expect(screen.getByText('Large Dialog')).toBeInTheDocument();
387
+ });
388
+
389
+ dialog = document.querySelector('[role="dialog"]');
390
+ expect(dialog).toHaveClass('max-w-lg');
391
+ });
392
+ });
393
+
394
+ describe('Body Scroll Lock', () => {
395
+ it('locks body scroll when dialog is open', () => {
396
+ render(
397
+ <Dialog defaultOpen>
398
+ <Dialog.Content>
399
+ <Dialog.Title>Test Dialog</Dialog.Title>
400
+ </Dialog.Content>
401
+ </Dialog>
402
+ );
403
+
404
+ expect(document.body.style.overflow).toBe('hidden');
405
+ });
406
+
407
+ it('unlocks body scroll when dialog is closed', async () => {
408
+ const _user = userEvent.setup();
409
+ const { rerender } = render(
410
+ <Dialog defaultOpen>
411
+ <Dialog.Content>
412
+ <Dialog.Title>Test Dialog</Dialog.Title>
413
+ </Dialog.Content>
414
+ </Dialog>
415
+ );
416
+
417
+ await waitFor(() => {
418
+ expect(document.body.style.overflow).toBe('hidden');
419
+ });
420
+
421
+ rerender(
422
+ <Dialog open={false}>
423
+ <Dialog.Content>
424
+ <Dialog.Title>Test Dialog</Dialog.Title>
425
+ </Dialog.Content>
426
+ </Dialog>
427
+ );
428
+
429
+ await waitFor(() => {
430
+ // The overflow should be restored (empty string or original value)
431
+ expect(document.body.style.overflow).toBe('');
432
+ }, { timeout: 2000 });
433
+ });
434
+ });
435
+ });