@12-apps/ui 1.0.0 → 1.3.1

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 (448) hide show
  1. package/components-catalog.md +14 -0
  2. package/package.json +42 -27
  3. package/src/__tests__/data-grid.test.tsx +125 -0
  4. package/src/__tests__/package-wiring.test.ts +12 -8
  5. package/src/__tests__/social-login-button.test.tsx +5 -5
  6. package/src/__tests__/viewport.test.ts +50 -0
  7. package/src/charts/index.ts +8 -0
  8. package/src/components/data-display/Alert/Alert.md +1 -1
  9. package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
  10. package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
  11. package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
  12. package/src/components/data-display/Alert/Alert.tsx +135 -328
  13. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
  14. package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
  15. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
  16. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
  17. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
  18. package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
  19. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
  20. package/src/components/data-display/Avatar/Avatar.tsx +154 -450
  21. package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
  22. package/src/components/data-display/Badge/Badge.animations.ts +67 -0
  23. package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
  24. package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
  25. package/src/components/data-display/Badge/Badge.styles.ts +261 -0
  26. package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
  27. package/src/components/data-display/Badge/Badge.tsx +151 -557
  28. package/src/components/data-display/Badge/Badge.variants.ts +106 -0
  29. package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
  30. package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
  31. package/src/components/data-display/Banner/Banner.styles.ts +120 -0
  32. package/src/components/data-display/Banner/Banner.tsx +179 -224
  33. package/src/components/data-display/Chart/Chart.md +48 -1
  34. package/src/components/data-display/Chart/Chart.tsx +82 -500
  35. package/src/components/data-display/Chart/Chart.types.ts +2 -0
  36. package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
  37. package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
  38. package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
  39. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
  40. package/src/components/data-display/Chart/SpecChart.tsx +53 -0
  41. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
  42. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
  43. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
  44. package/src/components/data-display/Chart/chart-format.ts +26 -0
  45. package/src/components/data-display/Chart/chart-internals.ts +148 -0
  46. package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
  47. package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
  48. package/src/components/data-display/Chart/chart-spec.ts +171 -0
  49. package/src/components/data-display/Chart/index.ts +30 -0
  50. package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
  51. package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
  52. package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
  53. package/src/components/data-display/Chip/Chip.tsx +31 -94
  54. package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
  55. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
  56. package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
  57. package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
  58. package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
  59. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
  60. package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
  61. package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
  62. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
  63. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
  64. package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
  65. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
  66. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
  67. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
  68. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
  69. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
  70. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
  71. package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
  72. package/src/components/data-display/DataViews/base-card.tsx +278 -0
  73. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
  74. package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
  75. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
  76. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
  77. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
  78. package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
  79. package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
  80. package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
  81. package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
  82. package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
  83. package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
  84. package/src/components/data-display/DataViews/data-views-types.ts +312 -0
  85. package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
  86. package/src/components/data-display/DataViews/index.ts +33 -0
  87. package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
  88. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
  89. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
  90. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
  91. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
  92. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
  93. package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
  94. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
  95. package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
  98. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
  99. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
  100. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
  101. package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
  102. package/src/components/data-display/LazyImage/LazyImage.md +1 -1
  103. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
  104. package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
  105. package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
  106. package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
  107. package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
  108. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
  109. package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
  110. package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
  111. package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
  112. package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
  113. package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
  114. package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
  115. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
  116. package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
  117. package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
  118. package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
  119. package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
  120. package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
  121. package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
  122. package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
  123. package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
  124. package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
  125. package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
  126. package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
  127. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
  128. package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
  129. package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
  130. package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
  131. package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
  132. package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
  133. package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
  134. package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
  135. package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
  136. package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
  137. package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
  138. package/src/components/data-display/Progress/Progress.styles.ts +101 -0
  139. package/src/components/data-display/Progress/Progress.tsx +185 -213
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
  142. package/src/components/data-display/StatCard/StatCard.md +117 -0
  143. package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
  144. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
  145. package/src/components/data-display/StatCard/StatCard.tsx +236 -0
  146. package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
  147. package/src/components/data-display/StatCard/index.ts +7 -0
  148. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
  149. package/src/components/data-display/Stepper/Stepper.tsx +1 -1
  150. package/src/components/data-display/Table/Table.helpers.ts +31 -0
  151. package/src/components/data-display/Table/Table.hooks.ts +161 -0
  152. package/src/components/data-display/Table/Table.stories.tsx +3 -1
  153. package/src/components/data-display/Table/Table.styles.ts +223 -0
  154. package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
  155. package/src/components/data-display/Table/Table.tsx +291 -748
  156. package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
  157. package/src/components/data-display/Table/TableParts.tsx +298 -0
  158. package/src/components/data-display/Table/TableStates.tsx +21 -0
  159. package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
  160. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
  161. package/src/components/data-display/Timeline/Timeline.tsx +23 -284
  162. package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
  163. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
  164. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
  165. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
  166. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
  167. package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
  168. package/src/components/data-display/index.ts +1 -0
  169. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
  170. package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
  171. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
  172. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
  173. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
  174. package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
  175. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
  176. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
  177. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
  178. package/src/components/feedback/ConfirmAction/index.ts +16 -0
  179. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
  180. package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
  181. package/src/components/feedback/Dialog/Dialog.tsx +26 -1
  182. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
  183. package/src/components/feedback/Modal/Modal.md +1 -1
  184. package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
  185. package/src/components/feedback/Sonner/Sonner.tsx +104 -288
  186. package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
  187. package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
  188. package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
  189. package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
  190. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
  191. package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
  192. package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
  193. package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
  194. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
  195. package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
  196. package/src/components/feedback/Toast/Toast.tsx +92 -81
  197. package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
  198. package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
  199. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
  200. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
  201. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
  202. package/src/components/feedback/index.ts +1 -0
  203. package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
  204. package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
  205. package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
  206. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
  207. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
  208. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
  209. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
  210. package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
  211. package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
  212. package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
  213. package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
  214. package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
  215. package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
  216. package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
  217. package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
  218. package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
  219. package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
  220. package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
  221. package/src/components/form/Button/Button.helpers.ts +36 -0
  222. package/src/components/form/Button/Button.stories.tsx +4 -1
  223. package/src/components/form/Button/Button.styles.ts +225 -0
  224. package/src/components/form/Button/Button.test.stories.tsx +25 -21
  225. package/src/components/form/Button/Button.tsx +45 -252
  226. package/src/components/form/Calendar/Calendar.dates.ts +100 -0
  227. package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
  228. package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
  229. package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
  230. package/src/components/form/Calendar/Calendar.selection.ts +156 -0
  231. package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
  232. package/src/components/form/Calendar/Calendar.tsx +63 -551
  233. package/src/components/form/Calendar/Calendar.types.ts +16 -0
  234. package/src/components/form/Calendar/CalendarDay.tsx +127 -0
  235. package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
  236. package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
  237. package/src/components/form/CepField/CepField.md +138 -0
  238. package/src/components/form/CepField/CepField.stories.tsx +138 -0
  239. package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
  240. package/src/components/form/CepField/CepField.tsx +211 -0
  241. package/src/components/form/CepField/CepField.types.ts +73 -0
  242. package/src/components/form/CepField/index.ts +2 -0
  243. package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
  244. package/src/components/form/Checkbox/Checkbox.tsx +19 -16
  245. package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
  246. package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
  247. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
  248. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
  249. package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
  250. package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
  251. package/src/components/form/Command/Command.hooks.ts +207 -0
  252. package/src/components/form/Command/Command.parts.tsx +58 -0
  253. package/src/components/form/Command/Command.styles.ts +83 -0
  254. package/src/components/form/Command/Command.tsx +61 -270
  255. package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
  256. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
  257. package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
  258. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
  259. package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
  260. package/src/components/form/HeaderButton/index.ts +2 -0
  261. package/src/components/form/Input/Input.stories.tsx +5 -1
  262. package/src/components/form/Input/Input.styles.ts +176 -0
  263. package/src/components/form/Input/Input.test.stories.tsx +30 -23
  264. package/src/components/form/Input/Input.tsx +71 -211
  265. package/src/components/form/Input/Input.types.ts +11 -0
  266. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
  267. package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
  268. package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
  269. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
  270. package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
  271. package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
  272. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
  273. package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
  274. package/src/components/form/PhoneInput/countries.ts +54 -0
  275. package/src/components/form/PhoneInput/phone.ts +47 -0
  276. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
  277. package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
  278. package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
  279. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
  280. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
  281. package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
  282. package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
  283. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
  284. package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
  285. package/src/components/form/Select/Select.test.stories.tsx +35 -27
  286. package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
  287. package/src/components/form/Switch/Switch.md +2 -1
  288. package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
  289. package/src/components/form/Textarea/Textarea.styles.ts +143 -0
  290. package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
  291. package/src/components/form/Textarea/Textarea.tsx +114 -535
  292. package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
  293. package/src/components/form/Toggle/Toggle.styles.ts +211 -0
  294. package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
  295. package/src/components/form/Toggle/Toggle.tsx +10 -185
  296. package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
  297. package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
  298. package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
  299. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
  300. package/src/components/form/UploadButton/UploadButton.tsx +76 -305
  301. package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
  302. package/src/components/form/index.ts +1 -0
  303. package/src/components/form/total-form/Fields/CepField.tsx +143 -0
  304. package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
  305. package/src/components/form/total-form/Fields/index.ts +4 -0
  306. package/src/components/form/total-form/FormContainer.tsx +3 -3
  307. package/src/components/form/total-form/SubmitButton.tsx +25 -2
  308. package/src/components/form/total-form/total-form.test.tsx +118 -1
  309. package/src/components/layout/Accordion/Accordion.md +1 -1
  310. package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
  311. package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
  312. package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
  313. package/src/components/layout/Accordion/Accordion.tsx +2 -75
  314. package/src/components/layout/Card/Card.helpers.ts +30 -0
  315. package/src/components/layout/Card/Card.stories.tsx +9 -11
  316. package/src/components/layout/Card/Card.styles.ts +182 -0
  317. package/src/components/layout/Card/Card.test.stories.tsx +46 -46
  318. package/src/components/layout/Card/Card.tsx +24 -241
  319. package/src/components/layout/CardGrid/CardGrid.md +96 -0
  320. package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
  321. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
  322. package/src/components/layout/CardGrid/index.ts +2 -0
  323. package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
  324. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
  325. package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
  326. package/src/components/layout/Container/Container.test.stories.tsx +11 -16
  327. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
  328. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
  329. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
  330. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
  331. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
  332. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
  333. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
  334. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
  335. package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
  336. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
  337. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
  338. package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
  339. package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
  340. package/src/components/layout/Dashboard/index.ts +2 -1
  341. package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
  342. package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
  343. package/src/components/layout/Drawer/Drawer.tsx +67 -53
  344. package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
  345. package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
  346. package/src/components/layout/Resizable/Resizable.tsx +38 -153
  347. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
  348. package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
  349. package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
  350. package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
  351. package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
  352. package/src/components/layout/Separator/Separator.styles.ts +128 -0
  353. package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
  354. package/src/components/layout/Separator/Separator.tsx +6 -132
  355. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
  356. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
  357. package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
  358. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
  359. package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
  360. package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
  361. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
  362. package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
  363. package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
  364. package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
  365. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
  366. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
  367. package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
  368. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
  369. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
  370. package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
  371. package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
  372. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
  373. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
  374. package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
  375. package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
  376. package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
  377. package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
  378. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
  379. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
  380. package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
  381. package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
  382. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
  383. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
  384. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
  385. package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
  386. package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
  387. package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
  388. package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
  389. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
  390. package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
  391. package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
  392. package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
  393. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
  394. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
  395. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
  396. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
  397. package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
  398. package/src/components/navigation/Pagination/Pagination.md +2 -1
  399. package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
  400. package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
  401. package/src/components/navigation/Pagination/Pagination.tsx +178 -313
  402. package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
  403. package/src/components/navigation/Tabs/Tabs.md +3 -1
  404. package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
  405. package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
  406. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
  407. package/src/components/navigation/Tabs/Tabs.tsx +192 -361
  408. package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
  409. package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
  410. package/src/components/typography/Code/Code.test.stories.tsx +5 -5
  411. package/src/components/typography/Code/Code.tsx +74 -49
  412. package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
  413. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
  414. package/src/components/typography/Text/Text.tsx +84 -77
  415. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
  416. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
  417. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
  418. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
  419. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
  420. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
  421. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
  422. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
  423. package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
  424. package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
  425. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
  426. package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
  427. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
  428. package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
  429. package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
  430. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
  431. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
  432. package/src/components/utility/InstallPrompt/index.ts +10 -0
  433. package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
  434. package/src/components/utility/Transition/Transition.helpers.ts +40 -0
  435. package/src/components/utility/Transition/Transition.tsx +17 -68
  436. package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
  437. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
  438. package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
  439. package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
  440. package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
  441. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
  442. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
  443. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
  444. package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
  445. package/src/components/utility/index.ts +1 -0
  446. package/src/mui/Link.ts +2 -0
  447. package/src/utils/index.ts +2 -1
  448. package/src/utils/viewport.ts +65 -0
