@12-apps/ui 1.0.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 (633) hide show
  1. package/components-catalog.md +806 -0
  2. package/components-guidelines.md +347 -0
  3. package/dist/index.cjs +2 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +2 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +1 -0
  8. package/dist/index.js.map +1 -0
  9. package/eslint.config.js +77 -0
  10. package/package.json +247 -0
  11. package/src/__tests__/package-wiring.test.ts +37 -0
  12. package/src/__tests__/setup.ts +1 -0
  13. package/src/__tests__/social-login-button.test.tsx +186 -0
  14. package/src/__tests__/user-avatar.test.tsx +195 -0
  15. package/src/button.tsx +22 -0
  16. package/src/components/command/__tests__/command.test.tsx +112 -0
  17. package/src/components/data-display/Alert/Alert.md +209 -0
  18. package/src/components/data-display/Alert/Alert.stories.tsx +561 -0
  19. package/src/components/data-display/Alert/Alert.test.stories.tsx +709 -0
  20. package/src/components/data-display/Alert/Alert.tsx +449 -0
  21. package/src/components/data-display/Alert/Alert.types.ts +79 -0
  22. package/src/components/data-display/Alert/index.ts +2 -0
  23. package/src/components/data-display/AlertDialog/AlertDialog.md +408 -0
  24. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +360 -0
  25. package/src/components/data-display/AlertDialog/AlertDialog.test.stories.tsx +753 -0
  26. package/src/components/data-display/AlertDialog/AlertDialog.tsx +273 -0
  27. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +74 -0
  28. package/src/components/data-display/AlertDialog/index.ts +2 -0
  29. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.stories.tsx +230 -0
  30. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +270 -0
  31. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +116 -0
  32. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.types.ts +70 -0
  33. package/src/components/data-display/AsyncStateContainer/index.ts +2 -0
  34. package/src/components/data-display/Avatar/Avatar.md +568 -0
  35. package/src/components/data-display/Avatar/Avatar.stories.tsx +718 -0
  36. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +820 -0
  37. package/src/components/data-display/Avatar/Avatar.tsx +507 -0
  38. package/src/components/data-display/Avatar/Avatar.types.ts +88 -0
  39. package/src/components/data-display/Avatar/index.ts +2 -0
  40. package/src/components/data-display/Badge/Badge.md +469 -0
  41. package/src/components/data-display/Badge/Badge.stories.tsx +1136 -0
  42. package/src/components/data-display/Badge/Badge.test.stories.tsx +1193 -0
  43. package/src/components/data-display/Badge/Badge.tsx +606 -0
  44. package/src/components/data-display/Badge/Badge.types.ts +118 -0
  45. package/src/components/data-display/Badge/index.ts +2 -0
  46. package/src/components/data-display/Banner/Banner.stories.tsx +524 -0
  47. package/src/components/data-display/Banner/Banner.test.stories.tsx +503 -0
  48. package/src/components/data-display/Banner/Banner.tsx +350 -0
  49. package/src/components/data-display/Banner/Banner.types.ts +41 -0
  50. package/src/components/data-display/Banner/banner.md +141 -0
  51. package/src/components/data-display/Banner/index.ts +2 -0
  52. package/src/components/data-display/Carousel/Carousel.md +815 -0
  53. package/src/components/data-display/Carousel/Carousel.stories.tsx +607 -0
  54. package/src/components/data-display/Carousel/Carousel.test.stories.tsx +691 -0
  55. package/src/components/data-display/Carousel/Carousel.tsx +765 -0
  56. package/src/components/data-display/Carousel/Carousel.types.ts +79 -0
  57. package/src/components/data-display/Carousel/index.ts +8 -0
  58. package/src/components/data-display/Chart/Chart.md +352 -0
  59. package/src/components/data-display/Chart/Chart.stories.tsx +568 -0
  60. package/src/components/data-display/Chart/Chart.test.stories.tsx +174 -0
  61. package/src/components/data-display/Chart/Chart.tsx +520 -0
  62. package/src/components/data-display/Chart/Chart.types.ts +65 -0
  63. package/src/components/data-display/Chart/index.ts +2 -0
  64. package/src/components/data-display/Chip/Chip.stories.tsx +251 -0
  65. package/src/components/data-display/Chip/Chip.test.stories.tsx +263 -0
  66. package/src/components/data-display/Chip/Chip.tsx +134 -0
  67. package/src/components/data-display/Chip/Chip.types.ts +51 -0
  68. package/src/components/data-display/Chip/chip.md +395 -0
  69. package/src/components/data-display/Chip/index.ts +2 -0
  70. package/src/components/data-display/DataGrid/DataGrid.md +602 -0
  71. package/src/components/data-display/DataGrid/DataGrid.stories.tsx +515 -0
  72. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +659 -0
  73. package/src/components/data-display/DataGrid/DataGrid.tsx +743 -0
  74. package/src/components/data-display/DataGrid/DataGrid.types.ts +171 -0
  75. package/src/components/data-display/DataGrid/index.ts +21 -0
  76. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +197 -0
  77. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.types.ts +46 -0
  78. package/src/components/data-display/DateTimeDisplay/index.ts +2 -0
  79. package/src/components/data-display/DescriptionItem/DescriptionItem.md +226 -0
  80. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +254 -0
  81. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +100 -0
  82. package/src/components/data-display/DescriptionItem/DescriptionItem.types.ts +1 -0
  83. package/src/components/data-display/DescriptionItem/index.ts +2 -0
  84. package/src/components/data-display/EmptyState/EmptyState.md +265 -0
  85. package/src/components/data-display/EmptyState/EmptyState.stories.tsx +282 -0
  86. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +441 -0
  87. package/src/components/data-display/EmptyState/EmptyState.tsx +180 -0
  88. package/src/components/data-display/EmptyState/EmptyState.types.ts +31 -0
  89. package/src/components/data-display/EmptyState/index.ts +2 -0
  90. package/src/components/data-display/ErrorState/ErrorState.stories.tsx +110 -0
  91. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +133 -0
  92. package/src/components/data-display/ErrorState/ErrorState.tsx +118 -0
  93. package/src/components/data-display/ErrorState/ErrorState.types.ts +45 -0
  94. package/src/components/data-display/ErrorState/index.ts +2 -0
  95. package/src/components/data-display/HoverCard/HoverCard.md +389 -0
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +648 -0
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +929 -0
  98. package/src/components/data-display/HoverCard/HoverCard.tsx +657 -0
  99. package/src/components/data-display/HoverCard/HoverCard.types.ts +116 -0
  100. package/src/components/data-display/HoverCard/index.ts +2 -0
  101. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.md +532 -0
  102. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.stories.tsx +411 -0
  103. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +245 -0
  104. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.types.ts +64 -0
  105. package/src/components/data-display/InteractiveTooltip/index.ts +2 -0
  106. package/src/components/data-display/LazyImage/LazyImage.md +356 -0
  107. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +387 -0
  108. package/src/components/data-display/LazyImage/LazyImage.tsx +323 -0
  109. package/src/components/data-display/LazyImage/LazyImage.types.ts +205 -0
  110. package/src/components/data-display/LazyImage/index.ts +2 -0
  111. package/src/components/data-display/Lightbox/Lightbox.stories.tsx +315 -0
  112. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +605 -0
  113. package/src/components/data-display/Lightbox/Lightbox.tsx +666 -0
  114. package/src/components/data-display/Lightbox/Lightbox.types.ts +49 -0
  115. package/src/components/data-display/Lightbox/index.ts +2 -0
  116. package/src/components/data-display/Lightbox/lightbox.md +298 -0
  117. package/src/components/data-display/LoadingState/LoadingState.stories.tsx +124 -0
  118. package/src/components/data-display/LoadingState/LoadingState.test.stories.tsx +99 -0
  119. package/src/components/data-display/LoadingState/LoadingState.tsx +103 -0
  120. package/src/components/data-display/LoadingState/LoadingState.types.ts +37 -0
  121. package/src/components/data-display/LoadingState/index.ts +2 -0
  122. package/src/components/data-display/MapPreview/MapPreview.md +154 -0
  123. package/src/components/data-display/MapPreview/MapPreview.stories.tsx +458 -0
  124. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +390 -0
  125. package/src/components/data-display/MapPreview/MapPreview.tsx +922 -0
  126. package/src/components/data-display/MapPreview/MapPreview.types.ts +56 -0
  127. package/src/components/data-display/MapPreview/index.ts +2 -0
  128. package/src/components/data-display/Popover/Popover.md +245 -0
  129. package/src/components/data-display/Popover/Popover.stories.tsx +295 -0
  130. package/src/components/data-display/Popover/Popover.test.stories.tsx +1168 -0
  131. package/src/components/data-display/Popover/Popover.tsx +132 -0
  132. package/src/components/data-display/Popover/Popover.types.ts +33 -0
  133. package/src/components/data-display/Popover/index.ts +2 -0
  134. package/src/components/data-display/Progress/Progress.md +450 -0
  135. package/src/components/data-display/Progress/Progress.stories.tsx +481 -0
  136. package/src/components/data-display/Progress/Progress.test.stories.tsx +2070 -0
  137. package/src/components/data-display/Progress/Progress.tsx +332 -0
  138. package/src/components/data-display/Progress/Progress.types.ts +61 -0
  139. package/src/components/data-display/Progress/index.ts +2 -0
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.md +108 -0
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +160 -0
  142. package/src/components/data-display/SectionOnboarding/SectionOnboarding.test.stories.tsx +190 -0
  143. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +224 -0
  144. package/src/components/data-display/SectionOnboarding/SectionOnboarding.types.ts +101 -0
  145. package/src/components/data-display/SectionOnboarding/index.ts +7 -0
  146. package/src/components/data-display/Sheet/Sheet.md +475 -0
  147. package/src/components/data-display/Sheet/Sheet.stories.tsx +883 -0
  148. package/src/components/data-display/Sheet/Sheet.test.stories.tsx +1101 -0
  149. package/src/components/data-display/Sheet/Sheet.tsx +978 -0
  150. package/src/components/data-display/Sheet/Sheet.types.ts +93 -0
  151. package/src/components/data-display/Sheet/index.ts +8 -0
  152. package/src/components/data-display/Stepper/Stepper.md +542 -0
  153. package/src/components/data-display/Stepper/Stepper.stories.tsx +540 -0
  154. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +607 -0
  155. package/src/components/data-display/Stepper/Stepper.tsx +328 -0
  156. package/src/components/data-display/Stepper/Stepper.types.ts +97 -0
  157. package/src/components/data-display/Stepper/index.ts +2 -0
  158. package/src/components/data-display/Table/Table.md +243 -0
  159. package/src/components/data-display/Table/Table.stories.tsx +801 -0
  160. package/src/components/data-display/Table/Table.test.stories.tsx +369 -0
  161. package/src/components/data-display/Table/Table.tsx +831 -0
  162. package/src/components/data-display/Table/Table.types.ts +335 -0
  163. package/src/components/data-display/Table/index.ts +2 -0
  164. package/src/components/data-display/Timeline/Timeline.md +201 -0
  165. package/src/components/data-display/Timeline/Timeline.stories.tsx +444 -0
  166. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +944 -0
  167. package/src/components/data-display/Timeline/Timeline.tsx +348 -0
  168. package/src/components/data-display/Timeline/Timeline.types.ts +26 -0
  169. package/src/components/data-display/Timeline/index.ts +2 -0
  170. package/src/components/data-display/TimingDiagram/TimingDiagram.md +162 -0
  171. package/src/components/data-display/TimingDiagram/TimingDiagram.stories.tsx +475 -0
  172. package/src/components/data-display/TimingDiagram/TimingDiagram.test.stories.tsx +734 -0
  173. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +399 -0
  174. package/src/components/data-display/TimingDiagram/TimingDiagram.types.ts +19 -0
  175. package/src/components/data-display/TimingDiagram/index.ts +2 -0
  176. package/src/components/data-display/Tooltip/Tooltip.md +397 -0
  177. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +465 -0
  178. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +1168 -0
  179. package/src/components/data-display/Tooltip/Tooltip.tsx +161 -0
  180. package/src/components/data-display/Tooltip/Tooltip.types.ts +33 -0
  181. package/src/components/data-display/Tooltip/index.ts +2 -0
  182. package/src/components/data-display/index.ts +29 -0
  183. package/src/components/feedback/Dialog/Dialog.md +527 -0
  184. package/src/components/feedback/Dialog/Dialog.stories.tsx +833 -0
  185. package/src/components/feedback/Dialog/Dialog.styles.ts +171 -0
  186. package/src/components/feedback/Dialog/Dialog.test.stories.tsx +955 -0
  187. package/src/components/feedback/Dialog/Dialog.tsx +256 -0
  188. package/src/components/feedback/Dialog/Dialog.types.ts +46 -0
  189. package/src/components/feedback/Dialog/index.ts +9 -0
  190. package/src/components/feedback/Modal/Modal.md +629 -0
  191. package/src/components/feedback/Modal/Modal.stories.tsx +765 -0
  192. package/src/components/feedback/Modal/Modal.test.stories.tsx +251 -0
  193. package/src/components/feedback/Modal/Modal.tsx +279 -0
  194. package/src/components/feedback/Modal/Modal.types.ts +26 -0
  195. package/src/components/feedback/Modal/index.ts +7 -0
  196. package/src/components/feedback/Sonner/Sonner.stories.tsx +698 -0
  197. package/src/components/feedback/Sonner/Sonner.test.stories.tsx +896 -0
  198. package/src/components/feedback/Sonner/Sonner.tsx +493 -0
  199. package/src/components/feedback/Sonner/Sonner.types.ts +65 -0
  200. package/src/components/feedback/Sonner/index.ts +8 -0
  201. package/src/components/feedback/StackedModal/StackedModal.md +273 -0
  202. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +1785 -0
  203. package/src/components/feedback/StackedModal/StackedModal.test.stories.tsx +975 -0
  204. package/src/components/feedback/StackedModal/StackedModal.tsx +664 -0
  205. package/src/components/feedback/StackedModal/StackedModal.types.ts +70 -0
  206. package/src/components/feedback/StackedModal/index.ts +11 -0
  207. package/src/components/feedback/Toast/Toast.md +547 -0
  208. package/src/components/feedback/Toast/Toast.stories.tsx +548 -0
  209. package/src/components/feedback/Toast/Toast.test.stories.tsx +834 -0
  210. package/src/components/feedback/Toast/Toast.tsx +279 -0
  211. package/src/components/feedback/Toast/Toast.types.ts +59 -0
  212. package/src/components/feedback/Toast/index.ts +8 -0
  213. package/src/components/feedback/TutorialOverlay/TutorialOverlay.md +610 -0
  214. package/src/components/feedback/TutorialOverlay/TutorialOverlay.stories.tsx +691 -0
  215. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +634 -0
  216. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +554 -0
  217. package/src/components/feedback/TutorialOverlay/TutorialOverlay.types.ts +30 -0
  218. package/src/components/feedback/TutorialOverlay/index.ts +2 -0
  219. package/src/components/feedback/index.ts +6 -0
  220. package/src/components/form/AddressAutocomplete/AddressAutocomplete.md +633 -0
  221. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +663 -0
  222. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +723 -0
  223. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +836 -0
  224. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +37 -0
  225. package/src/components/form/AddressAutocomplete/index.ts +2 -0
  226. package/src/components/form/Autocomplete/Autocomplete.helpers.ts +115 -0
  227. package/src/components/form/Autocomplete/Autocomplete.keys.ts +134 -0
  228. package/src/components/form/Autocomplete/Autocomplete.parts.tsx +337 -0
  229. package/src/components/form/Autocomplete/Autocomplete.stories.tsx +715 -0
  230. package/src/components/form/Autocomplete/Autocomplete.test.stories.tsx +825 -0
  231. package/src/components/form/Autocomplete/Autocomplete.tsx +166 -0
  232. package/src/components/form/Autocomplete/Autocomplete.types.ts +116 -0
  233. package/src/components/form/Autocomplete/autocomplete.md +789 -0
  234. package/src/components/form/Autocomplete/index.ts +8 -0
  235. package/src/components/form/Autocomplete/useAutocomplete.ts +311 -0
  236. package/src/components/form/Button/Button.md +411 -0
  237. package/src/components/form/Button/Button.stories.tsx +362 -0
  238. package/src/components/form/Button/Button.test.stories.tsx +603 -0
  239. package/src/components/form/Button/Button.tsx +326 -0
  240. package/src/components/form/Button/Button.types.ts +74 -0
  241. package/src/components/form/Button/index.ts +2 -0
  242. package/src/components/form/Calendar/Calendar.md +807 -0
  243. package/src/components/form/Calendar/Calendar.stories.tsx +349 -0
  244. package/src/components/form/Calendar/Calendar.test.stories.tsx +465 -0
  245. package/src/components/form/Calendar/Calendar.tsx +571 -0
  246. package/src/components/form/Calendar/Calendar.types.ts +81 -0
  247. package/src/components/form/Calendar/index.ts +11 -0
  248. package/src/components/form/Checkbox/Checkbox.md +200 -0
  249. package/src/components/form/Checkbox/Checkbox.stories.tsx +265 -0
  250. package/src/components/form/Checkbox/Checkbox.test.stories.tsx +181 -0
  251. package/src/components/form/Checkbox/Checkbox.tsx +170 -0
  252. package/src/components/form/Checkbox/Checkbox.types.ts +20 -0
  253. package/src/components/form/Checkbox/index.ts +2 -0
  254. package/src/components/form/CodeEditor/CodeEditor.md +350 -0
  255. package/src/components/form/CodeEditor/CodeEditor.stories.tsx +871 -0
  256. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +575 -0
  257. package/src/components/form/CodeEditor/CodeEditor.tsx +415 -0
  258. package/src/components/form/CodeEditor/CodeEditor.types.ts +38 -0
  259. package/src/components/form/CodeEditor/index.ts +2 -0
  260. package/src/components/form/Command/Command.md +468 -0
  261. package/src/components/form/Command/Command.stories.tsx +580 -0
  262. package/src/components/form/Command/Command.test.stories.tsx +215 -0
  263. package/src/components/form/Command/Command.tsx +545 -0
  264. package/src/components/form/Command/Command.types.ts +116 -0
  265. package/src/components/form/Command/index.ts +12 -0
  266. package/src/components/form/CreatableSelect/CreatableSelect.md +114 -0
  267. package/src/components/form/CreatableSelect/CreatableSelect.stories.tsx +112 -0
  268. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +134 -0
  269. package/src/components/form/CreatableSelect/CreatableSelect.tsx +149 -0
  270. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +37 -0
  271. package/src/components/form/CreatableSelect/index.ts +2 -0
  272. package/src/components/form/Form/Form.md +325 -0
  273. package/src/components/form/Form/Form.stories.tsx +687 -0
  274. package/src/components/form/Form/Form.test.stories.tsx +601 -0
  275. package/src/components/form/Form/Form.tsx +136 -0
  276. package/src/components/form/Form/Form.types.ts +42 -0
  277. package/src/components/form/Form/index.ts +8 -0
  278. package/src/components/form/Input/Input.md +252 -0
  279. package/src/components/form/Input/Input.stories.tsx +256 -0
  280. package/src/components/form/Input/Input.test.stories.tsx +1184 -0
  281. package/src/components/form/Input/Input.tsx +263 -0
  282. package/src/components/form/Input/Input.types.ts +24 -0
  283. package/src/components/form/Input/index.ts +2 -0
  284. package/src/components/form/InputOTP/InputOTP.md +419 -0
  285. package/src/components/form/InputOTP/InputOTP.stories.tsx +774 -0
  286. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +596 -0
  287. package/src/components/form/InputOTP/InputOTP.tsx +231 -0
  288. package/src/components/form/InputOTP/InputOTP.types.ts +68 -0
  289. package/src/components/form/InputOTP/index.ts +2 -0
  290. package/src/components/form/Label/Label.md +426 -0
  291. package/src/components/form/Label/Label.stories.tsx +473 -0
  292. package/src/components/form/Label/Label.test.stories.tsx +909 -0
  293. package/src/components/form/Label/Label.tsx +367 -0
  294. package/src/components/form/Label/Label.types.ts +35 -0
  295. package/src/components/form/Label/index.ts +2 -0
  296. package/src/components/form/Menubar/Menubar.md +275 -0
  297. package/src/components/form/Menubar/Menubar.stories.tsx +472 -0
  298. package/src/components/form/Menubar/Menubar.test.stories.tsx +588 -0
  299. package/src/components/form/Menubar/Menubar.tsx +467 -0
  300. package/src/components/form/Menubar/Menubar.types.ts +71 -0
  301. package/src/components/form/Menubar/index.ts +8 -0
  302. package/src/components/form/PasswordStrength/PasswordStrength.md +139 -0
  303. package/src/components/form/PasswordStrength/PasswordStrength.stories.tsx +562 -0
  304. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +327 -0
  305. package/src/components/form/PasswordStrength/PasswordStrength.tsx +419 -0
  306. package/src/components/form/PasswordStrength/PasswordStrength.types.ts +18 -0
  307. package/src/components/form/PasswordStrength/index.ts +2 -0
  308. package/src/components/form/PhoneInput/PhoneInput.md +578 -0
  309. package/src/components/form/PhoneInput/PhoneInput.stories.tsx +495 -0
  310. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +666 -0
  311. package/src/components/form/PhoneInput/PhoneInput.tsx +376 -0
  312. package/src/components/form/PhoneInput/PhoneInput.types.ts +25 -0
  313. package/src/components/form/PhoneInput/index.ts +2 -0
  314. package/src/components/form/RadioGroup/RadioGroup.md +477 -0
  315. package/src/components/form/RadioGroup/RadioGroup.stories.tsx +518 -0
  316. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +685 -0
  317. package/src/components/form/RadioGroup/RadioGroup.tsx +664 -0
  318. package/src/components/form/RadioGroup/RadioGroup.types.ts +82 -0
  319. package/src/components/form/RadioGroup/index.ts +2 -0
  320. package/src/components/form/RichTextEditor/RichTextEditor.md +710 -0
  321. package/src/components/form/RichTextEditor/RichTextEditor.stories.tsx +261 -0
  322. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +498 -0
  323. package/src/components/form/RichTextEditor/RichTextEditor.tsx +468 -0
  324. package/src/components/form/RichTextEditor/RichTextEditor.types.ts +72 -0
  325. package/src/components/form/RichTextEditor/index.ts +2 -0
  326. package/src/components/form/SearchPalette/SearchPalette.md +69 -0
  327. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +358 -0
  328. package/src/components/form/SearchPalette/SearchPalette.stories.tsx +135 -0
  329. package/src/components/form/SearchPalette/SearchPalette.tsx +141 -0
  330. package/src/components/form/SearchPalette/SearchPalette.types.ts +82 -0
  331. package/src/components/form/SearchPalette/index.ts +7 -0
  332. package/src/components/form/Select/Select.md +254 -0
  333. package/src/components/form/Select/Select.stories.tsx +364 -0
  334. package/src/components/form/Select/Select.test.stories.tsx +977 -0
  335. package/src/components/form/Select/Select.tsx +239 -0
  336. package/src/components/form/Select/Select.types.ts +57 -0
  337. package/src/components/form/Select/index.ts +2 -0
  338. package/src/components/form/Slider/Slider.md +326 -0
  339. package/src/components/form/Slider/Slider.stories.tsx +418 -0
  340. package/src/components/form/Slider/Slider.test.stories.tsx +1044 -0
  341. package/src/components/form/Slider/Slider.tsx +374 -0
  342. package/src/components/form/Slider/Slider.types.ts +113 -0
  343. package/src/components/form/Slider/index.ts +2 -0
  344. package/src/components/form/Switch/Switch.md +565 -0
  345. package/src/components/form/Switch/Switch.stories.tsx +697 -0
  346. package/src/components/form/Switch/Switch.test.stories.tsx +597 -0
  347. package/src/components/form/Switch/Switch.tsx +578 -0
  348. package/src/components/form/Switch/Switch.types.ts +130 -0
  349. package/src/components/form/Switch/index.ts +2 -0
  350. package/src/components/form/Textarea/Textarea.stories.tsx +473 -0
  351. package/src/components/form/Textarea/Textarea.test.stories.tsx +708 -0
  352. package/src/components/form/Textarea/Textarea.tsx +678 -0
  353. package/src/components/form/Textarea/Textarea.types.ts +84 -0
  354. package/src/components/form/Textarea/index.ts +2 -0
  355. package/src/components/form/Toggle/Toggle.md +234 -0
  356. package/src/components/form/Toggle/Toggle.stories.tsx +638 -0
  357. package/src/components/form/Toggle/Toggle.test.stories.tsx +1167 -0
  358. package/src/components/form/Toggle/Toggle.tsx +265 -0
  359. package/src/components/form/Toggle/Toggle.types.ts +79 -0
  360. package/src/components/form/Toggle/index.ts +2 -0
  361. package/src/components/form/ToggleGroup/ToggleGroup.md +329 -0
  362. package/src/components/form/ToggleGroup/ToggleGroup.stories.tsx +617 -0
  363. package/src/components/form/ToggleGroup/ToggleGroup.test.stories.tsx +918 -0
  364. package/src/components/form/ToggleGroup/ToggleGroup.tsx +129 -0
  365. package/src/components/form/ToggleGroup/ToggleGroup.types.ts +53 -0
  366. package/src/components/form/ToggleGroup/index.ts +2 -0
  367. package/src/components/form/UploadButton/UploadButton.md +44 -0
  368. package/src/components/form/UploadButton/UploadButton.stories.tsx +366 -0
  369. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +454 -0
  370. package/src/components/form/UploadButton/UploadButton.tsx +312 -0
  371. package/src/components/form/UploadButton/UploadButton.types.ts +58 -0
  372. package/src/components/form/UploadButton/index.ts +2 -0
  373. package/src/components/form/index.ts +25 -0
  374. package/src/components/form/total-form/Fields/SelectField.tsx +57 -0
  375. package/src/components/form/total-form/Fields/TextField.tsx +58 -0
  376. package/src/components/form/total-form/Fields/index.ts +4 -0
  377. package/src/components/form/total-form/FormContainer.tsx +104 -0
  378. package/src/components/form/total-form/FormContext.tsx +38 -0
  379. package/src/components/form/total-form/FormErrorSnackbar.tsx +35 -0
  380. package/src/components/form/total-form/SubmitButton.tsx +27 -0
  381. package/src/components/form/total-form/index.ts +12 -0
  382. package/src/components/form/total-form/total-form.test.tsx +97 -0
  383. package/src/components/index.ts +7 -0
  384. package/src/components/layout/Accordion/Accordion.md +725 -0
  385. package/src/components/layout/Accordion/Accordion.stories.tsx +690 -0
  386. package/src/components/layout/Accordion/Accordion.test.stories.tsx +1362 -0
  387. package/src/components/layout/Accordion/Accordion.tsx +242 -0
  388. package/src/components/layout/Accordion/Accordion.types.ts +32 -0
  389. package/src/components/layout/Accordion/index.ts +8 -0
  390. package/src/components/layout/Card/Card.md +533 -0
  391. package/src/components/layout/Card/Card.stories.tsx +593 -0
  392. package/src/components/layout/Card/Card.test.stories.tsx +1134 -0
  393. package/src/components/layout/Card/Card.tsx +404 -0
  394. package/src/components/layout/Card/Card.types.ts +57 -0
  395. package/src/components/layout/Card/index.ts +8 -0
  396. package/src/components/layout/Collapsible/Collapsible.md +135 -0
  397. package/src/components/layout/Collapsible/Collapsible.stories.tsx +180 -0
  398. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +304 -0
  399. package/src/components/layout/Collapsible/Collapsible.tsx +198 -0
  400. package/src/components/layout/Collapsible/Collapsible.types.ts +35 -0
  401. package/src/components/layout/Collapsible/index.ts +6 -0
  402. package/src/components/layout/Container/Container.md +420 -0
  403. package/src/components/layout/Container/Container.stories.tsx +557 -0
  404. package/src/components/layout/Container/Container.test.stories.tsx +750 -0
  405. package/src/components/layout/Container/Container.tsx +72 -0
  406. package/src/components/layout/Container/Container.types.ts +11 -0
  407. package/src/components/layout/Container/index.ts +2 -0
  408. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +99 -0
  409. package/src/components/layout/ContentToolbar/ContentToolbar.md +75 -0
  410. package/src/components/layout/ContentToolbar/ContentToolbar.stories.tsx +129 -0
  411. package/src/components/layout/ContentToolbar/ContentToolbar.test.stories.tsx +251 -0
  412. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +108 -0
  413. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +229 -0
  414. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +71 -0
  415. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +297 -0
  416. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +334 -0
  417. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +213 -0
  418. package/src/components/layout/ContentToolbar/ViewSelector.tsx +98 -0
  419. package/src/components/layout/ContentToolbar/__tests__/ColumnsMenu.test.tsx +39 -0
  420. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +110 -0
  421. package/src/components/layout/ContentToolbar/__tests__/SavedViewsMenu.test.tsx +99 -0
  422. package/src/components/layout/ContentToolbar/index.ts +24 -0
  423. package/src/components/layout/ContentToolbar/tests.md +42 -0
  424. package/src/components/layout/ContentToolbar/track.md +41 -0
  425. package/src/components/layout/Dashboard/Dashboard.md +71 -0
  426. package/src/components/layout/Dashboard/Dashboard.stories.tsx +104 -0
  427. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +164 -0
  428. package/src/components/layout/Dashboard/Dashboard.tsx +297 -0
  429. package/src/components/layout/Dashboard/Dashboard.types.ts +157 -0
  430. package/src/components/layout/Dashboard/DashboardContext.tsx +47 -0
  431. package/src/components/layout/Dashboard/DashboardParts.tsx +216 -0
  432. package/src/components/layout/Dashboard/index.ts +18 -0
  433. package/src/components/layout/Dashboard/tests.md +46 -0
  434. package/src/components/layout/Dashboard/track.md +50 -0
  435. package/src/components/layout/Drawer/Drawer.md +479 -0
  436. package/src/components/layout/Drawer/Drawer.stories.tsx +660 -0
  437. package/src/components/layout/Drawer/Drawer.test.stories.tsx +1339 -0
  438. package/src/components/layout/Drawer/Drawer.tsx +150 -0
  439. package/src/components/layout/Drawer/Drawer.types.ts +34 -0
  440. package/src/components/layout/Drawer/index.ts +2 -0
  441. package/src/components/layout/Resizable/Resizable.md +308 -0
  442. package/src/components/layout/Resizable/Resizable.stories.tsx +1039 -0
  443. package/src/components/layout/Resizable/Resizable.test.stories.tsx +750 -0
  444. package/src/components/layout/Resizable/Resizable.tsx +190 -0
  445. package/src/components/layout/Resizable/Resizable.types.ts +34 -0
  446. package/src/components/layout/Resizable/index.ts +2 -0
  447. package/src/components/layout/ScrollArea/ScrollArea.md +122 -0
  448. package/src/components/layout/ScrollArea/ScrollArea.stories.tsx +651 -0
  449. package/src/components/layout/ScrollArea/ScrollArea.test.stories.tsx +619 -0
  450. package/src/components/layout/ScrollArea/ScrollArea.tsx +449 -0
  451. package/src/components/layout/ScrollArea/ScrollArea.types.ts +80 -0
  452. package/src/components/layout/ScrollArea/index.ts +7 -0
  453. package/src/components/layout/Separator/Separator.stories.tsx +563 -0
  454. package/src/components/layout/Separator/Separator.test.stories.tsx +527 -0
  455. package/src/components/layout/Separator/Separator.tsx +187 -0
  456. package/src/components/layout/Separator/Separator.types.ts +17 -0
  457. package/src/components/layout/Separator/index.ts +2 -0
  458. package/src/components/layout/SettingsLayout/SettingsLayout.md +139 -0
  459. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +357 -0
  460. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +194 -0
  461. package/src/components/layout/SettingsLayout/SettingsLayout.test.stories.tsx +175 -0
  462. package/src/components/layout/SettingsLayout/SettingsLayout.tsx +69 -0
  463. package/src/components/layout/SettingsLayout/SettingsLayout.types.ts +61 -0
  464. package/src/components/layout/SettingsLayout/index.ts +6 -0
  465. package/src/components/layout/Sidebar/Sidebar.md +367 -0
  466. package/src/components/layout/Sidebar/Sidebar.stories.tsx +611 -0
  467. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +1326 -0
  468. package/src/components/layout/Sidebar/Sidebar.tsx +131 -0
  469. package/src/components/layout/Sidebar/Sidebar.types.ts +30 -0
  470. package/src/components/layout/Sidebar/index.ts +7 -0
  471. package/src/components/layout/Skeleton/Skeleton.md +240 -0
  472. package/src/components/layout/Skeleton/Skeleton.stories.tsx +689 -0
  473. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +521 -0
  474. package/src/components/layout/Skeleton/Skeleton.tsx +166 -0
  475. package/src/components/layout/Skeleton/Skeleton.types.ts +19 -0
  476. package/src/components/layout/Skeleton/index.ts +2 -0
  477. package/src/components/layout/Spacer/Spacer.md +84 -0
  478. package/src/components/layout/Spacer/Spacer.stories.tsx +502 -0
  479. package/src/components/layout/Spacer/Spacer.test.stories.tsx +472 -0
  480. package/src/components/layout/Spacer/Spacer.tsx +68 -0
  481. package/src/components/layout/Spacer/Spacer.types.ts +12 -0
  482. package/src/components/layout/Spacer/index.ts +2 -0
  483. package/src/components/layout/TableFilter/TableFilter.md +55 -0
  484. package/src/components/layout/TableFilter/TableFilter.stories.tsx +82 -0
  485. package/src/components/layout/TableFilter/TableFilter.test.stories.tsx +87 -0
  486. package/src/components/layout/TableFilter/TableFilter.tsx +383 -0
  487. package/src/components/layout/TableFilter/TableFilter.types.ts +87 -0
  488. package/src/components/layout/TableFilter/TableFilterContext.tsx +29 -0
  489. package/src/components/layout/TableFilter/index.ts +15 -0
  490. package/src/components/layout/TableFilter/tests.md +37 -0
  491. package/src/components/layout/TableFilter/track.md +36 -0
  492. package/src/components/layout/index.ts +14 -0
  493. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +558 -0
  494. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +640 -0
  495. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +1007 -0
  496. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +516 -0
  497. package/src/components/navigation/Breadcrumbs/Breadcrumbs.types.ts +132 -0
  498. package/src/components/navigation/Breadcrumbs/index.ts +2 -0
  499. package/src/components/navigation/CommandPalette/CommandPalette.md +201 -0
  500. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +384 -0
  501. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +437 -0
  502. package/src/components/navigation/CommandPalette/CommandPalette.tsx +434 -0
  503. package/src/components/navigation/CommandPalette/CommandPalette.types.ts +25 -0
  504. package/src/components/navigation/CommandPalette/index.ts +2 -0
  505. package/src/components/navigation/ContextMenu/ContextMenu.md +535 -0
  506. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +611 -0
  507. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +850 -0
  508. package/src/components/navigation/ContextMenu/ContextMenu.tsx +254 -0
  509. package/src/components/navigation/ContextMenu/ContextMenu.types.ts +96 -0
  510. package/src/components/navigation/ContextMenu/index.ts +2 -0
  511. package/src/components/navigation/DropdownMenu/DropdownMenu.md +514 -0
  512. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +580 -0
  513. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +660 -0
  514. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +305 -0
  515. package/src/components/navigation/DropdownMenu/DropdownMenu.types.ts +116 -0
  516. package/src/components/navigation/DropdownMenu/index.ts +2 -0
  517. package/src/components/navigation/NavigationMenu/NavigationMenu.md +580 -0
  518. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +874 -0
  519. package/src/components/navigation/NavigationMenu/NavigationMenu.types.ts +135 -0
  520. package/src/components/navigation/NavigationMenu/index.ts +2 -0
  521. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +518 -0
  522. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +931 -0
  523. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +503 -0
  524. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +455 -0
  525. package/src/components/navigation/Pagination/Pagination.md +699 -0
  526. package/src/components/navigation/Pagination/Pagination.stories.tsx +604 -0
  527. package/src/components/navigation/Pagination/Pagination.test.stories.tsx +520 -0
  528. package/src/components/navigation/Pagination/Pagination.tsx +356 -0
  529. package/src/components/navigation/Pagination/Pagination.types.ts +129 -0
  530. package/src/components/navigation/Pagination/index.ts +2 -0
  531. package/src/components/navigation/Tabs/Tabs.md +774 -0
  532. package/src/components/navigation/Tabs/Tabs.stories.tsx +1006 -0
  533. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +1225 -0
  534. package/src/components/navigation/Tabs/Tabs.tsx +433 -0
  535. package/src/components/navigation/Tabs/Tabs.types.ts +239 -0
  536. package/src/components/navigation/Tabs/index.ts +2 -0
  537. package/src/components/navigation/index.ts +7 -0
  538. package/src/components/typography/Blockquote/Blockquote.md +130 -0
  539. package/src/components/typography/Blockquote/Blockquote.stories.tsx +359 -0
  540. package/src/components/typography/Blockquote/Blockquote.test.stories.tsx +432 -0
  541. package/src/components/typography/Blockquote/Blockquote.tsx +166 -0
  542. package/src/components/typography/Blockquote/Blockquote.types.ts +11 -0
  543. package/src/components/typography/Blockquote/index.ts +2 -0
  544. package/src/components/typography/Code/Code.md +182 -0
  545. package/src/components/typography/Code/Code.stories.tsx +686 -0
  546. package/src/components/typography/Code/Code.test.stories.tsx +703 -0
  547. package/src/components/typography/Code/Code.tsx +228 -0
  548. package/src/components/typography/Code/Code.types.ts +12 -0
  549. package/src/components/typography/Code/index.ts +2 -0
  550. package/src/components/typography/Heading/Heading.md +143 -0
  551. package/src/components/typography/Heading/Heading.stories.tsx +451 -0
  552. package/src/components/typography/Heading/Heading.test.stories.tsx +830 -0
  553. package/src/components/typography/Heading/Heading.tsx +178 -0
  554. package/src/components/typography/Heading/Heading.types.ts +11 -0
  555. package/src/components/typography/Heading/index.ts +2 -0
  556. package/src/components/typography/Paragraph/Paragraph.md +80 -0
  557. package/src/components/typography/Paragraph/Paragraph.stories.tsx +280 -0
  558. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +238 -0
  559. package/src/components/typography/Paragraph/Paragraph.tsx +99 -0
  560. package/src/components/typography/Paragraph/Paragraph.types.ts +10 -0
  561. package/src/components/typography/Paragraph/index.ts +2 -0
  562. package/src/components/typography/Text/Text.md +129 -0
  563. package/src/components/typography/Text/Text.stories.tsx +359 -0
  564. package/src/components/typography/Text/Text.test.stories.tsx +762 -0
  565. package/src/components/typography/Text/Text.tsx +159 -0
  566. package/src/components/typography/Text/Text.types.ts +15 -0
  567. package/src/components/typography/Text/index.ts +2 -0
  568. package/src/components/typography/index.ts +5 -0
  569. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +359 -0
  570. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +947 -0
  571. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +596 -0
  572. package/src/components/utility/AnimatedIcon/AnimatedIcon.tsx +595 -0
  573. package/src/components/utility/AnimatedIcon/AnimatedIcon.types.ts +98 -0
  574. package/src/components/utility/AnimatedIcon/index.ts +2 -0
  575. package/src/components/utility/AspectRatio/AspectRatio.md +200 -0
  576. package/src/components/utility/AspectRatio/AspectRatio.stories.tsx +414 -0
  577. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +859 -0
  578. package/src/components/utility/AspectRatio/AspectRatio.tsx +76 -0
  579. package/src/components/utility/AspectRatio/AspectRatio.types.ts +13 -0
  580. package/src/components/utility/AspectRatio/index.ts +2 -0
  581. package/src/components/utility/InfiniteScroll/InfiniteScroll.md +531 -0
  582. package/src/components/utility/InfiniteScroll/InfiniteScroll.stories.tsx +620 -0
  583. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +358 -0
  584. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +204 -0
  585. package/src/components/utility/InfiniteScroll/InfiniteScroll.types.ts +39 -0
  586. package/src/components/utility/InfiniteScroll/index.ts +6 -0
  587. package/src/components/utility/Portal/Portal.button-container.example.tsx +99 -0
  588. package/src/components/utility/Portal/Portal.md +593 -0
  589. package/src/components/utility/Portal/Portal.stories.tsx +340 -0
  590. package/src/components/utility/Portal/Portal.test.stories.tsx +2086 -0
  591. package/src/components/utility/Portal/Portal.tsx +39 -0
  592. package/src/components/utility/Portal/Portal.types.ts +7 -0
  593. package/src/components/utility/Portal/index.ts +2 -0
  594. package/src/components/utility/Transition/Transition.md +684 -0
  595. package/src/components/utility/Transition/Transition.stories.tsx +493 -0
  596. package/src/components/utility/Transition/Transition.test.stories.tsx +854 -0
  597. package/src/components/utility/Transition/Transition.tsx +140 -0
  598. package/src/components/utility/Transition/Transition.types.ts +14 -0
  599. package/src/components/utility/Transition/index.ts +6 -0
  600. package/src/components/utility/VirtualList/VirtualList.md +520 -0
  601. package/src/components/utility/VirtualList/VirtualList.stories.tsx +1073 -0
  602. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +1074 -0
  603. package/src/components/utility/VirtualList/VirtualList.tsx +369 -0
  604. package/src/components/utility/VirtualList/VirtualList.types.ts +56 -0
  605. package/src/components/utility/VirtualList/index.ts +7 -0
  606. package/src/components/utility/WorkflowStep/WorkflowStep.md +187 -0
  607. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +433 -0
  608. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +364 -0
  609. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +506 -0
  610. package/src/components/utility/WorkflowStep/WorkflowStep.types.ts +133 -0
  611. package/src/components/utility/WorkflowStep/index.ts +13 -0
  612. package/src/components/utility/index.ts +7 -0
  613. package/src/index.ts +17 -0
  614. package/src/mui/AppBar.ts +2 -0
  615. package/src/mui/Box.ts +2 -0
  616. package/src/mui/CssBaseline.ts +2 -0
  617. package/src/mui/FormControl.ts +2 -0
  618. package/src/mui/FormControlLabel.ts +2 -0
  619. package/src/mui/Grid2.ts +2 -0
  620. package/src/mui/InputLabel.ts +2 -0
  621. package/src/mui/List.ts +2 -0
  622. package/src/mui/ListItem.ts +2 -0
  623. package/src/mui/ListItemButton.ts +2 -0
  624. package/src/mui/ListItemText.ts +2 -0
  625. package/src/mui/Stack.ts +2 -0
  626. package/src/mui/SvgIcon.ts +2 -0
  627. package/src/mui/Toolbar.ts +2 -0
  628. package/src/mui/styles.ts +2 -0
  629. package/src/mui/useMediaQuery.ts +1 -0
  630. package/src/social-login-button.tsx +199 -0
  631. package/src/user-avatar.tsx +102 -0
  632. package/src/utils/cn.ts +9 -0
  633. package/src/utils/index.ts +1 -0
@@ -0,0 +1,2070 @@
1
+ import { Box, Button, Stack,Typography } from '@mui/material';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ import React from 'react';
4
+ import { expect, userEvent, waitFor,within } from 'storybook/test';
5
+
6
+ import { Progress } from './Progress';
7
+
8
+ const meta: Meta<typeof Progress> = {
9
+ title: 'DataDisplay/Progress/Tests',
10
+ component: Progress,
11
+ parameters: {
12
+ layout: 'centered',
13
+ chromatic: { disableSnapshot: false },
14
+ },
15
+ tags: ['autodocs', 'test', 'component:Progress', 'checked'],
16
+ };
17
+
18
+ export default meta;
19
+ type Story = StoryObj<typeof meta>;
20
+
21
+ // Basic Interaction Tests
22
+ export const BasicInteraction: Story = {
23
+ name: '🧪 Basic Interaction Test',
24
+ args: {
25
+ value: 50,
26
+ showLabel: true,
27
+ },
28
+ render: (args) => (
29
+ <Box data-testid="progress-container" sx={{ width: 300, p: 2 }}>
30
+ <Progress {...args} data-testid="progress-component" />
31
+ <Typography variant="caption" sx={{ mt: 1, display: 'block' }}>
32
+ Progress: {args.value}%
33
+ </Typography>
34
+ </Box>
35
+ ),
36
+ play: async ({ canvasElement, step }) => {
37
+ const canvas = within(canvasElement);
38
+
39
+ await step('Initial render verification', async () => {
40
+ const container = canvas.getByTestId('progress-container');
41
+ await expect(container).toBeInTheDocument();
42
+
43
+ const progressComponent = canvas.getByTestId('progress-component');
44
+ await expect(progressComponent).toBeInTheDocument();
45
+
46
+ // Check for progress value display
47
+ const label = canvas.getByText('50%');
48
+ await expect(label).toBeInTheDocument();
49
+ });
50
+
51
+ await step('Progress component properties', async () => {
52
+ const progressComponent = canvas.getByTestId('progress-component');
53
+ await expect(progressComponent).toHaveAttribute('data-testid', 'progress-component');
54
+
55
+ // Verify progress bar is visible
56
+ const progressBar = progressComponent.querySelector('.MuiLinearProgress-bar');
57
+ await expect(progressBar).toBeInTheDocument();
58
+
59
+ // Check that progress value is reflected in the bar's style
60
+ if (progressBar) {
61
+ const computedStyle = window.getComputedStyle(progressBar);
62
+ const transform = computedStyle.transform;
63
+
64
+ // Progress bar should have some transform or width for determinate state
65
+ // MUI LinearProgress may use different methods (transform or width)
66
+ if (transform && transform !== 'none') {
67
+ // Transform is being used
68
+ expect(transform).toBeTruthy();
69
+
70
+ // Just verify it has a transform, don't assume specific values
71
+ // as MUI implementation may vary
72
+ if (transform.includes('matrix')) {
73
+ const matrixValues = transform.match(/matrix\(([^)]+)\)/);
74
+ expect(matrixValues).toBeTruthy();
75
+ } else if (transform.includes('translateX') || transform.includes('scaleX')) {
76
+ // Has some form of transform
77
+ expect(transform).toMatch(/translateX|scaleX/);
78
+ }
79
+ }
80
+
81
+ // Also check if width is being used instead of transform
82
+ const width = computedStyle.width;
83
+ if (width && width !== 'auto' && width !== '100%') {
84
+ // Width-based progress indication
85
+ expect(width).toBeTruthy();
86
+ }
87
+ }
88
+ });
89
+
90
+ await step('Visual state verification', async () => {
91
+ const progressComponent = canvas.getByTestId('progress-component');
92
+ const computedStyle = window.getComputedStyle(progressComponent);
93
+
94
+ // Should be visible and have proper dimensions
95
+ await expect(computedStyle.display).not.toBe('none');
96
+ await expect(progressComponent).toBeVisible();
97
+ });
98
+ },
99
+ };
100
+
101
+ // Form Interaction Test (Progress can be controlled)
102
+ const FormInteractionComponent = () => {
103
+ const [progress, setProgress] = React.useState(0);
104
+ const [isRunning, setIsRunning] = React.useState(false);
105
+
106
+ const startProgress = () => {
107
+ setIsRunning(true);
108
+ setProgress(0);
109
+
110
+ const interval = window.setInterval(() => {
111
+ setProgress((prev) => {
112
+ if (prev >= 100) {
113
+ window.clearInterval(interval);
114
+ setIsRunning(false);
115
+ return 100;
116
+ }
117
+ return prev + 10;
118
+ });
119
+ }, 100);
120
+ };
121
+
122
+ const resetProgress = () => {
123
+ setProgress(0);
124
+ setIsRunning(false);
125
+ };
126
+
127
+ return (
128
+ <Box sx={{ width: 400, p: 2 }}>
129
+ <Progress value={progress} showLabel data-testid="controllable-progress" color="primary" />
130
+ <Box sx={{ mt: 2, display: 'flex', gap: 1 }}>
131
+ <Button
132
+ variant="contained"
133
+ onClick={startProgress}
134
+ disabled={isRunning}
135
+ data-testid="start-button"
136
+ >
137
+ Start
138
+ </Button>
139
+ <Button variant="outlined" onClick={resetProgress} data-testid="reset-button">
140
+ Reset
141
+ </Button>
142
+ </Box>
143
+ <Typography variant="caption" sx={{ mt: 1, display: 'block' }}>
144
+ Status: {isRunning ? 'Running' : 'Stopped'}
145
+ </Typography>
146
+ </Box>
147
+ );
148
+ };
149
+
150
+ export const FormInteraction: Story = {
151
+ name: '📝 Form Interaction Test',
152
+ render: () => <FormInteractionComponent />,
153
+ play: async ({ canvasElement, step }) => {
154
+ const canvas = within(canvasElement);
155
+
156
+ await step('Initial state verification', async () => {
157
+ const progressComponent = canvas.getByTestId('controllable-progress');
158
+ await expect(progressComponent).toBeInTheDocument();
159
+
160
+ const startButton = canvas.getByTestId('start-button');
161
+ const resetButton = canvas.getByTestId('reset-button');
162
+
163
+ await expect(startButton).toBeEnabled();
164
+ await expect(resetButton).toBeEnabled();
165
+
166
+ // Should show 0% initially
167
+ const progressContainer = canvas.getByTestId('controllable-progress').parentElement;
168
+ await expect(progressContainer).toHaveTextContent('0%');
169
+ });
170
+
171
+ await step('Start progress interaction', async () => {
172
+ const startButton = canvas.getByTestId('start-button');
173
+ await userEvent.click(startButton);
174
+
175
+ // Button should become disabled when running
176
+ await expect(startButton).toBeDisabled();
177
+
178
+ // Status should change to running
179
+ await waitFor(
180
+ () => {
181
+ const status = canvas.getByText('Status: Running');
182
+ expect(status).toBeInTheDocument();
183
+ },
184
+ { timeout: 2000 },
185
+ );
186
+ });
187
+
188
+ await step('Progress value changes verification', async () => {
189
+ // Store initial transform value
190
+ const progressComponent = canvas.getByTestId('controllable-progress');
191
+ const progressBar = progressComponent.querySelector('.MuiLinearProgress-bar');
192
+ let previousTransform = '';
193
+
194
+ if (progressBar) {
195
+ previousTransform = window.getComputedStyle(progressBar).transform;
196
+ }
197
+
198
+ // Wait for progress to start changing
199
+ await waitFor(
200
+ () => {
201
+ const progressBar = progressComponent.querySelector('.MuiLinearProgress-bar');
202
+
203
+ if (progressBar) {
204
+ const computedStyle = window.getComputedStyle(progressBar);
205
+ const currentTransform = computedStyle.transform;
206
+
207
+ // Transform or style should be changing as progress updates
208
+ if (currentTransform && currentTransform !== 'none') {
209
+ expect(currentTransform).not.toBe(previousTransform);
210
+ }
211
+
212
+ // Also check width changes as an alternative progress indicator
213
+ const currentWidth = computedStyle.width;
214
+ if (currentWidth && currentWidth !== 'auto') {
215
+ // Just verify something is changing
216
+ expect(currentTransform !== previousTransform || currentWidth).toBeTruthy();
217
+ }
218
+ }
219
+ },
220
+ { timeout: 3000 },
221
+ );
222
+
223
+ // Check that progress values are changing by verifying multiple intermediate values
224
+ const seenValues = new Set();
225
+ await waitFor(
226
+ () => {
227
+ const progressContainer = canvas.getByTestId('controllable-progress').parentElement;
228
+ const textContent = progressContainer?.textContent || '';
229
+
230
+ // Extract percentage value
231
+ const percentMatch = textContent.match(/(\d+)%/);
232
+ if (percentMatch) {
233
+ const value = parseInt(percentMatch[1]);
234
+ seenValues.add(value);
235
+ }
236
+
237
+ // We should see at least 3 different values during animation
238
+ expect(seenValues.size).toBeGreaterThanOrEqual(3);
239
+ },
240
+ { timeout: 3000 },
241
+ );
242
+ });
243
+
244
+ await step('Progress completion', async () => {
245
+ // Wait for progress to complete
246
+ await waitFor(
247
+ () => {
248
+ const completedLabel = canvas.queryByText('100%');
249
+ expect(completedLabel).toBeInTheDocument();
250
+ },
251
+ { timeout: 5000 },
252
+ );
253
+
254
+ // Verify the progress bar shows full completion
255
+ const progressComponent = canvas.getByTestId('controllable-progress');
256
+ const progressBar = progressComponent.querySelector('.MuiLinearProgress-bar');
257
+
258
+ if (progressBar) {
259
+ const computedStyle = window.getComputedStyle(progressBar);
260
+ const transform = computedStyle.transform;
261
+
262
+ // At 100%, the progress should be complete
263
+ // MUI may use transform or width to show this
264
+ if (transform && transform !== 'none') {
265
+ expect(transform).toBeTruthy();
266
+ // Just verify it has changed from initial state
267
+ } else {
268
+ // Check if width indicates 100%
269
+ const width = computedStyle.width;
270
+ if (width) {
271
+ expect(width).toBeTruthy();
272
+ }
273
+ }
274
+ }
275
+
276
+ // Button should be re-enabled after completion
277
+ await waitFor(
278
+ () => {
279
+ const startButton = canvas.getByTestId('start-button');
280
+ expect(startButton).toBeEnabled();
281
+ },
282
+ { timeout: 1000 },
283
+ );
284
+ });
285
+
286
+ await step('Reset functionality', async () => {
287
+ const resetButton = canvas.getByTestId('reset-button');
288
+ await userEvent.click(resetButton);
289
+
290
+ // Should reset to 0%
291
+ await waitFor(() => {
292
+ const progressContainer = canvas.getByTestId('controllable-progress').parentElement;
293
+ expect(progressContainer).toHaveTextContent('0%');
294
+ });
295
+
296
+ // Status should change to stopped
297
+ const status = canvas.getByText('Status: Stopped');
298
+ await expect(status).toBeInTheDocument();
299
+ });
300
+ },
301
+ };
302
+
303
+ // Keyboard Navigation Test
304
+ export const KeyboardNavigation: Story = {
305
+ name: '⌨️ Keyboard Navigation Test',
306
+ args: {
307
+ value: 60,
308
+ showLabel: true,
309
+ },
310
+ parameters: {
311
+ a11y: {
312
+ element: '#storybook-root',
313
+ config: {
314
+ rules: [
315
+ { id: 'color-contrast', enabled: true },
316
+ { id: 'aria-required-attr', enabled: true },
317
+ { id: 'aria-roles', enabled: true },
318
+ { id: 'aria-valid-attr-value', enabled: true },
319
+ { id: 'duplicate-id', enabled: true },
320
+ { id: 'label', enabled: true },
321
+ ],
322
+ },
323
+ },
324
+ },
325
+ render: (args) => (
326
+ <Box sx={{ width: 400, p: 2 }}>
327
+ <Typography variant="h6" sx={{ mb: 2 }}>
328
+ Progress Accessibility Test
329
+ </Typography>
330
+ <Button data-testid="before-progress" tabIndex={0}>
331
+ Before Progress
332
+ </Button>
333
+ <Box sx={{ my: 2 }}>
334
+ <Progress
335
+ {...args}
336
+ data-testid="progress-keyboard"
337
+ role="progressbar"
338
+ aria-valuemin={0}
339
+ aria-valuemax={100}
340
+ aria-valuenow={args.value}
341
+ aria-label="Loading progress"
342
+ />
343
+ </Box>
344
+ <Button data-testid="after-progress" tabIndex={0}>
345
+ After Progress
346
+ </Button>
347
+ </Box>
348
+ ),
349
+ play: async ({ canvasElement, step }) => {
350
+ const canvas = within(canvasElement);
351
+
352
+ await step('Progress accessibility attributes', async () => {
353
+ const progressComponent = canvas.getByTestId('progress-keyboard');
354
+
355
+ // Check ARIA attributes
356
+ await expect(progressComponent).toHaveAttribute('role', 'progressbar');
357
+ await expect(progressComponent).toHaveAttribute('aria-valuemin', '0');
358
+ await expect(progressComponent).toHaveAttribute('aria-valuemax', '100');
359
+ await expect(progressComponent).toHaveAttribute('aria-valuenow', '60');
360
+ await expect(progressComponent).toHaveAttribute('aria-label', 'Loading progress');
361
+ });
362
+
363
+ await step('Tab navigation sequence', async () => {
364
+ const beforeButton = canvas.getByTestId('before-progress');
365
+ const afterButton = canvas.getByTestId('after-progress');
366
+
367
+ // Start from before button
368
+ beforeButton.focus();
369
+ await expect(beforeButton).toHaveFocus();
370
+
371
+ // Tab to after button (progress should be skipped as it's not interactive)
372
+ await userEvent.tab();
373
+ await expect(afterButton).toHaveFocus();
374
+
375
+ // Tab backward
376
+ await userEvent.tab({ shift: true });
377
+ await expect(beforeButton).toHaveFocus();
378
+ });
379
+
380
+ await step('Screen reader compatibility', async () => {
381
+ const progressComponent = canvas.getByTestId('progress-keyboard');
382
+
383
+ // Should be findable by screen reader via role
384
+ const progressByRole = canvas.getByRole('progressbar');
385
+ await expect(progressByRole).toBe(progressComponent);
386
+
387
+ // Should be findable by accessible name
388
+ const progressByLabel = canvas.getByLabelText('Loading progress');
389
+ await expect(progressByLabel).toBe(progressComponent);
390
+ });
391
+ },
392
+ };
393
+
394
+ // Screen Reader Test
395
+ export const ScreenReader: Story = {
396
+ name: '🔊 Screen Reader Test',
397
+ render: () => (
398
+ <Box sx={{ width: 500, p: 2 }}>
399
+ <Typography variant="h6" sx={{ mb: 2 }} id="progress-section">
400
+ File Upload Progress
401
+ </Typography>
402
+
403
+ <Progress
404
+ value={75}
405
+ showLabel
406
+ data-testid="screen-reader-progress"
407
+ role="progressbar"
408
+ aria-valuemin={0}
409
+ aria-valuemax={100}
410
+ aria-valuenow={75}
411
+ aria-label="File upload progress"
412
+ aria-describedby="progress-description"
413
+ />
414
+
415
+ <Typography
416
+ id="progress-description"
417
+ variant="body2"
418
+ sx={{ mt: 1 }}
419
+ data-testid="progress-description"
420
+ >
421
+ Uploading document.pdf - 3 of 4 files completed
422
+ </Typography>
423
+
424
+ <div role="status" aria-live="polite" data-testid="live-region">
425
+ Upload progress: 75% complete
426
+ </div>
427
+
428
+ {/* Different progress states for screen reader testing */}
429
+ <Box sx={{ mt: 3 }}>
430
+ <Typography variant="subtitle2" sx={{ mb: 1 }}>
431
+ Loading State
432
+ </Typography>
433
+ <Progress
434
+ data-testid="indeterminate-progress"
435
+ role="progressbar"
436
+ aria-label="Loading content"
437
+ aria-describedby="loading-description"
438
+ />
439
+ <Typography id="loading-description" variant="caption" sx={{ display: 'block', mt: 0.5 }}>
440
+ Please wait while content loads...
441
+ </Typography>
442
+ </Box>
443
+ </Box>
444
+ ),
445
+ play: async ({ canvasElement, step }) => {
446
+ const canvas = within(canvasElement);
447
+
448
+ await step('ARIA labels verification', async () => {
449
+ const progressComponent = canvas.getByTestId('screen-reader-progress');
450
+
451
+ await expect(progressComponent).toHaveAttribute('aria-label', 'File upload progress');
452
+ await expect(progressComponent).toHaveAttribute('aria-describedby', 'progress-description');
453
+ await expect(progressComponent).toHaveAttribute('role', 'progressbar');
454
+
455
+ // Should be findable by screen readers
456
+ const progressByLabel = canvas.getByLabelText('File upload progress');
457
+ await expect(progressByLabel).toBe(progressComponent);
458
+ });
459
+
460
+ await step('ARIA descriptions verification', async () => {
461
+ const description = canvas.getByTestId('progress-description');
462
+ await expect(description).toBeInTheDocument();
463
+ await expect(description).toHaveAttribute('id', 'progress-description');
464
+
465
+ const descriptionText = canvas.getByText(/Uploading document.pdf/);
466
+ await expect(descriptionText).toBeInTheDocument();
467
+ });
468
+
469
+ await step('Live region verification', async () => {
470
+ const liveRegion = canvas.getByTestId('live-region');
471
+ await expect(liveRegion).toHaveAttribute('role', 'status');
472
+ await expect(liveRegion).toHaveAttribute('aria-live', 'polite');
473
+
474
+ const liveText = canvas.getByText('Upload progress: 75% complete');
475
+ await expect(liveText).toBeInTheDocument();
476
+ });
477
+
478
+ await step('Indeterminate progress accessibility', async () => {
479
+ const indeterminateProgress = canvas.getByTestId('indeterminate-progress');
480
+
481
+ await expect(indeterminateProgress).toHaveAttribute('role', 'progressbar');
482
+ await expect(indeterminateProgress).toHaveAttribute('aria-label', 'Loading content');
483
+ await expect(indeterminateProgress).toHaveAttribute(
484
+ 'aria-describedby',
485
+ 'loading-description',
486
+ );
487
+
488
+ // For indeterminate progress, aria-valuenow should not be set
489
+ await expect(indeterminateProgress).not.toHaveAttribute('aria-valuenow');
490
+
491
+ // Verify indeterminate animation is active
492
+ const indeterminateBar = indeterminateProgress.querySelector(
493
+ '.MuiLinearProgress-bar1Indeterminate, .MuiLinearProgress-bar',
494
+ );
495
+ if (indeterminateBar) {
496
+ const computedStyle = window.getComputedStyle(indeterminateBar);
497
+ // Should have animation for indeterminate state
498
+ expect(computedStyle.animation || computedStyle.animationName).not.toBe('none');
499
+ }
500
+ });
501
+
502
+ await step('Progress role verification', async () => {
503
+ // All progress elements should be findable by role
504
+ const allProgressBars = canvas.getAllByRole('progressbar');
505
+ await expect(allProgressBars).toHaveLength(2);
506
+
507
+ // Each should have appropriate labeling
508
+ allProgressBars.forEach(async (progress) => {
509
+ const hasLabel =
510
+ progress.hasAttribute('aria-label') || progress.hasAttribute('aria-labelledby');
511
+ await expect(hasLabel).toBe(true);
512
+ });
513
+ });
514
+ },
515
+ };
516
+
517
+ // Focus Management Test
518
+ const FocusManagementComponent = () => {
519
+ const [showProgress, setShowProgress] = React.useState(false);
520
+ const [progress, setProgress] = React.useState(0);
521
+
522
+ const startTask = () => {
523
+ setShowProgress(true);
524
+ setProgress(0);
525
+
526
+ const interval = window.setInterval(() => {
527
+ setProgress((prev) => {
528
+ if (prev >= 100) {
529
+ window.clearInterval(interval);
530
+ return 100;
531
+ }
532
+ return prev + 20;
533
+ });
534
+ }, 500);
535
+ };
536
+
537
+ return (
538
+ <Box sx={{ width: 400, p: 2 }}>
539
+ <Typography variant="h6" sx={{ mb: 2 }}>
540
+ Focus Management Demo
541
+ </Typography>
542
+
543
+ <Button
544
+ data-testid="trigger-button"
545
+ variant="contained"
546
+ onClick={startTask}
547
+ disabled={showProgress}
548
+ >
549
+ Start Task
550
+ </Button>
551
+
552
+ {showProgress && (
553
+ <Box sx={{ mt: 2 }} data-testid="progress-section">
554
+ <Typography variant="body2" sx={{ mb: 1 }}>
555
+ Task in progress...
556
+ </Typography>
557
+ <Progress
558
+ value={progress}
559
+ showLabel
560
+ data-testid="focus-progress"
561
+ role="progressbar"
562
+ aria-label="Task progress"
563
+ aria-valuemin={0}
564
+ aria-valuemax={100}
565
+ aria-valuenow={progress}
566
+ />
567
+
568
+ {progress === 100 && (
569
+ <Box sx={{ mt: 2 }}>
570
+ <Typography variant="body2" color="success.main" sx={{ mb: 1 }}>
571
+ Task completed successfully!
572
+ </Typography>
573
+ <Button
574
+ data-testid="completion-button"
575
+ variant="outlined"
576
+ onClick={() => setShowProgress(false)}
577
+ autoFocus
578
+ >
579
+ Continue
580
+ </Button>
581
+ </Box>
582
+ )}
583
+ </Box>
584
+ )}
585
+ </Box>
586
+ );
587
+ };
588
+
589
+ export const FocusManagement: Story = {
590
+ name: '🎯 Focus Management Test',
591
+ render: () => <FocusManagementComponent />,
592
+ play: async ({ canvasElement, step }) => {
593
+ const canvas = within(canvasElement);
594
+
595
+ await step('Initial focus state', async () => {
596
+ const triggerButton = canvas.getByTestId('trigger-button');
597
+ await expect(triggerButton).toBeInTheDocument();
598
+ await expect(triggerButton).toBeEnabled();
599
+ });
600
+
601
+ await step('Progress appearance and focus', async () => {
602
+ const triggerButton = canvas.getByTestId('trigger-button');
603
+ triggerButton.focus();
604
+ await expect(triggerButton).toHaveFocus();
605
+
606
+ await userEvent.click(triggerButton);
607
+
608
+ // Progress should appear
609
+ await waitFor(() => {
610
+ const progressSection = canvas.getByTestId('progress-section');
611
+ expect(progressSection).toBeInTheDocument();
612
+ });
613
+
614
+ const progressComponent = canvas.getByTestId('focus-progress');
615
+ await expect(progressComponent).toBeInTheDocument();
616
+
617
+ // Trigger button should be disabled
618
+ await expect(triggerButton).toBeDisabled();
619
+ });
620
+
621
+ await step('Progress completion and focus restoration', async () => {
622
+ // Wait for progress to complete
623
+ await waitFor(
624
+ () => {
625
+ const completionMessage = canvas.getByText('Task completed successfully!');
626
+ expect(completionMessage).toBeInTheDocument();
627
+ },
628
+ { timeout: 8000 },
629
+ );
630
+
631
+ // Continue button should appear with auto focus
632
+ const continueButton = canvas.getByTestId('completion-button');
633
+ await expect(continueButton).toBeInTheDocument();
634
+
635
+ await waitFor(
636
+ () => {
637
+ expect(continueButton).toHaveFocus();
638
+ },
639
+ { timeout: 1000 },
640
+ );
641
+ });
642
+
643
+ await step('Focus restoration after cleanup', async () => {
644
+ const continueButton = canvas.getByTestId('completion-button');
645
+ await userEvent.click(continueButton);
646
+
647
+ // Progress section should disappear
648
+ await waitFor(() => {
649
+ const progressSection = canvas.queryByTestId('progress-section');
650
+ expect(progressSection).not.toBeInTheDocument();
651
+ });
652
+
653
+ // Trigger button should be enabled again
654
+ const triggerButton = canvas.getByTestId('trigger-button');
655
+ await expect(triggerButton).toBeEnabled();
656
+ });
657
+ },
658
+ };
659
+
660
+ // Responsive Design Test
661
+ export const ResponsiveDesign: Story = {
662
+ name: '📱 Responsive Design Test',
663
+ parameters: {
664
+ viewport: {
665
+ viewports: {
666
+ mobile: {
667
+ name: 'Mobile',
668
+ styles: { width: '375px', height: '667px' },
669
+ type: 'mobile',
670
+ },
671
+ tablet: {
672
+ name: 'Tablet',
673
+ styles: { width: '768px', height: '1024px' },
674
+ type: 'tablet',
675
+ },
676
+ desktop: {
677
+ name: 'Desktop',
678
+ styles: { width: '1920px', height: '1080px' },
679
+ type: 'desktop',
680
+ },
681
+ },
682
+ defaultViewport: 'mobile',
683
+ },
684
+ chromatic: {
685
+ viewports: [375, 768, 1920],
686
+ delay: 300,
687
+ },
688
+ },
689
+ render: () => (
690
+ <Box sx={{ p: 2, maxWidth: '100%' }}>
691
+ <Typography variant="h6" sx={{ mb: 3 }}>
692
+ Responsive Progress Components
693
+ </Typography>
694
+
695
+ <Stack spacing={3} data-testid="responsive-container">
696
+ {/* Linear Progress - should adapt width */}
697
+ <Box>
698
+ <Typography variant="subtitle2" sx={{ mb: 1 }}>
699
+ Linear Progress (Full Width)
700
+ </Typography>
701
+ <Progress value={60} showLabel data-testid="responsive-linear" sx={{ width: '100%' }} />
702
+ </Box>
703
+
704
+ {/* Circular Progress - should center on small screens */}
705
+ <Box
706
+ sx={{
707
+ display: 'flex',
708
+ flexDirection: { xs: 'column', sm: 'row' },
709
+ alignItems: 'center',
710
+ gap: 2,
711
+ }}
712
+ >
713
+ <Typography variant="subtitle2">Circular Progress:</Typography>
714
+ <Progress variant="circular" value={75} showLabel data-testid="responsive-circular" />
715
+ </Box>
716
+
717
+ {/* Segmented Progress - should adapt segment sizes */}
718
+ <Box>
719
+ <Typography variant="subtitle2" sx={{ mb: 1 }}>
720
+ Segmented Progress (Adaptive)
721
+ </Typography>
722
+ <Progress
723
+ variant="segmented"
724
+ segments={10}
725
+ value={80}
726
+ showLabel
727
+ data-testid="responsive-segmented"
728
+ />
729
+ </Box>
730
+
731
+ {/* Multiple sizes for different viewports */}
732
+ <Box
733
+ sx={{
734
+ display: 'grid',
735
+ gridTemplateColumns: { xs: '1fr', sm: 'repeat(3, 1fr)' },
736
+ gap: 2,
737
+ mt: 2,
738
+ }}
739
+ >
740
+ <Box textAlign="center">
741
+ <Typography variant="caption" sx={{ display: 'block', mb: 1 }}>
742
+ Small
743
+ </Typography>
744
+ <Progress
745
+ variant="circular"
746
+ size="sm"
747
+ value={40}
748
+ showLabel
749
+ data-testid="responsive-small"
750
+ />
751
+ </Box>
752
+ <Box textAlign="center">
753
+ <Typography variant="caption" sx={{ display: 'block', mb: 1 }}>
754
+ Medium
755
+ </Typography>
756
+ <Progress
757
+ variant="circular"
758
+ size="md"
759
+ value={60}
760
+ showLabel
761
+ data-testid="responsive-medium"
762
+ />
763
+ </Box>
764
+ <Box textAlign="center">
765
+ <Typography variant="caption" sx={{ display: 'block', mb: 1 }}>
766
+ Large
767
+ </Typography>
768
+ <Progress
769
+ variant="circular"
770
+ size="lg"
771
+ value={80}
772
+ showLabel
773
+ data-testid="responsive-large"
774
+ />
775
+ </Box>
776
+ </Box>
777
+ </Stack>
778
+ </Box>
779
+ ),
780
+ play: async ({ canvasElement, step }) => {
781
+ const canvas = within(canvasElement);
782
+
783
+ await step('Container responsiveness', async () => {
784
+ const container = canvas.getByTestId('responsive-container');
785
+ await expect(container).toBeInTheDocument();
786
+
787
+ const computedStyle = window.getComputedStyle(container);
788
+ await expect(computedStyle.display).toBe('flex');
789
+ });
790
+
791
+ await step('Linear progress width adaptation', async () => {
792
+ const linearProgress = canvas.getByTestId('responsive-linear');
793
+ await expect(linearProgress).toBeInTheDocument();
794
+
795
+ const computedStyle = window.getComputedStyle(linearProgress);
796
+ // Should take full width of container
797
+ expect(computedStyle.width).toBeTruthy();
798
+ });
799
+
800
+ await step('Circular progress visibility and value verification', async () => {
801
+ const circularProgress = canvas.getByTestId('responsive-circular');
802
+ await expect(circularProgress).toBeInTheDocument();
803
+ await expect(circularProgress).toBeVisible();
804
+
805
+ // Should maintain aspect ratio
806
+ const boundingBox = circularProgress.getBoundingClientRect();
807
+ expect(boundingBox.width).toBeGreaterThan(0);
808
+ expect(boundingBox.height).toBeGreaterThan(0);
809
+
810
+ // Verify actual circular progress value (75%) is reflected in stroke-dashoffset
811
+ const circularPath = circularProgress.querySelector('.MuiCircularProgress-circle');
812
+
813
+ if (circularPath) {
814
+ const computedStyle = window.getComputedStyle(circularPath);
815
+ const strokeDashArray = computedStyle.strokeDasharray;
816
+ const strokeDashOffset = computedStyle.strokeDashoffset;
817
+
818
+ // For a 75% progress, stroke-dashoffset should be about 25% of stroke-dasharray
819
+ if (strokeDashArray && strokeDashOffset && strokeDashArray !== 'none') {
820
+ const dashArrayValue = parseFloat(strokeDashArray.split(',')[0] || strokeDashArray);
821
+ const dashOffsetValue = parseFloat(strokeDashOffset);
822
+
823
+ // The offset should represent the remaining 25% (100% - 75%)
824
+ // MUI CircularProgress calculates offset as: circumference * (1 - value/100)
825
+ const progressRatio = 1 - dashOffsetValue / dashArrayValue;
826
+ expect(progressRatio).toBeCloseTo(0.75, 1); // Should be close to 75%
827
+ }
828
+ }
829
+ });
830
+
831
+ await step('Segmented progress adaptation and fill calculation', async () => {
832
+ const segmentedProgress = canvas.getByTestId('responsive-segmented');
833
+ await expect(segmentedProgress).toBeInTheDocument();
834
+
835
+ // Should contain segment elements - look for the container with display: flex
836
+ const segmentContainer = segmentedProgress.querySelector(
837
+ 'div[style*="display: flex"], div div',
838
+ );
839
+ if (segmentContainer) {
840
+ const segments = segmentContainer.children;
841
+ expect(segments.length).toBe(10); // Should have exactly 10 segments
842
+
843
+ // For 80% progress with 10 segments, 8 segments should be filled
844
+ // Test the background colors to verify which segments are filled
845
+ let filledSegments = 0;
846
+ let emptySegments = 0;
847
+
848
+ for (let i = 0; i < segments.length; i++) {
849
+ const segment = segments[i] as HTMLElement;
850
+ const computedStyle = window.getComputedStyle(segment);
851
+ const backgroundColor = computedStyle.backgroundColor;
852
+
853
+ // Parse RGB values to determine if segment is filled or empty
854
+ // Filled segments have solid color, empty ones have low opacity (0.1)
855
+ if (backgroundColor && backgroundColor.includes('rgba')) {
856
+ const rgbaMatch = backgroundColor.match(/rgba\(([^)]+)\)/);
857
+ if (rgbaMatch) {
858
+ const values = rgbaMatch[1].split(',').map((v) => v.trim());
859
+ const opacity = parseFloat(values[3] || '1');
860
+
861
+ if (opacity < 0.2) {
862
+ emptySegments++;
863
+ } else {
864
+ filledSegments++;
865
+ }
866
+ }
867
+ } else if (backgroundColor && backgroundColor.includes('rgb')) {
868
+ // Solid RGB color means filled
869
+ filledSegments++;
870
+ }
871
+ }
872
+
873
+ // For 80% of 10 segments, we expect exactly 8 filled and 2 empty
874
+ expect(filledSegments).toBe(8);
875
+ expect(emptySegments).toBe(2);
876
+ } else {
877
+ // If we can't find segments, just verify the component exists
878
+ await expect(segmentedProgress).toBeVisible();
879
+ }
880
+ });
881
+
882
+ await step('Size variants responsive behavior', async () => {
883
+ const smallProgress = canvas.getByTestId('responsive-small');
884
+ const mediumProgress = canvas.getByTestId('responsive-medium');
885
+ const largeProgress = canvas.getByTestId('responsive-large');
886
+
887
+ await expect(smallProgress).toBeVisible();
888
+ await expect(mediumProgress).toBeVisible();
889
+ await expect(largeProgress).toBeVisible();
890
+
891
+ // Each should be properly sized
892
+ const smallBounds = smallProgress.getBoundingClientRect();
893
+ const mediumBounds = mediumProgress.getBoundingClientRect();
894
+ const largeBounds = largeProgress.getBoundingClientRect();
895
+
896
+ expect(smallBounds.width).toBeLessThan(mediumBounds.width);
897
+ expect(mediumBounds.width).toBeLessThan(largeBounds.width);
898
+ });
899
+ },
900
+ };
901
+
902
+ // Theme Variations Test
903
+ export const ThemeVariations: Story = {
904
+ name: '🎨 Theme Variations Test',
905
+ parameters: {
906
+ backgrounds: {
907
+ default: 'light',
908
+ values: [
909
+ { name: 'light', value: '#ffffff' },
910
+ { name: 'dark', value: '#1a1a1a' },
911
+ ],
912
+ },
913
+ },
914
+ render: () => (
915
+ <Box sx={{ p: 3, width: 600 }}>
916
+ <Typography variant="h6" sx={{ mb: 3 }}>
917
+ Theme Color Variations
918
+ </Typography>
919
+
920
+ <Stack spacing={3} data-testid="theme-container">
921
+ {/* Primary Colors */}
922
+ <Box>
923
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
924
+ Color Themes
925
+ </Typography>
926
+ <Stack spacing={2}>
927
+ <Progress color="primary" value={70} showLabel data-testid="theme-primary" />
928
+ <Progress color="secondary" value={70} showLabel data-testid="theme-secondary" />
929
+ <Progress color="success" value={70} showLabel data-testid="theme-success" />
930
+ <Progress color="warning" value={70} showLabel data-testid="theme-warning" />
931
+ <Progress color="error" value={70} showLabel data-testid="theme-error" />
932
+ <Progress color="neutral" value={70} showLabel data-testid="theme-neutral" />
933
+ </Stack>
934
+ </Box>
935
+
936
+ {/* Variant with theme colors */}
937
+ <Box>
938
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
939
+ Circular with Theme Colors
940
+ </Typography>
941
+ <Stack direction="row" spacing={2} justifyContent="center">
942
+ <Progress
943
+ variant="circular"
944
+ color="primary"
945
+ value={60}
946
+ showLabel
947
+ data-testid="circular-primary"
948
+ />
949
+ <Progress
950
+ variant="circular"
951
+ color="success"
952
+ value={80}
953
+ showLabel
954
+ data-testid="circular-success"
955
+ />
956
+ <Progress
957
+ variant="circular"
958
+ color="warning"
959
+ value={45}
960
+ showLabel
961
+ data-testid="circular-warning"
962
+ />
963
+ </Stack>
964
+ </Box>
965
+
966
+ {/* Effects with theme colors */}
967
+ <Box>
968
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
969
+ Effects with Theme Colors
970
+ </Typography>
971
+ <Stack spacing={2}>
972
+ <Progress
973
+ variant="gradient"
974
+ color="primary"
975
+ value={65}
976
+ showLabel
977
+ glow
978
+ data-testid="gradient-glow"
979
+ />
980
+ <Progress color="success" value={85} showLabel pulse data-testid="linear-pulse" />
981
+ </Stack>
982
+ </Box>
983
+ </Stack>
984
+ </Box>
985
+ ),
986
+ play: async ({ canvasElement, step }) => {
987
+ const canvas = within(canvasElement);
988
+
989
+ await step('Theme color application', async () => {
990
+ const primaryProgress = canvas.getByTestId('theme-primary');
991
+ const successProgress = canvas.getByTestId('theme-success');
992
+ const errorProgress = canvas.getByTestId('theme-error');
993
+
994
+ await expect(primaryProgress).toBeInTheDocument();
995
+ await expect(successProgress).toBeInTheDocument();
996
+ await expect(errorProgress).toBeInTheDocument();
997
+
998
+ // Each should be visually distinct (we can't easily test exact colors,
999
+ // but we can verify they render and have different styling)
1000
+ const primaryBar = primaryProgress.querySelector('.MuiLinearProgress-bar');
1001
+ const successBar = successProgress.querySelector('.MuiLinearProgress-bar');
1002
+
1003
+ expect(primaryBar).toBeTruthy();
1004
+ expect(successBar).toBeTruthy();
1005
+
1006
+ if (primaryBar && successBar) {
1007
+ const primaryStyle = window.getComputedStyle(primaryBar);
1008
+ const successStyle = window.getComputedStyle(successBar);
1009
+
1010
+ // Colors should be different
1011
+ expect(primaryStyle.backgroundColor).not.toBe(successStyle.backgroundColor);
1012
+ }
1013
+ });
1014
+
1015
+ await step('Circular theme variations', async () => {
1016
+ const circularPrimary = canvas.getByTestId('circular-primary');
1017
+ const circularSuccess = canvas.getByTestId('circular-success');
1018
+ const circularWarning = canvas.getByTestId('circular-warning');
1019
+
1020
+ await expect(circularPrimary).toBeVisible();
1021
+ await expect(circularSuccess).toBeVisible();
1022
+ await expect(circularWarning).toBeVisible();
1023
+
1024
+ // Check for color attributes or styling differences
1025
+ const primaryCircle = circularPrimary.querySelector('.MuiCircularProgress-circle');
1026
+ const successCircle = circularSuccess.querySelector('.MuiCircularProgress-circle');
1027
+
1028
+ if (primaryCircle && successCircle) {
1029
+ const primaryStyle = window.getComputedStyle(primaryCircle);
1030
+ const successStyle = window.getComputedStyle(successCircle);
1031
+
1032
+ // Should have different stroke colors
1033
+ expect(primaryStyle.stroke || primaryStyle.color).not.toBe(
1034
+ successStyle.stroke || successStyle.color,
1035
+ );
1036
+ }
1037
+ });
1038
+
1039
+ await step('Effect styling with theme colors', async () => {
1040
+ const glowProgress = canvas.getByTestId('gradient-glow');
1041
+ const pulseProgress = canvas.getByTestId('linear-pulse');
1042
+
1043
+ await expect(glowProgress).toBeVisible();
1044
+ await expect(pulseProgress).toBeVisible();
1045
+
1046
+ // Verify glow effect is applied
1047
+ const glowBar = glowProgress.querySelector('.MuiLinearProgress-bar');
1048
+ if (glowBar) {
1049
+ const glowStyle = window.getComputedStyle(glowBar);
1050
+ // Should have box-shadow for glow effect
1051
+ expect(glowStyle.boxShadow).not.toBe('none');
1052
+ }
1053
+
1054
+ // Verify pulse animation is applied
1055
+ const pulseBar = pulseProgress.querySelector('.MuiLinearProgress-bar');
1056
+ if (pulseBar) {
1057
+ const pulseStyle = window.getComputedStyle(pulseBar);
1058
+ // Should have animation applied
1059
+ expect(pulseStyle.animation).not.toBe('none');
1060
+ }
1061
+ });
1062
+
1063
+ await step('Color contrast verification', async () => {
1064
+ // Verify all theme colors render with sufficient contrast
1065
+ const allThemeProgress = [
1066
+ canvas.getByTestId('theme-primary'),
1067
+ canvas.getByTestId('theme-secondary'),
1068
+ canvas.getByTestId('theme-success'),
1069
+ canvas.getByTestId('theme-warning'),
1070
+ canvas.getByTestId('theme-error'),
1071
+ canvas.getByTestId('theme-neutral'),
1072
+ ];
1073
+
1074
+ allThemeProgress.forEach(async (progress) => {
1075
+ await expect(progress).toBeVisible();
1076
+
1077
+ const progressBar = progress.querySelector('.MuiLinearProgress-bar');
1078
+ if (progressBar) {
1079
+ const computedStyle = window.getComputedStyle(progressBar);
1080
+ // Should have a background color set
1081
+ expect(computedStyle.backgroundColor).not.toBe('transparent');
1082
+ expect(computedStyle.backgroundColor).not.toBe('');
1083
+ }
1084
+ });
1085
+ });
1086
+ },
1087
+ };
1088
+
1089
+ // Visual States Test
1090
+ export const VisualStates: Story = {
1091
+ name: '👁️ Visual States Test',
1092
+ render: () => (
1093
+ <Box sx={{ p: 3, width: 700 }}>
1094
+ <Typography variant="h6" sx={{ mb: 3 }}>
1095
+ Visual States and Variants
1096
+ </Typography>
1097
+
1098
+ <Stack spacing={4} data-testid="visual-states-container">
1099
+ {/* Default states */}
1100
+ <Box>
1101
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1102
+ Default States
1103
+ </Typography>
1104
+ <Stack spacing={2}>
1105
+ <Box>
1106
+ <Typography variant="caption">Linear - 50%</Typography>
1107
+ <Progress value={50} showLabel data-testid="default-linear" />
1108
+ </Box>
1109
+ <Box>
1110
+ <Typography variant="caption">Indeterminate Linear</Typography>
1111
+ <Progress data-testid="default-indeterminate" />
1112
+ </Box>
1113
+ </Stack>
1114
+ </Box>
1115
+
1116
+ {/* Hover-like states (simulated through styling) */}
1117
+ <Box>
1118
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1119
+ Interactive States
1120
+ </Typography>
1121
+ <Stack spacing={2}>
1122
+ <Box>
1123
+ <Typography variant="caption">With Glow Effect</Typography>
1124
+ <Progress value={75} showLabel glow data-testid="glow-state" />
1125
+ </Box>
1126
+ <Box>
1127
+ <Typography variant="caption">With Pulse Animation</Typography>
1128
+ <Progress value={60} showLabel pulse data-testid="pulse-state" />
1129
+ </Box>
1130
+ <Box>
1131
+ <Typography variant="caption">Glass Effect</Typography>
1132
+ <Progress variant="glass" value={85} showLabel data-testid="glass-state" />
1133
+ </Box>
1134
+ </Stack>
1135
+ </Box>
1136
+
1137
+ {/* Loading states */}
1138
+ <Box>
1139
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1140
+ Loading States
1141
+ </Typography>
1142
+ <Stack spacing={2}>
1143
+ <Box>
1144
+ <Typography variant="caption">Linear Loading</Typography>
1145
+ <Progress data-testid="loading-linear" color="primary" />
1146
+ </Box>
1147
+ <Box>
1148
+ <Typography variant="caption">Circular Loading</Typography>
1149
+ <Progress variant="circular" data-testid="loading-circular" color="primary" />
1150
+ </Box>
1151
+ </Stack>
1152
+ </Box>
1153
+
1154
+ {/* Size variations */}
1155
+ <Box>
1156
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1157
+ Size Variations
1158
+ </Typography>
1159
+ <Stack spacing={2}>
1160
+ <Box>
1161
+ <Typography variant="caption">Small (4px height)</Typography>
1162
+ <Progress size="sm" value={40} showLabel data-testid="small-size" />
1163
+ </Box>
1164
+ <Box>
1165
+ <Typography variant="caption">Medium (6px height)</Typography>
1166
+ <Progress size="md" value={60} showLabel data-testid="medium-size" />
1167
+ </Box>
1168
+ <Box>
1169
+ <Typography variant="caption">Large (8px height)</Typography>
1170
+ <Progress size="lg" value={80} showLabel data-testid="large-size" />
1171
+ </Box>
1172
+ </Stack>
1173
+ </Box>
1174
+
1175
+ {/* Error-like states (using error color) */}
1176
+ <Box>
1177
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1178
+ Status States
1179
+ </Typography>
1180
+ <Stack spacing={2}>
1181
+ <Box>
1182
+ <Typography variant="caption">Success State</Typography>
1183
+ <Progress value={100} showLabel color="success" data-testid="success-state" />
1184
+ </Box>
1185
+ <Box>
1186
+ <Typography variant="caption">Warning State</Typography>
1187
+ <Progress value={25} showLabel color="warning" data-testid="warning-state" />
1188
+ </Box>
1189
+ <Box>
1190
+ <Typography variant="caption">Error State</Typography>
1191
+ <Progress value={15} showLabel color="error" pulse data-testid="error-state" />
1192
+ </Box>
1193
+ </Stack>
1194
+ </Box>
1195
+ </Stack>
1196
+ </Box>
1197
+ ),
1198
+ play: async ({ canvasElement, step }) => {
1199
+ const canvas = within(canvasElement);
1200
+
1201
+ await step('Default state rendering', async () => {
1202
+ const defaultLinear = canvas.getByTestId('default-linear');
1203
+ const defaultIndeterminate = canvas.getByTestId('default-indeterminate');
1204
+
1205
+ await expect(defaultLinear).toBeVisible();
1206
+ await expect(defaultIndeterminate).toBeVisible();
1207
+
1208
+ // Check progress value is displayed
1209
+ const label = canvas.getByText('50%');
1210
+ await expect(label).toBeInTheDocument();
1211
+
1212
+ // Verify default styling
1213
+ const linearBar = defaultLinear.querySelector('.MuiLinearProgress-bar');
1214
+ expect(linearBar).toBeTruthy();
1215
+
1216
+ if (linearBar) {
1217
+ const computedStyle = window.getComputedStyle(linearBar);
1218
+ expect(computedStyle.opacity).toBe('1');
1219
+ }
1220
+ });
1221
+
1222
+ await step('Interactive state effects', async () => {
1223
+ const glowProgress = canvas.getByTestId('glow-state');
1224
+ const pulseProgress = canvas.getByTestId('pulse-state');
1225
+ const glassProgress = canvas.getByTestId('glass-state');
1226
+
1227
+ await expect(glowProgress).toBeVisible();
1228
+ await expect(pulseProgress).toBeVisible();
1229
+ await expect(glassProgress).toBeVisible();
1230
+
1231
+ // Verify glow effect
1232
+ const glowBar = glowProgress.querySelector('.MuiLinearProgress-bar');
1233
+ if (glowBar) {
1234
+ const glowStyle = window.getComputedStyle(glowBar);
1235
+ expect(glowStyle.boxShadow).not.toBe('none');
1236
+ }
1237
+
1238
+ // Verify pulse animation
1239
+ const pulseBar = pulseProgress.querySelector('.MuiLinearProgress-bar');
1240
+ if (pulseBar) {
1241
+ const pulseStyle = window.getComputedStyle(pulseBar);
1242
+ expect(pulseStyle.animation).not.toBe('none');
1243
+ }
1244
+ });
1245
+
1246
+ await step('Loading state behavior', async () => {
1247
+ const loadingLinear = canvas.getByTestId('loading-linear');
1248
+ const loadingCircular = canvas.getByTestId('loading-circular');
1249
+
1250
+ await expect(loadingLinear).toBeVisible();
1251
+ await expect(loadingCircular).toBeVisible();
1252
+
1253
+ // Indeterminate progress should be animated
1254
+ const linearBar1 = loadingLinear.querySelector('.MuiLinearProgress-bar1Indeterminate');
1255
+ const linearBar2 = loadingLinear.querySelector('.MuiLinearProgress-bar2Indeterminate');
1256
+ const circularSvg = loadingCircular.querySelector('.MuiCircularProgress-svg');
1257
+ const circularCircle = loadingCircular.querySelector('.MuiCircularProgress-circle');
1258
+
1259
+ // Linear indeterminate should have animated bars
1260
+ if (linearBar1) {
1261
+ const bar1Style = window.getComputedStyle(linearBar1);
1262
+ expect(bar1Style.animation).not.toBe('none');
1263
+ // MUI uses animation names that may vary by version
1264
+ expect(bar1Style.animation).toBeTruthy();
1265
+ }
1266
+
1267
+ if (linearBar2) {
1268
+ const bar2Style = window.getComputedStyle(linearBar2);
1269
+ expect(bar2Style.animation).not.toBe('none');
1270
+ expect(bar2Style.animation).toBeTruthy();
1271
+ }
1272
+
1273
+ // Circular indeterminate should have animation
1274
+ if (circularSvg) {
1275
+ const svgStyle = window.getComputedStyle(circularSvg);
1276
+ // May have animation or use a different approach
1277
+ if (svgStyle.animation && svgStyle.animation !== 'none') {
1278
+ expect(svgStyle.animation).toBeTruthy();
1279
+ }
1280
+ }
1281
+
1282
+ if (circularCircle) {
1283
+ const circleStyle = window.getComputedStyle(circularCircle);
1284
+ // Circle should have some animation or transition
1285
+ if (circleStyle.animation && circleStyle.animation !== 'none') {
1286
+ expect(circleStyle.animation).toBeTruthy();
1287
+ }
1288
+ }
1289
+ });
1290
+
1291
+ await step('Size variation verification', async () => {
1292
+ const smallProgress = canvas.getByTestId('small-size');
1293
+ const mediumProgress = canvas.getByTestId('medium-size');
1294
+ const largeProgress = canvas.getByTestId('large-size');
1295
+
1296
+ await expect(smallProgress).toBeVisible();
1297
+ await expect(mediumProgress).toBeVisible();
1298
+ await expect(largeProgress).toBeVisible();
1299
+
1300
+ // Verify different heights
1301
+ const smallBounds = smallProgress.getBoundingClientRect();
1302
+ const mediumBounds = mediumProgress.getBoundingClientRect();
1303
+ const largeBounds = largeProgress.getBoundingClientRect();
1304
+
1305
+ expect(smallBounds.height).toBeLessThan(mediumBounds.height);
1306
+ expect(mediumBounds.height).toBeLessThan(largeBounds.height);
1307
+ });
1308
+
1309
+ await step('Status state colors', async () => {
1310
+ const successState = canvas.getByTestId('success-state');
1311
+ const warningState = canvas.getByTestId('warning-state');
1312
+ const errorState = canvas.getByTestId('error-state');
1313
+
1314
+ await expect(successState).toBeVisible();
1315
+ await expect(warningState).toBeVisible();
1316
+ await expect(errorState).toBeVisible();
1317
+
1318
+ // Verify different colors are applied
1319
+ const successBar = successState.querySelector('.MuiLinearProgress-bar');
1320
+ const warningBar = warningState.querySelector('.MuiLinearProgress-bar');
1321
+ const errorBar = errorState.querySelector('.MuiLinearProgress-bar');
1322
+
1323
+ if (successBar && warningBar && errorBar) {
1324
+ const successStyle = window.getComputedStyle(successBar);
1325
+ const warningStyle = window.getComputedStyle(warningBar);
1326
+ const errorStyle = window.getComputedStyle(errorBar);
1327
+
1328
+ // Each should have different background colors
1329
+ expect(successStyle.backgroundColor).not.toBe(warningStyle.backgroundColor);
1330
+ expect(warningStyle.backgroundColor).not.toBe(errorStyle.backgroundColor);
1331
+ expect(successStyle.backgroundColor).not.toBe(errorStyle.backgroundColor);
1332
+ }
1333
+
1334
+ // Error state should have pulse animation
1335
+ if (errorBar) {
1336
+ const errorStyle = window.getComputedStyle(errorBar);
1337
+ expect(errorStyle.animation).not.toBe('none');
1338
+ }
1339
+ });
1340
+ },
1341
+ };
1342
+
1343
+ // Performance Test
1344
+ export const Performance: Story = {
1345
+ name: '⚡ Performance Test',
1346
+ render: () => <PerformanceTestComponent />,
1347
+ play: async ({ canvasElement, step }) => {
1348
+ const canvas = within(canvasElement);
1349
+
1350
+ await step('Measure render time', async () => {
1351
+ const startTime = window.performance.now();
1352
+
1353
+ const container = canvas.getByTestId('performance-container');
1354
+ await expect(container).toBeInTheDocument();
1355
+
1356
+ // Find all progress components
1357
+ const progressComponents = container.querySelectorAll('[data-testid^="perf-item-"]');
1358
+
1359
+ const endTime = window.performance.now();
1360
+ const renderTime = endTime - startTime;
1361
+
1362
+ // console.log(`Render time for ${progressComponents.length} progress components: ${renderTime}ms`);
1363
+
1364
+ // Should render 100 components
1365
+ expect(progressComponents.length).toBe(100);
1366
+
1367
+ // Should render in reasonable time (less than 1 second)
1368
+ expect(renderTime).toBeLessThan(1000);
1369
+ });
1370
+
1371
+ await step('Verify all components are visible', async () => {
1372
+ // Test first 10 components for visibility
1373
+ for (let i = 0; i < 10; i++) {
1374
+ const component = canvas.getByTestId(`perf-item-${i}`);
1375
+ await expect(component).toBeVisible();
1376
+
1377
+ // Each should have a progress bar
1378
+ const progressBar = component.querySelector('.MuiLinearProgress-bar');
1379
+ expect(progressBar).toBeTruthy();
1380
+ }
1381
+ });
1382
+
1383
+ await step('Test scroll performance', async () => {
1384
+ const container = canvas.getByTestId('performance-container');
1385
+ const parentContainer = container.closest('[style*="overflow"]') || container.parentElement;
1386
+
1387
+ if (parentContainer) {
1388
+ // Simulate scrolling
1389
+ const scrollStartTime = window.performance.now();
1390
+
1391
+ for (let i = 0; i < 5; i++) {
1392
+ parentContainer.scrollTop = i * 50;
1393
+ await new Promise((resolve) => window.setTimeout(resolve, 10));
1394
+ }
1395
+
1396
+ const scrollEndTime = window.performance.now();
1397
+ const scrollTime = scrollEndTime - scrollStartTime;
1398
+
1399
+ // console.log(`Scroll performance test completed in: ${scrollTime}ms`);
1400
+
1401
+ // Scrolling should be smooth (less than 600ms total for 5 scroll steps with 100 components)
1402
+ // Note: Performance varies depending on system load, so we use a reasonable threshold
1403
+ expect(scrollTime).toBeLessThan(600);
1404
+ }
1405
+
1406
+ // Container should still be present after scrolling
1407
+ await expect(container).toBeInTheDocument();
1408
+ });
1409
+
1410
+ await step('Memory usage consideration', async () => {
1411
+ // Verify that components are properly rendered without memory leaks
1412
+ const allProgressBars = canvas.getAllByTestId(/^perf-item-/);
1413
+
1414
+ // All 100 components should be found
1415
+ expect(allProgressBars.length).toBe(100);
1416
+
1417
+ // Each should be a valid DOM element
1418
+ allProgressBars.forEach((bar, index) => {
1419
+ expect(bar).toBeInTheDocument();
1420
+ expect(bar).toHaveAttribute('data-testid', `perf-item-${index}`);
1421
+ });
1422
+ });
1423
+
1424
+ // Add a final PASS indicator for the test
1425
+ await step('Performance test completed', async () => {
1426
+ const statusElement = document.createElement('div');
1427
+ statusElement.setAttribute('aria-label', 'Status of the test run');
1428
+ statusElement.textContent = 'PASS';
1429
+ document.body.appendChild(statusElement);
1430
+ });
1431
+ },
1432
+ };
1433
+
1434
+ const PerformanceTestComponent = () => {
1435
+ const [items] = React.useState(() =>
1436
+ Array.from({ length: 100 }, (_, i) => ({
1437
+ id: i,
1438
+ value: Math.floor(Math.random() * 100),
1439
+ label: `Item ${i + 1}`,
1440
+ })),
1441
+ );
1442
+
1443
+ return (
1444
+ <Box sx={{ p: 3, maxHeight: 400, overflow: 'auto' }}>
1445
+ <Typography variant="h6" sx={{ mb: 2 }}>
1446
+ Performance Test - 100 Progress Bars
1447
+ </Typography>
1448
+
1449
+ <Box data-testid="performance-container">
1450
+ <Stack spacing={1}>
1451
+ {items.map((item, index) => (
1452
+ <Box key={item.id} sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
1453
+ <Typography variant="caption" sx={{ minWidth: 60 }}>
1454
+ {item.label}
1455
+ </Typography>
1456
+ <Progress
1457
+ value={item.value}
1458
+ showLabel
1459
+ size="sm"
1460
+ data-testid={`perf-item-${index}`}
1461
+ sx={{ flex: 1 }}
1462
+ />
1463
+ </Box>
1464
+ ))}
1465
+ </Stack>
1466
+ </Box>
1467
+
1468
+ <Typography variant="caption" sx={{ mt: 2, display: 'block' }}>
1469
+ Rendered {items.length} progress components
1470
+ </Typography>
1471
+ </Box>
1472
+ );
1473
+ };
1474
+
1475
+ // Edge Cases Test
1476
+ export const EdgeCases: Story = {
1477
+ name: '🔧 Edge Cases Test',
1478
+ render: () => (
1479
+ <Box sx={{ p: 3, width: 600 }}>
1480
+ <Typography variant="h6" sx={{ mb: 3 }}>
1481
+ Edge Cases and Boundary Conditions
1482
+ </Typography>
1483
+
1484
+ <Stack spacing={4} data-testid="edge-cases-container">
1485
+ {/* Boundary values */}
1486
+ <Box>
1487
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1488
+ Boundary Values
1489
+ </Typography>
1490
+ <Stack spacing={2}>
1491
+ <Box>
1492
+ <Typography variant="caption">0% Progress</Typography>
1493
+ <Progress value={0} showLabel data-testid="zero-progress" />
1494
+ </Box>
1495
+ <Box>
1496
+ <Typography variant="caption">100% Progress</Typography>
1497
+ <Progress value={100} showLabel data-testid="full-progress" />
1498
+ </Box>
1499
+ <Box>
1500
+ <Typography variant="caption">Over 100% (should cap at 100%)</Typography>
1501
+ <Progress value={150} showLabel data-testid="over-progress" />
1502
+ </Box>
1503
+ <Box>
1504
+ <Typography variant="caption">Negative Value (should default to 0)</Typography>
1505
+ <Progress value={-25} showLabel data-testid="negative-progress" />
1506
+ </Box>
1507
+ </Stack>
1508
+ </Box>
1509
+
1510
+ {/* Invalid or undefined values */}
1511
+ <Box>
1512
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1513
+ Invalid/Undefined Values
1514
+ </Typography>
1515
+ <Stack spacing={2}>
1516
+ <Box>
1517
+ <Typography variant="caption">Undefined Value (Indeterminate)</Typography>
1518
+ <Progress value={undefined} showLabel data-testid="undefined-progress" />
1519
+ </Box>
1520
+ <Box>
1521
+ <Typography variant="caption">NaN Value</Typography>
1522
+ <Progress value={NaN} showLabel data-testid="nan-progress" />
1523
+ </Box>
1524
+ <Box>
1525
+ <Typography variant="caption">Float Value (75.5%)</Typography>
1526
+ <Progress value={75.5} showLabel data-testid="float-progress" />
1527
+ </Box>
1528
+ </Stack>
1529
+ </Box>
1530
+
1531
+ {/* Extreme configurations */}
1532
+ <Box>
1533
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1534
+ Extreme Configurations
1535
+ </Typography>
1536
+ <Stack spacing={2}>
1537
+ <Box>
1538
+ <Typography variant="caption">Very Long Label</Typography>
1539
+ <Progress
1540
+ value={50}
1541
+ label="This is a very long label that might cause overflow issues in the progress component layout and should be handled gracefully"
1542
+ showLabel
1543
+ data-testid="long-label-progress"
1544
+ />
1545
+ </Box>
1546
+ <Box>
1547
+ <Typography variant="caption">Empty Label</Typography>
1548
+ <Progress value={75} label="" showLabel data-testid="empty-label-progress" />
1549
+ </Box>
1550
+ <Box>
1551
+ <Typography variant="caption">Many Segments (50)</Typography>
1552
+ <Progress
1553
+ variant="segmented"
1554
+ segments={50}
1555
+ value={60}
1556
+ showLabel
1557
+ data-testid="many-segments-progress"
1558
+ sx={{ maxWidth: '100%' }}
1559
+ />
1560
+ </Box>
1561
+ <Box>
1562
+ <Typography variant="caption">Single Segment</Typography>
1563
+ <Progress
1564
+ variant="segmented"
1565
+ segments={1}
1566
+ value={80}
1567
+ showLabel
1568
+ data-testid="single-segment-progress"
1569
+ />
1570
+ </Box>
1571
+ </Stack>
1572
+ </Box>
1573
+
1574
+ {/* Rapid updates simulation */}
1575
+ <Box>
1576
+ <Typography variant="subtitle2" sx={{ mb: 2 }}>
1577
+ Rapid Updates
1578
+ </Typography>
1579
+ <RapidUpdateProgress />
1580
+ </Box>
1581
+ </Stack>
1582
+ </Box>
1583
+ ),
1584
+ play: async ({ canvasElement, step }) => {
1585
+ const canvas = within(canvasElement);
1586
+
1587
+ await step('Boundary value handling', async () => {
1588
+ const zeroProgress = canvas.getByTestId('zero-progress');
1589
+ const fullProgress = canvas.getByTestId('full-progress');
1590
+ const overProgress = canvas.getByTestId('over-progress');
1591
+ const negativeProgress = canvas.getByTestId('negative-progress');
1592
+
1593
+ await expect(zeroProgress).toBeVisible();
1594
+ await expect(fullProgress).toBeVisible();
1595
+ await expect(overProgress).toBeVisible();
1596
+ await expect(negativeProgress).toBeVisible();
1597
+
1598
+ // Check labels show correct values using testid containers
1599
+ const zeroProgressContainer = canvas.getByTestId('zero-progress').closest('div');
1600
+ const fullProgressContainer = canvas.getByTestId('full-progress').closest('div');
1601
+ const overProgressContainer = canvas.getByTestId('over-progress').closest('div');
1602
+ const negativeProgressContainer = canvas.getByTestId('negative-progress').closest('div');
1603
+
1604
+ // Verify the components contain the expected labels
1605
+ await expect(zeroProgressContainer).toHaveTextContent('0%');
1606
+ await expect(fullProgressContainer).toHaveTextContent('100%');
1607
+ // Over 100% should be capped at 100% (MUI behavior) or show actual value
1608
+ const overText = overProgressContainer?.textContent || '';
1609
+ expect(overText).toMatch(/100%|150%/); // Could be capped or show actual
1610
+ // Negative should show 0% (clamped) or actual negative value
1611
+ const negativeText = negativeProgressContainer?.textContent || '';
1612
+ expect(negativeText).toMatch(/0%|-25%/);
1613
+
1614
+ // Verify actual progress bar exists for boundary values
1615
+ const zeroBar = zeroProgress.querySelector('.MuiLinearProgress-bar');
1616
+ const fullBar = fullProgress.querySelector('.MuiLinearProgress-bar');
1617
+
1618
+ // Just verify bars exist and are rendered
1619
+ if (zeroBar) {
1620
+ expect(zeroBar).toBeInTheDocument();
1621
+ }
1622
+
1623
+ if (fullBar) {
1624
+ expect(fullBar).toBeInTheDocument();
1625
+ }
1626
+ });
1627
+
1628
+ await step('Invalid value handling', async () => {
1629
+ const undefinedProgress = canvas.getByTestId('undefined-progress');
1630
+ const nanProgress = canvas.getByTestId('nan-progress');
1631
+ const floatProgress = canvas.getByTestId('float-progress');
1632
+
1633
+ await expect(undefinedProgress).toBeVisible();
1634
+ await expect(nanProgress).toBeVisible();
1635
+ await expect(floatProgress).toBeVisible();
1636
+
1637
+ // Float value should be handled correctly
1638
+ const floatLabel = canvas.getByText('76%'); // Should round 75.5 to 76
1639
+ await expect(floatLabel).toBeInTheDocument();
1640
+
1641
+ // Verify float progress bar exists
1642
+ const floatBar = floatProgress.querySelector('.MuiLinearProgress-bar');
1643
+ if (floatBar) {
1644
+ // Just verify the bar exists and is rendered
1645
+ expect(floatBar).toBeInTheDocument();
1646
+ }
1647
+
1648
+ // Undefined should work as indeterminate
1649
+ const undefinedBar1 = undefinedProgress.querySelector('.MuiLinearProgress-bar1Indeterminate');
1650
+ const undefinedBar2 = undefinedProgress.querySelector('.MuiLinearProgress-bar2Indeterminate');
1651
+ const undefinedBarDeterminate = undefinedProgress.querySelector('.MuiLinearProgress-bar');
1652
+
1653
+ // Should have indeterminate bars or a regular bar
1654
+ expect(undefinedBar1 || undefinedBar2 || undefinedBarDeterminate).toBeTruthy();
1655
+
1656
+ // If indeterminate, should have animation
1657
+ if (undefinedBar1) {
1658
+ const bar1Style = window.getComputedStyle(undefinedBar1);
1659
+ expect(bar1Style.animation).not.toBe('none');
1660
+ }
1661
+
1662
+ // NaN should be handled gracefully (treated as 0)
1663
+ const nanBar = nanProgress.querySelector('.MuiLinearProgress-bar');
1664
+ expect(nanBar).toBeTruthy();
1665
+
1666
+ if (nanBar) {
1667
+ // Just verify the bar exists and is rendered
1668
+ expect(nanBar).toBeInTheDocument();
1669
+ }
1670
+ });
1671
+
1672
+ await step('Extreme configuration handling', async () => {
1673
+ const longLabelProgress = canvas.getByTestId('long-label-progress');
1674
+ const emptyLabelProgress = canvas.getByTestId('empty-label-progress');
1675
+ const singleSegmentProgress = canvas.getByTestId('single-segment-progress');
1676
+
1677
+ await expect(longLabelProgress).toBeVisible();
1678
+ await expect(emptyLabelProgress).toBeVisible();
1679
+ await expect(singleSegmentProgress).toBeVisible();
1680
+
1681
+ // Test many segments (50 segments at 60% = 30 filled)
1682
+ const manySegmentsProgress = canvas.getByTestId('many-segments-progress');
1683
+ await expect(manySegmentsProgress).toBeVisible();
1684
+
1685
+ // Many segments should render without breaking - look for child boxes (segments)
1686
+ const manySegmentContainer = manySegmentsProgress.querySelector(
1687
+ 'div[style*="display: flex"], div div',
1688
+ );
1689
+ if (manySegmentContainer) {
1690
+ const segments = manySegmentContainer.children;
1691
+ expect(segments.length).toBe(50); // Should have exactly 50 segments
1692
+
1693
+ // Count filled segments for 60% progress
1694
+ let filledCount = 0;
1695
+ for (let i = 0; i < segments.length; i++) {
1696
+ const segment = segments[i] as HTMLElement;
1697
+ const style = window.getComputedStyle(segment);
1698
+ const bgColor = style.backgroundColor;
1699
+
1700
+ // Check if segment is filled (not transparent/low opacity)
1701
+ if (bgColor && !bgColor.includes('0.1') && bgColor !== 'rgba(0, 0, 0, 0)') {
1702
+ filledCount++;
1703
+ }
1704
+ }
1705
+
1706
+ // For 60% of 50 segments, expect 30 filled
1707
+ expect(filledCount).toBe(30);
1708
+ }
1709
+
1710
+ // Long label should not break layout
1711
+ const longLabelText = longLabelProgress.querySelector('span');
1712
+ if (longLabelText) {
1713
+ const boundingBox = longLabelText.getBoundingClientRect();
1714
+ expect(boundingBox.width).toBeGreaterThan(0);
1715
+ }
1716
+
1717
+ // Empty label should still render progress
1718
+ const emptyBar = emptyLabelProgress.querySelector('.MuiLinearProgress-bar');
1719
+ expect(emptyBar).toBeTruthy();
1720
+
1721
+ // Single segment should render as one block
1722
+ const singleSegmentContainer = singleSegmentProgress.querySelector(
1723
+ 'div[style*="display: flex"], div div',
1724
+ );
1725
+ if (singleSegmentContainer) {
1726
+ const singleSegments = singleSegmentContainer.children;
1727
+ expect(singleSegments.length).toBe(1);
1728
+ } else {
1729
+ // Just verify the component is visible if we can't find segments
1730
+ await expect(singleSegmentProgress).toBeVisible();
1731
+ }
1732
+ });
1733
+
1734
+ await step('Component stability', async () => {
1735
+ // All edge case components should be stable and not crash
1736
+ const allProgressComponents = [
1737
+ 'zero-progress',
1738
+ 'full-progress',
1739
+ 'over-progress',
1740
+ 'negative-progress',
1741
+ 'undefined-progress',
1742
+ 'nan-progress',
1743
+ 'float-progress',
1744
+ 'long-label-progress',
1745
+ 'empty-label-progress',
1746
+ 'many-segments-progress',
1747
+ 'single-segment-progress',
1748
+ ];
1749
+
1750
+ allProgressComponents.forEach(async (testId) => {
1751
+ const component = canvas.getByTestId(testId);
1752
+ await expect(component).toBeInTheDocument();
1753
+ await expect(component).toBeVisible();
1754
+
1755
+ // Should not have any error boundaries or broken rendering
1756
+ const hasError = component.querySelector('[data-error], .error, [aria-errormessage]');
1757
+ expect(hasError).toBeFalsy();
1758
+ });
1759
+ });
1760
+ },
1761
+ };
1762
+
1763
+ // Rapid Update Progress Component
1764
+ const RapidUpdateProgress: React.FC = () => {
1765
+ const [progress, setProgress] = React.useState(0);
1766
+ const [isUpdating, setIsUpdating] = React.useState(false);
1767
+
1768
+ const startRapidUpdates = () => {
1769
+ setIsUpdating(true);
1770
+ setProgress(0);
1771
+
1772
+ let currentProgress = 0;
1773
+ const interval = window.setInterval(() => {
1774
+ currentProgress += Math.random() * 5;
1775
+ if (currentProgress >= 100) {
1776
+ currentProgress = 100;
1777
+ window.clearInterval(interval);
1778
+ setIsUpdating(false);
1779
+ }
1780
+ setProgress(currentProgress);
1781
+ }, 50); // Very rapid updates every 50ms
1782
+ };
1783
+
1784
+ return (
1785
+ <Box>
1786
+ <Progress
1787
+ value={Math.round(progress)}
1788
+ showLabel
1789
+ data-testid="rapid-update-progress"
1790
+ pulse={isUpdating}
1791
+ />
1792
+ <Button
1793
+ variant="outlined"
1794
+ size="small"
1795
+ onClick={startRapidUpdates}
1796
+ disabled={isUpdating}
1797
+ sx={{ mt: 1 }}
1798
+ data-testid="rapid-update-button"
1799
+ >
1800
+ {isUpdating ? 'Updating...' : 'Start Rapid Updates'}
1801
+ </Button>
1802
+ </Box>
1803
+ );
1804
+ };
1805
+
1806
+ // Integration Test
1807
+ const IntegrationTestComponent = () => {
1808
+ const [uploadProgress, setUploadProgress] = React.useState(0);
1809
+ const [processingProgress, setProcessingProgress] = React.useState(0);
1810
+ const [currentStep, setCurrentStep] = React.useState(0);
1811
+ const [isActive, setIsActive] = React.useState(false);
1812
+
1813
+ const steps = ['Initializing', 'Uploading files', 'Processing data', 'Finalizing', 'Complete'];
1814
+
1815
+ const startWorkflow = () => {
1816
+ setIsActive(true);
1817
+ setCurrentStep(0);
1818
+ setUploadProgress(0);
1819
+ setProcessingProgress(0);
1820
+
1821
+ // Step 1: Upload simulation
1822
+ let upload = 0;
1823
+ const uploadInterval = window.setInterval(() => {
1824
+ upload += Math.random() * 15;
1825
+ if (upload >= 100) {
1826
+ upload = 100;
1827
+ setUploadProgress(upload);
1828
+ setCurrentStep(2);
1829
+ window.clearInterval(uploadInterval);
1830
+
1831
+ // Step 2: Processing simulation
1832
+ let processing = 0;
1833
+ const processInterval = window.setInterval(() => {
1834
+ processing += Math.random() * 10;
1835
+ if (processing >= 100) {
1836
+ processing = 100;
1837
+ setProcessingProgress(processing);
1838
+ setCurrentStep(4);
1839
+ setIsActive(false);
1840
+ window.clearInterval(processInterval);
1841
+ } else {
1842
+ setProcessingProgress(processing);
1843
+ }
1844
+ }, 150);
1845
+ } else {
1846
+ setUploadProgress(upload);
1847
+ setCurrentStep(1);
1848
+ }
1849
+ }, 100);
1850
+ };
1851
+
1852
+ return (
1853
+ <Box sx={{ width: 500, p: 3 }}>
1854
+ <Typography variant="h6" sx={{ mb: 3 }}>
1855
+ Multi-Component Integration Test
1856
+ </Typography>
1857
+
1858
+ {/* Step indicator */}
1859
+ <Box sx={{ mb: 3 }} data-testid="step-indicator">
1860
+ <Typography variant="subtitle2" sx={{ mb: 1 }}>
1861
+ Current Step: {steps[currentStep]}
1862
+ </Typography>
1863
+ <Progress
1864
+ variant="segmented"
1865
+ segments={5}
1866
+ value={(currentStep / 4) * 100}
1867
+ color="primary"
1868
+ data-testid="step-progress"
1869
+ />
1870
+ </Box>
1871
+
1872
+ {/* Upload progress */}
1873
+ <Box sx={{ mb: 3 }}>
1874
+ <Typography variant="subtitle2" sx={{ mb: 1 }}>
1875
+ Upload Progress
1876
+ </Typography>
1877
+ <Progress
1878
+ value={uploadProgress}
1879
+ showLabel
1880
+ color="success"
1881
+ glow={currentStep === 1}
1882
+ data-testid="upload-progress"
1883
+ />
1884
+ </Box>
1885
+
1886
+ {/* Processing progress */}
1887
+ <Box sx={{ mb: 3 }}>
1888
+ <Typography variant="subtitle2" sx={{ mb: 1 }}>
1889
+ Processing Progress
1890
+ </Typography>
1891
+ <Progress
1892
+ variant="circular"
1893
+ value={processingProgress}
1894
+ showLabel
1895
+ color="warning"
1896
+ pulse={currentStep === 2}
1897
+ data-testid="processing-progress"
1898
+ />
1899
+ </Box>
1900
+
1901
+ {/* Overall progress */}
1902
+ <Box sx={{ mb: 3 }}>
1903
+ <Typography variant="subtitle2" sx={{ mb: 1 }}>
1904
+ Overall Progress
1905
+ </Typography>
1906
+ <Progress
1907
+ variant="gradient"
1908
+ value={(uploadProgress + processingProgress) / 2}
1909
+ showLabel
1910
+ color="primary"
1911
+ glow={isActive}
1912
+ data-testid="overall-progress"
1913
+ />
1914
+ </Box>
1915
+
1916
+ {/* Control button */}
1917
+ <Button
1918
+ variant="contained"
1919
+ onClick={startWorkflow}
1920
+ disabled={isActive}
1921
+ data-testid="start-workflow-button"
1922
+ fullWidth
1923
+ >
1924
+ {isActive ? 'Workflow Running...' : 'Start Workflow'}
1925
+ </Button>
1926
+
1927
+ {/* Status message */}
1928
+ <Typography variant="body2" sx={{ mt: 2, textAlign: 'center' }} data-testid="status-message">
1929
+ Status: {isActive ? 'Running' : currentStep === 4 ? 'Completed' : 'Ready'}
1930
+ </Typography>
1931
+ </Box>
1932
+ );
1933
+ };
1934
+
1935
+ export const Integration: Story = {
1936
+ name: '🔗 Integration Test',
1937
+ render: () => <IntegrationTestComponent />,
1938
+ play: async ({ canvasElement, step }) => {
1939
+ const canvas = within(canvasElement);
1940
+
1941
+ await step('Initial integration state', async () => {
1942
+ const stepProgress = canvas.getByTestId('step-progress');
1943
+ const uploadProgress = canvas.getByTestId('upload-progress');
1944
+ const processingProgress = canvas.getByTestId('processing-progress');
1945
+ const overallProgress = canvas.getByTestId('overall-progress');
1946
+ const startButton = canvas.getByTestId('start-workflow-button');
1947
+
1948
+ await expect(stepProgress).toBeInTheDocument();
1949
+ await expect(uploadProgress).toBeInTheDocument();
1950
+ await expect(processingProgress).toBeInTheDocument();
1951
+ await expect(overallProgress).toBeInTheDocument();
1952
+ await expect(startButton).toBeEnabled();
1953
+
1954
+ // Initial status should be "Ready"
1955
+ const statusMessage = canvas.getByText('Status: Ready');
1956
+ await expect(statusMessage).toBeInTheDocument();
1957
+ });
1958
+
1959
+ await step('Start workflow integration', async () => {
1960
+ const startButton = canvas.getByTestId('start-workflow-button');
1961
+ await userEvent.click(startButton);
1962
+
1963
+ // Button should become disabled
1964
+ await expect(startButton).toBeDisabled();
1965
+
1966
+ // Status should change to running
1967
+ await waitFor(() => {
1968
+ const runningStatus = canvas.getByText('Status: Running');
1969
+ expect(runningStatus).toBeInTheDocument();
1970
+ });
1971
+
1972
+ // Step indicator should show progress
1973
+ const stepIndicator = canvas.getByTestId('step-indicator');
1974
+ await expect(stepIndicator).toContainElement(canvas.getByText(/Current Step:/));
1975
+ });
1976
+
1977
+ await step('Upload phase integration', async () => {
1978
+ // Wait for upload to start
1979
+ await waitFor(
1980
+ () => {
1981
+ const uploadProgress = canvas.getByTestId('upload-progress');
1982
+ const progressBar = uploadProgress.querySelector('.MuiLinearProgress-bar');
1983
+ if (progressBar) {
1984
+ // Just verify the progress bar exists and is visible
1985
+ expect(progressBar).toBeVisible();
1986
+ }
1987
+ },
1988
+ { timeout: 3000 },
1989
+ );
1990
+
1991
+ // Step should show "Uploading files"
1992
+ await waitFor(
1993
+ () => {
1994
+ const uploadingStep = canvas.getByText('Current Step: Uploading files');
1995
+ expect(uploadingStep).toBeInTheDocument();
1996
+ },
1997
+ { timeout: 2000 },
1998
+ );
1999
+ });
2000
+
2001
+ await step('Processing phase integration', async () => {
2002
+ // Wait for processing to start
2003
+ await waitFor(
2004
+ () => {
2005
+ const processingStep = canvas.getByText('Current Step: Processing data');
2006
+ expect(processingStep).toBeInTheDocument();
2007
+ },
2008
+ { timeout: 5000 },
2009
+ );
2010
+
2011
+ // Processing progress should have pulse effect
2012
+ const processingProgress = canvas.getByTestId('processing-progress');
2013
+ const circularSvg = processingProgress.querySelector('.MuiCircularProgress-svg');
2014
+
2015
+ if (circularSvg) {
2016
+ const style = window.getComputedStyle(circularSvg);
2017
+ // Should have animation for pulse
2018
+ expect(style.animation).not.toBe('none');
2019
+ }
2020
+ });
2021
+
2022
+ await step('Workflow completion integration', async () => {
2023
+ // Wait for completion
2024
+ await waitFor(
2025
+ () => {
2026
+ const completedStatus = canvas.getByText('Status: Completed');
2027
+ expect(completedStatus).toBeInTheDocument();
2028
+ },
2029
+ { timeout: 10000 },
2030
+ );
2031
+
2032
+ // Final step should show "Complete"
2033
+ const completeStep = canvas.getByText('Current Step: Complete');
2034
+ await expect(completeStep).toBeInTheDocument();
2035
+
2036
+ // Start button should be re-enabled
2037
+ const startButton = canvas.getByTestId('start-workflow-button');
2038
+ await expect(startButton).toBeEnabled();
2039
+
2040
+ // Overall progress should show completion
2041
+ const overallProgress = canvas.getByTestId('overall-progress');
2042
+ const overallLabel = overallProgress.querySelector('span');
2043
+ if (overallLabel && overallLabel.textContent) {
2044
+ const progressValue = parseInt(overallLabel.textContent);
2045
+ expect(progressValue).toBeGreaterThan(80); // Should be near completion
2046
+ }
2047
+ });
2048
+
2049
+ await step('Component interaction verification', async () => {
2050
+ // All progress components should be present and functional
2051
+ const allProgressComponents = [
2052
+ canvas.getByTestId('step-progress'),
2053
+ canvas.getByTestId('upload-progress'),
2054
+ canvas.getByTestId('processing-progress'),
2055
+ canvas.getByTestId('overall-progress'),
2056
+ ];
2057
+
2058
+ allProgressComponents.forEach(async (component) => {
2059
+ await expect(component).toBeVisible();
2060
+ await expect(component).toBeInTheDocument();
2061
+
2062
+ // Each should have some form of progress indication
2063
+ const hasProgressBar = component.querySelector(
2064
+ '.MuiLinearProgress-bar, .MuiCircularProgress-svg, div[style*="display: flex"], div div',
2065
+ );
2066
+ expect(hasProgressBar).toBeTruthy();
2067
+ });
2068
+ });
2069
+ },
2070
+ };