@@ -1,25 +1,12 @@
1
- import { Circle as DotIcon, ExpandMore as ExpandIcon } from '@mui/icons-material';
2
1
  import {
3
2
  alpha,
4
3
  Box,
5
- Button,
6
- Card,
7
- CardContent,
8
- Chip,
9
- Collapse,
10
- Fade,
11
- IconButton,
12
- keyframes,
13
- Stack,
14
- styled,
15
- Typography,
16
- } from '@mui/material';
4
+ styled } from '@mui/material';
17
5
  import type { FC } from 'react';
18
6
  import React from 'react';
19
- import { TimelineItem, TimelineProps } from './Timeline.types';
7
+ import { TimelineRow } from './TimelineRow';
8
+ import type { TimelineProps } from './Timeline.types';
20
9
 
21
- const slideInAnimation = keyframes`from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); }`;
22
- const pulseAnimation = keyframes`0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.8; }`;
23
10
  // ---
24
11
 
25
12
  // --- Styled Components ---
@@ -34,140 +21,18 @@ const TimelineContainer = styled(Box)<{ orientation: 'vertical' | 'horizontal' }
34
21
  overflowX: 'auto',
35
22
  paddingBottom: theme.spacing(2),
36
23
  '&::-webkit-scrollbar': {
37
- height: 8,
38
- },
24
+ height: 8 },
39
25
  '&::-webkit-scrollbar-track': {
40
26
  background: alpha(theme.palette.action.disabled, 0.1),
41
- borderRadius: 4,
42
- },
27
+ borderRadius: 4 },
43
28
  '&::-webkit-scrollbar-thumb': {
44
29
  background: alpha(theme.palette.primary.main, 0.3),
45
30
  borderRadius: 4,
46
31
  '&:hover': {
47
- background: alpha(theme.palette.primary.main, 0.5),
48
- },
49
- },
50
- }),
51
- }),
32
+ background: alpha(theme.palette.primary.main, 0.5) } } }) }),
52
33
  );
53
34
 
54
- const TimelineItemContainer = styled(Box, {
55
- shouldForwardProp: (prop) => !['animated', 'alternating', 'index'].includes(prop as string),
56
- })<{
57
- animated: boolean;
58
- alternating: boolean;
59
- index: number;
60
- orientation: 'vertical' | 'horizontal';
61
- }>(({ theme, animated, alternating, index, orientation }) => ({
62
- display: 'flex',
63
- gap: theme.spacing(2),
64
- position: 'relative',
65
- ...(animated && {
66
- animation: `${slideInAnimation} 0.5s ease ${index * 0.1}s both`,
67
- }),
68
- ...(orientation === 'vertical' &&
69
- alternating && {
70
- flexDirection: index % 2 === 0 ? 'row' : 'row-reverse',
71
- textAlign: index % 2 === 0 ? 'left' : 'right',
72
- }),
73
- ...(orientation === 'horizontal' && {
74
- flexDirection: 'column',
75
- alignItems: 'center',
76
- minWidth: 280,
77
- }),
78
- }));
79
-
80
- const TimelineConnector = styled(Box, {
81
- shouldForwardProp: (prop) => !['isLast'].includes(prop as string),
82
- })<{
83
- orientation: 'vertical' | 'horizontal';
84
- isLast: boolean;
85
- }>(({ theme, orientation, isLast }) => ({
86
- position: 'absolute',
87
- background: `linear-gradient(180deg, ${theme.palette.primary.main} 0%, ${alpha(theme.palette.primary.main, 0.3)} 100%)`,
88
- ...(orientation === 'vertical'
89
- ? {
90
- width: 2,
91
- height: isLast ? 0 : 'calc(100% + 16px)',
92
- left: 19,
93
- top: 40,
94
- }
95
- : {
96
- height: 2,
97
- width: isLast ? 0 : '240px',
98
- top: 19,
99
- left: 40,
100
- }),
101
- }));
102
35
 
103
- const TimelineDot = styled(Box, {
104
- shouldForwardProp: (prop) => !['dotColor', 'hasIcon', 'animated'].includes(prop as string),
105
- })<{ dotColor?: string; hasIcon: boolean; animated: boolean }>(({ theme, dotColor, hasIcon, animated }) => ({
106
- width: 40,
107
- height: 40,
108
- borderRadius: '50%',
109
- display: 'flex',
110
- alignItems: 'center',
111
- justifyContent: 'center',
112
- background: dotColor
113
- ? `linear-gradient(135deg, ${dotColor} 0%, ${alpha(dotColor, 0.8)} 100%)`
114
- : `linear-gradient(135deg, ${theme.palette.primary.main} 0%, ${theme.palette.primary.light} 100%)`,
115
- boxShadow: `0 4px 12px ${alpha(dotColor || theme.palette.primary.main, 0.3)}`,
116
- border: `2px solid ${theme.palette.background.paper}`,
117
- zIndex: 1,
118
- flexShrink: 0,
119
- ...(animated && {
120
- animation: `${pulseAnimation} 2s ease infinite`,
121
- }),
122
- '& svg': {
123
- fontSize: hasIcon ? '1.2rem' : '0.8rem',
124
- color: theme.palette.background.paper,
125
- },
126
- }));
127
-
128
- const TimelineCard = styled(Card, {
129
- shouldForwardProp: (prop) => !['timelineVariant', 'isClickable'].includes(prop as string),
130
- })<{ timelineVariant: 'default' | 'compact' | 'detailed'; isClickable: boolean }>(
131
- ({ theme, timelineVariant, isClickable }) => ({
132
- flex: 1,
133
- background: `linear-gradient(135deg, ${alpha(theme.palette.background.paper, 0.9)} 0%, ${alpha(theme.palette.background.paper, 0.8)} 100%)`,
134
- backdropFilter: 'blur(10px)',
135
- WebkitBackdropFilter: 'blur(10px)',
136
- border: `1px solid ${alpha(theme.palette.divider, 0.18)}`,
137
- transition: theme.transitions.create(['transform', 'box-shadow']),
138
- ...(isClickable && {
139
- cursor: 'pointer',
140
- '&:hover': {
141
- transform: 'translateY(-2px)',
142
- boxShadow: theme.shadows[8],
143
- },
144
- }),
145
- ...(timelineVariant === 'compact' && {
146
- padding: theme.spacing(1.5),
147
- '& .MuiCardContent-root': {
148
- padding: 0,
149
- '&:last-child': {
150
- paddingBottom: 0,
151
- },
152
- },
153
- }),
154
- }),
155
- );
156
-
157
- const TimelineTimestamp = styled(Typography)(({ theme }) => ({
158
- color: theme.palette.text.secondary,
159
- fontSize: '0.75rem',
160
- fontWeight: 500,
161
- letterSpacing: '0.5px',
162
- textTransform: 'uppercase',
163
- }));
164
-
165
- const MetadataChip = styled(Chip)(({ theme }) => ({
166
- height: 24,
167
- fontSize: '0.75rem',
168
- background: alpha(theme.palette.primary.main, 0.08),
169
- border: `1px solid ${alpha(theme.palette.primary.main, 0.2)}`,
170
- }));
171
36
  // ---
172
37
 
173
38
  // Main component
@@ -178,8 +43,7 @@ export const Timeline: FC<TimelineProps> = ({
178
43
  showConnector = true,
179
44
  animated = true,
180
45
  alternating = false,
181
- onItemClick,
182
- }) => {
46
+ onItemClick }) => {
183
47
  const [expandedItems, setExpandedItems] = React.useState<Set<string>>(new Set());
184
48
 
185
49
  const handleExpandClick = (itemId: string, event: React.MouseEvent) => {
@@ -195,152 +59,27 @@ export const Timeline: FC<TimelineProps> = ({
195
59
  });
196
60
  };
197
61
 
198
- const handleItemClick = (item: TimelineItem) => {
199
- if (onItemClick) {
200
- onItemClick(item);
201
- }
202
- };
203
-
204
- const renderTimelineItem = (item: TimelineItem, index: number) => {
205
- const isExpanded = expandedItems.has(item.id);
206
- const isLast = index === items.length - 1;
207
-
208
- // Determine if item should be clickable:
209
- // - Has onItemClick callback, OR
210
- // - Has description and variant is not compact (so it can be expanded)
211
- const hasExpandableContent = item.description && variant !== 'compact';
212
- const isClickable = !!onItemClick || !!hasExpandableContent;
213
-
214
- return (
215
- <TimelineItemContainer
216
- key={item.id}
217
- animated={animated}
218
- alternating={alternating && orientation === 'vertical'}
219
- index={index}
220
- orientation={orientation}
221
- data-testid="timeline-item-container"
222
- >
223
- <Box sx={{ position: 'relative' }}>
224
- <TimelineDot
225
- dotColor={item.color}
226
- hasIcon={!!item.icon}
227
- animated={animated}
228
- data-testid="timeline-dot"
229
- >
230
- {item.icon ? (
231
- <Box data-testid="item-icon">{item.icon}</Box>
232
- ) : (
233
- <DotIcon data-testid="item-icon-default" />
234
- )}
235
- </TimelineDot>
236
- {showConnector && !isLast && (
237
- <TimelineConnector
238
- orientation={orientation}
239
- isLast={isLast}
240
- data-testid="timeline-connector"
241
- />
242
- )}
243
- </Box>
244
-
245
- <TimelineCard
246
- timelineVariant={variant}
247
- isClickable={isClickable}
248
- onClick={isClickable ? () => handleItemClick(item) : undefined}
249
- role="article"
250
- aria-label={`Timeline item: ${item.title}`}
251
- data-testid="timeline-card"
252
- >
253
- <CardContent>
254
- <Stack spacing={1}>
255
- <Box
256
- sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}
257
- >
258
- <Box sx={{ flex: 1 }}>
259
- <TimelineTimestamp data-testid="timeline-timestamp">
260
- {item.timestamp}
261
- </TimelineTimestamp>
262
- <Typography
263
- variant={variant === 'compact' ? 'body2' : 'h6'}
264
- fontWeight={variant === 'compact' ? 500 : 600}
265
- sx={{ mt: 0.5 }}
266
- >
267
- {item.title}
268
- </Typography>
269
- </Box>
270
- {item.description && variant !== 'compact' && (
271
- <IconButton
272
- size="small"
273
- onClick={(e) => handleExpandClick(item.id, e)}
274
- aria-label={isExpanded ? 'Collapse item details' : 'Expand item details'}
275
- sx={{
276
- transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',
277
- transition: 'transform 0.3s ease',
278
- }}
279
- >
280
- <ExpandIcon />
281
- </IconButton>
282
- )}
283
- </Box>
284
-
285
- {variant === 'compact' && item.description && (
286
- <Typography variant="caption" color="text.secondary">
287
- {item.description}
288
- </Typography>
289
- )}
290
-
291
- {variant !== 'compact' && (
292
- <Collapse in={isExpanded || variant === 'detailed'}>
293
- <Fade in={isExpanded || variant === 'detailed'}>
294
- <Stack spacing={1.5} sx={{ mt: 1 }}>
295
- {item.description && (
296
- <Typography variant="body2" color="text.secondary">
297
- {item.description}
298
- </Typography>
299
- )}
300
-
301
- {item.metadata && (
302
- <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
303
- {Object.entries(item.metadata).map(([key, value]) => (
304
- <MetadataChip key={key} label={`${key}: ${value}`} size="small" />
305
- ))}
306
- </Box>
307
- )}
308
-
309
- {item.action && (
310
- <Box>
311
- <Button
312
- size="small"
313
- variant="contained"
314
- onClick={(e) => {
315
- e.stopPropagation();
316
- item.action!.onClick();
317
- }}
318
- sx={{
319
- background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
320
- color: 'white',
321
- }}
322
- >
323
- {item.action.label}
324
- </Button>
325
- </Box>
326
- )}
327
- </Stack>
328
- </Fade>
329
- </Collapse>
330
- )}
331
- </Stack>
332
- </CardContent>
333
- </TimelineCard>
334
- </TimelineItemContainer>
335
- );
336
- };
337
-
338
62
  return (
339
63
  <TimelineContainer
340
64
  orientation={orientation}
341
65
  data-testid="timeline-container"
342
66
  >
343
- {items.map((item, index) => renderTimelineItem(item, index))}
67
+ {items.map((item, index) => (
68
+ <TimelineRow
69
+ key={item.id}
70
+ item={item}
71
+ index={index}
72
+ isLast={index === items.length - 1}
73
+ variant={variant}
74
+ orientation={orientation}
75
+ showConnector={showConnector}
76
+ animated={animated}
77
+ alternating={alternating}
78
+ isExpanded={expandedItems.has(item.id)}
79
+ onItemClick={onItemClick}
80
+ onExpandClick={handleExpandClick}
81
+ />
82
+ ))}
344
83
  </TimelineContainer>
345
84
  );
346
85
  };
@@ -0,0 +1,346 @@
1
+ import DotIcon from '@mui/icons-material/Circle';
2
+ import ExpandIcon from '@mui/icons-material/ExpandMore';
3
+ import {
4
+ Box,
5
+ Button,
6
+ Card,
7
+ CardContent,
8
+ Chip,
9
+ Collapse,
10
+ Fade,
11
+ IconButton,
12
+ Stack,
13
+ Typography,
14
+ } from '@mui/material';
15
+ import { alpha, keyframes,styled } from '@mui/material/styles';
16
+ import React from 'react';
17
+
18
+ import type { TimelineItem, TimelineProps } from './Timeline.types';
19
+
20
+ const slideInAnimation = keyframes`from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); }`;
21
+ const pulseAnimation = keyframes`0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.8; }`;
22
+
23
+ const TimelineItemContainer = styled(Box, {
24
+ shouldForwardProp: (prop) => !['animated', 'alternating', 'index'].includes(prop as string),
25
+ })<{
26
+ animated: boolean;
27
+ alternating: boolean;
28
+ index: number;
29
+ orientation: 'vertical' | 'horizontal';
30
+ }>(({ theme, animated, alternating, index, orientation }) => ({
31
+ display: 'flex',
32
+ gap: theme.spacing(2),
33
+ position: 'relative',
34
+ ...(animated && {
35
+ animation: `${slideInAnimation} 0.5s ease ${index * 0.1}s both`,
36
+ }),
37
+ ...(orientation === 'vertical' &&
38
+ alternating && {
39
+ flexDirection: index % 2 === 0 ? 'row' : 'row-reverse',
40
+ textAlign: index % 2 === 0 ? 'left' : 'right',
41
+ }),
42
+ ...(orientation === 'horizontal' && {
43
+ flexDirection: 'column',
44
+ alignItems: 'center',
45
+ minWidth: 280,
46
+ }),
47
+ }));
48
+
49
+ const TimelineConnector = styled(Box, {
50
+ shouldForwardProp: (prop) => !['isLast'].includes(prop as string),
51
+ })<{
52
+ orientation: 'vertical' | 'horizontal';
53
+ isLast: boolean;
54
+ }>(({ theme, orientation, isLast }) => ({
55
+ position: 'absolute',
56
+ background: `linear-gradient(180deg, ${theme.palette.primary.main} 0%, ${alpha(theme.palette.primary.main, 0.3)} 100%)`,
57
+ ...(orientation === 'vertical'
58
+ ? {
59
+ width: 2,
60
+ height: isLast ? 0 : 'calc(100% + 16px)',
61
+ left: 19,
62
+ top: 40,
63
+ }
64
+ : {
65
+ height: 2,
66
+ width: isLast ? 0 : '240px',
67
+ top: 19,
68
+ left: 40,
69
+ }),
70
+ }));
71
+
72
+ const TimelineDot = styled(Box, {
73
+ shouldForwardProp: (prop) => !['dotColor', 'hasIcon', 'animated'].includes(prop as string),
74
+ })<{ dotColor?: string; hasIcon: boolean; animated: boolean }>(({ theme, dotColor, hasIcon, animated }) => ({
75
+ width: 40,
76
+ height: 40,
77
+ borderRadius: '50%',
78
+ display: 'flex',
79
+ alignItems: 'center',
80
+ justifyContent: 'center',
81
+ background: dotColor
82
+ ? `linear-gradient(135deg, ${dotColor} 0%, ${alpha(dotColor, 0.8)} 100%)`
83
+ : `linear-gradient(135deg, ${theme.palette.primary.main} 0%, ${theme.palette.primary.light} 100%)`,
84
+ boxShadow: `0 4px 12px ${alpha(dotColor || theme.palette.primary.main, 0.3)}`,
85
+ border: `2px solid ${theme.palette.background.paper}`,
86
+ zIndex: 1,
87
+ flexShrink: 0,
88
+ ...(animated && {
89
+ animation: `${pulseAnimation} 2s ease infinite`,
90
+ }),
91
+ '& svg': {
92
+ fontSize: hasIcon ? '1.2rem' : '0.8rem',
93
+ color: theme.palette.background.paper,
94
+ },
95
+ }));
96
+
97
+ const TimelineCard = styled(Card, {
98
+ shouldForwardProp: (prop) => !['timelineVariant', 'isClickable'].includes(prop as string),
99
+ })<{ timelineVariant: 'default' | 'compact' | 'detailed'; isClickable: boolean }>(
100
+ ({ theme, timelineVariant, isClickable }) => ({
101
+ flex: 1,
102
+ background: `linear-gradient(135deg, ${alpha(theme.palette.background.paper, 0.9)} 0%, ${alpha(theme.palette.background.paper, 0.8)} 100%)`,
103
+ backdropFilter: 'blur(10px)',
104
+ WebkitBackdropFilter: 'blur(10px)',
105
+ border: `1px solid ${alpha(theme.palette.divider, 0.18)}`,
106
+ transition: theme.transitions.create(['transform', 'box-shadow']),
107
+ ...(isClickable && {
108
+ cursor: 'pointer',
109
+ '&:hover': {
110
+ transform: 'translateY(-2px)',
111
+ boxShadow: theme.shadows[8],
112
+ },
113
+ }),
114
+ ...(timelineVariant === 'compact' && {
115
+ padding: theme.spacing(1.5),
116
+ '& .MuiCardContent-root': {
117
+ padding: 0,
118
+ '&:last-child': {
119
+ paddingBottom: 0,
120
+ },
121
+ },
122
+ }),
123
+ }),
124
+ );
125
+
126
+ const TimelineTimestamp = styled(Typography)(({ theme }) => ({
127
+ color: theme.palette.text.secondary,
128
+ fontSize: '0.75rem',
129
+ fontWeight: 500,
130
+ letterSpacing: '0.5px',
131
+ textTransform: 'uppercase',
132
+ }));
133
+
134
+ const MetadataChip = styled(Chip)(({ theme }) => ({
135
+ height: 24,
136
+ fontSize: '0.75rem',
137
+ background: alpha(theme.palette.primary.main, 0.08),
138
+ border: `1px solid ${alpha(theme.palette.primary.main, 0.2)}`,
139
+ }));
140
+
141
+ // Description, metadata chips and the action button, revealed on expand — or
142
+ // always, in the detailed variant.
143
+ const TimelineDetails: React.FC<{
144
+ item: TimelineItem;
145
+ isExpanded: boolean;
146
+ variant: NonNullable<TimelineProps['variant']>;
147
+ }> = ({ item, isExpanded, variant }) => {
148
+ const open = isExpanded || variant === 'detailed';
149
+
150
+ return (
151
+ <Collapse in={open}>
152
+ <Fade in={open}>
153
+ <Stack spacing={1.5} sx={{ mt: 1 }}>
154
+ {item.description && (
155
+ <Typography variant="body2" color="text.secondary">
156
+ {item.description}
157
+ </Typography>
158
+ )}
159
+
160
+ {item.metadata && (
161
+ <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
162
+ {Object.entries(item.metadata).map(([key, value]) => (
163
+ <MetadataChip key={key} label={`${key}: ${value}`} size="small" />
164
+ ))}
165
+ </Box>
166
+ )}
167
+
168
+ {item.action && (
169
+ <Box>
170
+ <Button
171
+ size="small"
172
+ variant="contained"
173
+ onClick={(e) => {
174
+ e.stopPropagation();
175
+ item.action!.onClick();
176
+ }}
177
+ sx={{
178
+ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
179
+ color: 'white',
180
+ }}
181
+ >
182
+ {item.action.label}
183
+ </Button>
184
+ </Box>
185
+ )}
186
+ </Stack>
187
+ </Fade>
188
+ </Collapse>
189
+ );
190
+ };
191
+
192
+ // Timestamp, title and the expand toggle.
193
+ const TimelineCardHeader: React.FC<{
194
+ item: TimelineItem;
195
+ variant: NonNullable<TimelineProps['variant']>;
196
+ isExpanded: boolean;
197
+ onExpandClick: (itemId: string, event: React.MouseEvent) => void;
198
+ }> = ({ item, variant, isExpanded, onExpandClick }) => (
199
+ <Box
200
+ sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}
201
+ >
202
+ <Box sx={{ flex: 1 }}>
203
+ <TimelineTimestamp data-testid="timeline-timestamp">
204
+ {item.timestamp}
205
+ </TimelineTimestamp>
206
+ <Typography
207
+ variant={variant === 'compact' ? 'body2' : 'h6'}
208
+ fontWeight={variant === 'compact' ? 500 : 600}
209
+ sx={{ mt: 0.5 }}
210
+ >
211
+ {item.title}
212
+ </Typography>
213
+ </Box>
214
+ {item.description && variant !== 'compact' && (
215
+ <IconButton
216
+ size="small"
217
+ onClick={(e) => onExpandClick(item.id, e)}
218
+ aria-label={isExpanded ? 'Collapse item details' : 'Expand item details'}
219
+ sx={{
220
+ transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',
221
+ transition: 'transform 0.3s ease',
222
+ }}
223
+ >
224
+ <ExpandIcon />
225
+ </IconButton>
226
+ )}
227
+ </Box>
228
+ );
229
+
230
+ // The card beside the rail: timestamp, title, expand toggle and the collapsible
231
+ // detail body.
232
+ const TimelineRowCard: React.FC<{
233
+ item: TimelineItem;
234
+ variant: NonNullable<TimelineProps['variant']>;
235
+ isClickable: boolean;
236
+ isExpanded: boolean;
237
+ onItemClick?: (item: TimelineItem) => void;
238
+ onExpandClick: (itemId: string, event: React.MouseEvent) => void;
239
+ }> = ({ item, variant, isClickable, isExpanded, onItemClick, onExpandClick }) => (
240
+ <TimelineCard
241
+ timelineVariant={variant}
242
+ isClickable={isClickable}
243
+ onClick={isClickable ? () => onItemClick?.(item) : undefined}
244
+ role="article"
245
+ aria-label={`Timeline item: ${item.title}`}
246
+ data-testid="timeline-card"
247
+ >
248
+ <CardContent>
249
+ <Stack spacing={1}>
250
+ <TimelineCardHeader
251
+ item={item}
252
+ variant={variant}
253
+ isExpanded={isExpanded}
254
+ onExpandClick={onExpandClick}
255
+ />
256
+
257
+ {variant === 'compact' && item.description && (
258
+ <Typography variant="caption" color="text.secondary">
259
+ {item.description}
260
+ </Typography>
261
+ )}
262
+
263
+ {variant !== 'compact' && (
264
+ <TimelineDetails item={item} isExpanded={isExpanded} variant={variant} />
265
+ )}
266
+ </Stack>
267
+ </CardContent>
268
+ </TimelineCard>
269
+ );
270
+
271
+ // One entry: the dot and connector on the rail, and the card beside it.
272
+ export const TimelineRow: React.FC<{
273
+ item: TimelineItem;
274
+ index: number;
275
+ isLast: boolean;
276
+ variant: NonNullable<TimelineProps['variant']>;
277
+ orientation: 'vertical' | 'horizontal';
278
+ showConnector: boolean;
279
+ animated: boolean;
280
+ alternating: boolean;
281
+ isExpanded: boolean;
282
+ onItemClick?: (item: TimelineItem) => void;
283
+ onExpandClick: (itemId: string, event: React.MouseEvent) => void;
284
+ }> = ({
285
+ item,
286
+ index,
287
+ isLast,
288
+ variant,
289
+ orientation,
290
+ showConnector,
291
+ animated,
292
+ alternating,
293
+ isExpanded,
294
+ onItemClick,
295
+ onExpandClick,
296
+ }) => {
297
+
298
+
299
+ // Determine if item should be clickable:
300
+ // - Has onItemClick callback, OR
301
+ // - Has description and variant is not compact (so it can be expanded)
302
+ const hasExpandableContent = item.description && variant !== 'compact';
303
+ const isClickable = !!onItemClick || !!hasExpandableContent;
304
+
305
+ return (
306
+ <TimelineItemContainer
307
+ key={item.id}
308
+ animated={animated}
309
+ alternating={alternating && orientation === 'vertical'}
310
+ index={index}
311
+ orientation={orientation}
312
+ data-testid="timeline-item-container"
313
+ >
314
+ <Box sx={{ position: 'relative' }}>
315
+ <TimelineDot
316
+ dotColor={item.color}
317
+ hasIcon={!!item.icon}
318
+ animated={animated}
319
+ data-testid="timeline-dot"
320
+ >
321
+ {item.icon ? (
322
+ <Box data-testid="item-icon">{item.icon}</Box>
323
+ ) : (
324
+ <DotIcon data-testid="item-icon-default" />
325
+ )}
326
+ </TimelineDot>
327
+ {showConnector && !isLast && (
328
+ <TimelineConnector
329
+ orientation={orientation}
330
+ isLast={isLast}
331
+ data-testid="timeline-connector"
332
+ />
333
+ )}
334
+ </Box>
335
+
336
+ <TimelineRowCard
337
+ item={item}
338
+ variant={variant}
339
+ isClickable={isClickable}
340
+ isExpanded={isExpanded}
341
+ onItemClick={onItemClick}
342
+ onExpandClick={onExpandClick}
343
+ />
344
+ </TimelineItemContainer>
345
+ );
346
+ };