@12-apps/ui 1.0.0 → 1.3.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 (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,40 +1,23 @@
1
- import { KeyboardArrowUp } from '@mui/icons-material';
1
+ import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp';
2
2
  import { alpha, Box, CircularProgress,Fab, useTheme, Zoom } from '@mui/material';
3
- import React, { useCallback,useEffect, useRef, useState } from 'react';
3
+ import type { FC } from 'react';
4
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
4
5
 
6
+ import type { ResolvedScrollAreaProps } from './ScrollArea.helpers';
7
+ import { resolveScrollAreaProps } from './ScrollArea.helpers';
5
8
  import type { ScrollAreaProps } from './ScrollArea.types';
6
-
7
- export const ScrollArea: React.FC<ScrollAreaProps> = ({
8
- children,
9
- width = '100%',
10
- height = '100%',
11
- maxHeight,
12
- maxWidth,
13
- orientation = 'vertical',
14
- scrollbarSize = 'medium',
15
- autoHide = true,
16
- autoHideDelay = 1000,
17
- smoothScroll = true,
18
- variant = 'default',
19
- onScroll,
20
- scrollToTopButton = false,
21
- scrollToTopThreshold = 100,
22
- scrollbarColor,
23
- scrollbarTrackColor,
24
- contentPadding = 0,
25
- alwaysShowScrollbar = false,
26
- disabled = false,
27
- loading = false,
28
- emptyContent,
29
- testId = 'scroll-area',
30
- scrollRef: externalScrollRef,
31
- onResize,
32
- sx,
33
- ...props
9
+ import { ScrollAreaContent } from './ScrollAreaContent';
10
+ import { ScrollViewport } from './ScrollViewport';
11
+
12
+ // Owns the scroll container ref (merging in any ref the caller passed) and
13
+ // reports size changes through a ResizeObserver.
14
+ const useObservedScrollRef = ({
15
+ externalScrollRef,
16
+ onResize }: {
17
+ externalScrollRef?: React.Ref<HTMLDivElement>;
18
+ onResize?: ScrollAreaProps['onResize'];
34
19
  }) => {
35
- const theme = useTheme();
36
20
  const internalScrollRef = useRef<HTMLDivElement>(null);
37
- const [showScrollToTop, setShowScrollToTop] = useState(false);
38
21
  const [containerDimensions, setContainerDimensions] = useState({ width: 0, height: 0 });
39
22
 
40
23
  // Track container dimensions with ResizeObserver
@@ -68,381 +51,207 @@ export const ScrollArea: React.FC<ScrollAreaProps> = ({
68
51
  );
69
52
 
70
53
  // Use internal ref for accessing the element
71
- const scrollRef = internalScrollRef;
72
- const [isScrolling, setIsScrolling] = useState(false);
73
- const scrollTimeoutRef = useRef<number | undefined>(undefined);
74
54
 
75
- // Get scrollbar size in pixels
76
- const getScrollbarSize = () => {
77
- switch (scrollbarSize) {
78
- case 'thin':
79
- return 8;
80
- case 'thick':
81
- return 16;
82
- default:
83
- return 12;
84
- }
85
- };
55
+ return { scrollRef: internalScrollRef, setScrollRef, containerDimensions };
56
+ };
57
+
58
+ // Scroll position, the transient "is scrolling" flag that drives auto-hide, the
59
+ // observed container size, and the scroll-to-top affordance.
60
+ // The scrollbar shows while scrolling and hides once movement stops.
61
+ const useAutoHide = ({
62
+ autoHide,
63
+ alwaysShowScrollbar,
64
+ autoHideDelay }: {
65
+ autoHide: boolean;
66
+ alwaysShowScrollbar: boolean;
67
+ autoHideDelay: number;
68
+ }) => {
69
+ const [isScrolling, setIsScrolling] = useState(false);
70
+ const timeoutRef = useRef<number | undefined>(undefined);
86
71
 
87
- // Get scrollbar colors
88
- const getScrollbarColors = () => {
89
- const defaultScrollbarColor =
90
- variant === 'glass'
91
- ? alpha(theme.palette.primary.main, 0.5)
92
- : theme.palette.mode === 'dark'
93
- ? theme.palette.grey[600]
94
- : theme.palette.grey[400];
72
+ const noteScroll = useCallback(() => {
73
+ if (!autoHide || alwaysShowScrollbar) return;
95
74
 
96
- const defaultTrackColor =
97
- variant === 'glass'
98
- ? alpha(theme.palette.background.paper, 0.1)
99
- : theme.palette.mode === 'dark'
100
- ? theme.palette.grey[900]
101
- : theme.palette.grey[200];
75
+ setIsScrolling(true);
76
+ window.clearTimeout(timeoutRef.current);
77
+ timeoutRef.current = window.setTimeout(() => setIsScrolling(false), autoHideDelay);
78
+ }, [autoHide, alwaysShowScrollbar, autoHideDelay]);
102
79
 
103
- return {
104
- scrollbar: scrollbarColor || defaultScrollbarColor,
105
- track: scrollbarTrackColor || defaultTrackColor,
106
- };
107
- };
80
+ useEffect(() => () => window.clearTimeout(timeoutRef.current), []);
108
81
 
109
- // Get overflow style based on orientation
110
- const getOverflowStyle = () => {
111
- if (disabled) return { overflow: 'hidden' as const };
82
+ return { isScrolling, noteScroll };
83
+ };
112
84
 
113
- switch (orientation) {
114
- case 'horizontal':
115
- return {
116
- overflow: 'hidden' as const,
117
- overflowX: 'auto' as const,
118
- overflowY: 'hidden' as const,
119
- };
120
- case 'both':
121
- return { overflow: 'auto' as const };
122
- default:
123
- return {
124
- overflow: 'hidden' as const,
125
- overflowY: 'auto' as const,
126
- overflowX: 'hidden' as const,
127
- };
128
- }
129
- };
85
+ const useScrollArea = (
86
+ props: ResolvedScrollAreaProps & { externalScrollRef?: React.Ref<HTMLDivElement> },
87
+ ) => {
88
+ const {
89
+ disabled,
90
+ onScroll,
91
+ onResize,
92
+ externalScrollRef,
93
+ autoHide,
94
+ autoHideDelay,
95
+ alwaysShowScrollbar,
96
+ scrollToTopButton,
97
+ scrollToTopThreshold,
98
+ smoothScroll } = props;
99
+
100
+ const { scrollRef, setScrollRef, containerDimensions } = useObservedScrollRef({
101
+ externalScrollRef,
102
+ onResize });
103
+ const [showScrollToTop, setShowScrollToTop] = useState(false);
104
+ const { isScrolling, noteScroll } = useAutoHide({
105
+ autoHide,
106
+ alwaysShowScrollbar,
107
+ autoHideDelay });
130
108
 
131
- // Handle scroll event
132
109
  const handleScroll = useCallback(
133
110
  (event: React.UIEvent<HTMLDivElement>) => {
134
111
  if (disabled) return;
135
112
 
136
- // Handle auto-hide behavior
137
- if (autoHide && !alwaysShowScrollbar) {
138
- setIsScrolling(true);
139
- if (scrollTimeoutRef.current) {
140
- window.clearTimeout(scrollTimeoutRef.current);
141
- }
142
- scrollTimeoutRef.current = window.setTimeout(() => {
143
- setIsScrolling(false);
144
- }, autoHideDelay);
145
- }
113
+ noteScroll();
146
114
 
147
- // Check if should show scroll to top button
148
115
  if (scrollToTopButton && scrollRef.current) {
149
- const scrollTop = scrollRef.current.scrollTop;
150
- setShowScrollToTop(scrollTop > scrollToTopThreshold);
116
+ setShowScrollToTop(scrollRef.current.scrollTop > scrollToTopThreshold);
151
117
  }
152
118
 
153
- // Call user's onScroll handler
154
- if (onScroll) {
155
- onScroll(event);
156
- }
119
+ onScroll?.(event);
157
120
  },
158
- [
159
- disabled,
160
- autoHide,
161
- alwaysShowScrollbar,
162
- autoHideDelay,
163
- scrollToTopButton,
164
- scrollToTopThreshold,
165
- onScroll,
166
- ],
121
+ [disabled, noteScroll, scrollToTopButton, scrollToTopThreshold, onScroll, scrollRef],
167
122
  );
168
123
 
169
- // Scroll to top function
170
124
  const scrollToTop = useCallback(() => {
171
- if (scrollRef.current) {
172
- scrollRef.current.scrollTo({
173
- top: 0,
174
- behavior: smoothScroll ? 'smooth' : 'auto',
175
- });
176
- }
177
- }, [smoothScroll]);
178
-
179
- // Clean up timeout on unmount
180
- useEffect(() => () => {
181
- if (scrollTimeoutRef.current) {
182
- window.clearTimeout(scrollTimeoutRef.current);
183
- }
184
- }, []);
185
-
186
- // Determine if scrollbar should be visible
187
- const shouldShowScrollbar = alwaysShowScrollbar || !autoHide || isScrolling;
188
-
189
- // Get variant-specific styles
190
- const getVariantStyles = () => {
191
- const colors = getScrollbarColors();
192
- const size = getScrollbarSize();
193
-
194
- // Common scrollbar styles with auto-hide support
195
- const getAutoHideStyles = (thumbColor: string, trackColor: string) => ({
196
- '&::-webkit-scrollbar': {
197
- width: orientation !== 'horizontal' ? size : '100%',
198
- height: orientation !== 'vertical' ? size : '100%',
199
- },
200
- '&::-webkit-scrollbar-track': {
201
- background: shouldShowScrollbar ? trackColor : 'transparent',
202
- borderRadius: size / 2,
203
- transition: 'background 0.3s ease',
204
- },
205
- '&::-webkit-scrollbar-thumb': {
206
- background: shouldShowScrollbar ? thumbColor : 'transparent',
207
- borderRadius: size / 2,
208
- transition: 'background 0.3s ease',
209
- '&:hover': {
210
- background: shouldShowScrollbar ? theme.palette.primary.main : 'transparent',
211
- },
212
- },
213
- '&::-webkit-scrollbar-corner': {
214
- background: shouldShowScrollbar ? trackColor : 'transparent',
215
- },
216
- // Firefox scrollbar styling
217
- scrollbarWidth: shouldShowScrollbar
218
- ? scrollbarSize === 'thin'
219
- ? ('thin' as const)
220
- : ('auto' as const)
221
- : ('none' as const),
222
- scrollbarColor: shouldShowScrollbar
223
- ? `${thumbColor} ${trackColor}`
224
- : 'transparent transparent',
225
- });
226
-
227
- switch (variant) {
228
- case 'overlay':
229
- return {
230
- '&::-webkit-scrollbar': {
231
- width: orientation !== 'horizontal' ? size : '100%',
232
- height: orientation !== 'vertical' ? size : '100%',
233
- position: 'absolute',
234
- right: 0,
235
- top: 0,
236
- },
237
- '&::-webkit-scrollbar-track': {
238
- background: 'transparent',
239
- borderRadius: size / 2,
240
- },
241
- '&::-webkit-scrollbar-thumb': {
242
- background: shouldShowScrollbar
243
- ? alpha(colors.scrollbar, 0.5)
244
- : 'transparent',
245
- borderRadius: size / 2,
246
- transition: 'background 0.3s ease',
247
- border: '2px solid transparent',
248
- backgroundClip: 'padding-box',
249
- '&:hover': {
250
- background: shouldShowScrollbar ? theme.palette.primary.main : 'transparent',
251
- },
252
- },
253
- '&::-webkit-scrollbar-corner': {
254
- background: 'transparent',
255
- },
256
- scrollbarWidth: shouldShowScrollbar
257
- ? scrollbarSize === 'thin'
258
- ? ('thin' as const)
259
- : ('auto' as const)
260
- : ('none' as const),
261
- scrollbarColor: shouldShowScrollbar
262
- ? `${alpha(colors.scrollbar, 0.5)} transparent`
263
- : 'transparent transparent',
264
- };
265
-
266
- case 'glass': {
267
- const glassThumbColor = `linear-gradient(180deg, ${alpha(theme.palette.primary.main, 0.3)}, ${alpha(theme.palette.secondary.main, 0.3)})`;
268
- const glassTrackColor = alpha(theme.palette.background.paper, 0.1);
269
- return {
270
- '&::-webkit-scrollbar': {
271
- width: orientation !== 'horizontal' ? size : '100%',
272
- height: orientation !== 'vertical' ? size : '100%',
273
- },
274
- '&::-webkit-scrollbar-track': {
275
- background: shouldShowScrollbar ? glassTrackColor : 'transparent',
276
- borderRadius: size / 2,
277
- backdropFilter: shouldShowScrollbar ? 'blur(5px)' : 'none',
278
- transition: 'background 0.3s ease',
279
- },
280
- '&::-webkit-scrollbar-thumb': {
281
- background: shouldShowScrollbar ? glassThumbColor : 'transparent',
282
- borderRadius: size / 2,
283
- transition: 'background 0.3s ease',
284
- boxShadow: shouldShowScrollbar
285
- ? `inset 0 0 6px ${alpha(theme.palette.common.white, 0.3)}`
286
- : 'none',
287
- '&:hover': {
288
- background: shouldShowScrollbar ? theme.palette.primary.main : 'transparent',
289
- },
290
- },
291
- '&::-webkit-scrollbar-corner': {
292
- background: shouldShowScrollbar ? glassTrackColor : 'transparent',
293
- },
294
- scrollbarWidth: shouldShowScrollbar
295
- ? scrollbarSize === 'thin'
296
- ? ('thin' as const)
297
- : ('auto' as const)
298
- : ('none' as const),
299
- scrollbarColor: shouldShowScrollbar
300
- ? `${colors.scrollbar} ${glassTrackColor}`
301
- : 'transparent transparent',
302
- backdropFilter: 'blur(10px)',
303
- };
304
- }
305
-
306
- default:
307
- return getAutoHideStyles(colors.scrollbar, colors.track);
308
- }
309
- };
310
-
311
- // Render empty content if no children and emptyContent is provided
312
- const renderContent = () => {
313
- if (!children && emptyContent) {
314
- return (
315
- <Box
316
- sx={{
317
- display: 'flex',
318
- alignItems: 'center',
319
- justifyContent: 'center',
320
- height: '100%',
321
- minHeight: 200,
322
- color: theme.palette.text.secondary,
323
- }}
324
- >
325
- {emptyContent}
326
- </Box>
327
- );
328
- }
329
-
330
- // Auto-enhance children that accept scrollContainerRef (like VirtualList/VirtualGrid)
331
- return React.Children.map(children, (child) => {
332
- if (React.isValidElement(child)) {
333
- // Check if the child component accepts scrollContainerRef prop
334
- // by looking at its props type or if it's a known virtualization component
335
- const childProps = child.props as Record<string, unknown>;
125
+ scrollRef.current?.scrollTo({ top: 0, behavior: smoothScroll ? 'smooth' : 'auto' });
126
+ }, [smoothScroll, scrollRef]);
127
+
128
+ return {
129
+ scrollRef,
130
+ setScrollRef,
131
+ isScrolling,
132
+ showScrollToTop,
133
+ containerDimensions,
134
+ handleScroll,
135
+ scrollToTop };
136
+ };
336
137
 
337
- // If child has disableInternalScroll prop, it's likely a VirtualList/VirtualGrid
338
- // Auto-inject scrollContainerRef, disableInternalScroll, and container width
339
- if ('disableInternalScroll' in childProps || childProps.scrollContainerRef !== undefined) {
340
- const enhancedProps: Record<string, unknown> = {
341
- scrollContainerRef: internalScrollRef,
342
- disableInternalScroll: true,
343
- };
138
+ const LoadingOverlay: FC = () => (
139
+ <Box
140
+ sx={{
141
+ position: 'absolute',
142
+ top: '50%',
143
+ left: '50%',
144
+ transform: 'translate(-50%, -50%)',
145
+ zIndex: 10 }}
146
+ >
147
+ <CircularProgress />
148
+ </Box>
149
+ );
150
+
151
+ const ScrollToTopFab: FC<{ visible: boolean; glass: boolean; onClick: () => void }> = ({
152
+ visible,
153
+ glass,
154
+ onClick }) => {
155
+ const theme = useTheme();
344
156
 
345
- // If child accepts width and doesn't have one set, provide container width
346
- if (containerDimensions.width > 0 && childProps.width === '100%') {
347
- enhancedProps.width = containerDimensions.width;
348
- }
157
+ return (
158
+ <Zoom in={visible}>
159
+ <Fab
160
+ size="small"
161
+ aria-label="Scroll to top"
162
+ onClick={onClick}
163
+ sx={{
164
+ position: 'absolute',
165
+ bottom: 16,
166
+ right: 16,
167
+ zIndex: 1,
168
+ backgroundColor: glass
169
+ ? alpha(theme.palette.primary.main, 0.2)
170
+ : theme.palette.primary.main,
171
+ backdropFilter: glass ? 'blur(10px)' : 'none',
172
+ '&:hover': {
173
+ backgroundColor: glass
174
+ ? alpha(theme.palette.primary.main, 0.3)
175
+ : theme.palette.primary.dark } }}
176
+ >
177
+ <KeyboardArrowUp />
178
+ </Fab>
179
+ </Zoom>
180
+ );
181
+ };
349
182
 
350
- return React.cloneElement(child, enhancedProps);
351
- }
352
- }
353
- return child;
354
- });
355
- };
183
+ export const ScrollArea: React.FC<ScrollAreaProps> = (componentProps) => {
184
+ const resolved = resolveScrollAreaProps(componentProps);
185
+ const {
186
+ children,
187
+ width,
188
+ height,
189
+ maxHeight,
190
+ maxWidth,
191
+ orientation: _orientation,
192
+ scrollbarSize: _scrollbarSize,
193
+ autoHide,
194
+ autoHideDelay: _autoHideDelay,
195
+ smoothScroll: _smoothScroll,
196
+ variant,
197
+ onScroll: _onScroll,
198
+ scrollToTopButton,
199
+ scrollToTopThreshold: _scrollToTopThreshold,
200
+ scrollbarColor: _scrollbarColor,
201
+ scrollbarTrackColor: _scrollbarTrackColor,
202
+ contentPadding: _contentPadding,
203
+ alwaysShowScrollbar,
204
+ disabled,
205
+ loading,
206
+ emptyContent,
207
+ testId,
208
+ scrollRef: externalScrollRef,
209
+ onResize: _onResize,
210
+ sx,
211
+ ...props
212
+ } = resolved;
213
+
214
+ const {
215
+ scrollRef,
216
+ setScrollRef,
217
+ isScrolling,
218
+ showScrollToTop,
219
+ containerDimensions,
220
+ handleScroll,
221
+ scrollToTop } = useScrollArea({ ...resolved, externalScrollRef });
222
+
223
+ // Auto-hide keeps the scrollbar out of the way until the user is scrolling.
224
+ const shouldShowScrollbar = alwaysShowScrollbar || !autoHide || isScrolling;
356
225
 
357
226
  return (
358
227
  <Box
359
228
  data-testid={testId}
360
- sx={{
361
- position: 'relative',
362
- width,
363
- height,
364
- maxHeight,
365
- maxWidth,
366
- ...sx,
367
- }}
229
+ sx={{ position: 'relative', width, height, maxHeight, maxWidth, ...sx }}
368
230
  {...props}
369
231
  >
370
- <Box
371
- ref={setScrollRef}
232
+ <ScrollViewport
233
+ {...resolved}
234
+ shouldShowScrollbar={shouldShowScrollbar}
235
+ setScrollRef={setScrollRef}
372
236
  onScroll={handleScroll}
373
- role="region"
374
- aria-label="Scrollable content"
375
- aria-busy={loading}
376
- tabIndex={disabled ? -1 : 0}
377
- sx={{
378
- width: '100%',
379
- height: '100%',
380
- // Use explicit maxHeight when height is 'auto', otherwise inherit from parent
381
- maxHeight: height === 'auto' && maxHeight ? maxHeight : '100%',
382
- padding: contentPadding,
383
- opacity: loading ? 0.5 : 1,
384
- pointerEvents: disabled || loading ? 'none' : 'auto',
385
- transition: 'opacity 0.3s ease',
386
- '&:focus': {
387
- outline: 'none',
388
- '&:focus-visible': {
389
- outline: `2px solid ${theme.palette.primary.main}`,
390
- outlineOffset: -2,
391
- },
392
- },
393
- ...getOverflowStyle(),
394
- ...getVariantStyles(),
395
- }}
396
- style={{
397
- scrollBehavior: smoothScroll ? 'smooth' : 'auto',
398
- }}
399
237
  >
400
- {renderContent()}
401
- </Box>
402
-
403
- {/* Loading overlay */}
404
- {loading && (
405
- <Box
406
- sx={{
407
- position: 'absolute',
408
- top: '50%',
409
- left: '50%',
410
- transform: 'translate(-50%, -50%)',
411
- zIndex: 10,
412
- }}
238
+ <ScrollAreaContent
239
+ emptyContent={emptyContent}
240
+ scrollRef={scrollRef}
241
+ containerWidth={containerDimensions.width}
413
242
  >
414
- <CircularProgress />
415
- </Box>
416
- )}
243
+ {children}
244
+ </ScrollAreaContent>
245
+ </ScrollViewport>
246
+
247
+ {loading && <LoadingOverlay />}
417
248
 
418
- {/* Scroll to top button */}
419
249
  {scrollToTopButton && !disabled && !loading && (
420
- <Zoom in={showScrollToTop}>
421
- <Fab
422
- size="small"
423
- aria-label="Scroll to top"
424
- onClick={scrollToTop}
425
- sx={{
426
- position: 'absolute',
427
- bottom: 16,
428
- right: 16,
429
- zIndex: 1,
430
- backgroundColor:
431
- variant === 'glass'
432
- ? alpha(theme.palette.primary.main, 0.2)
433
- : theme.palette.primary.main,
434
- backdropFilter: variant === 'glass' ? 'blur(10px)' : 'none',
435
- '&:hover': {
436
- backgroundColor:
437
- variant === 'glass'
438
- ? alpha(theme.palette.primary.main, 0.3)
439
- : theme.palette.primary.dark,
440
- },
441
- }}
442
- >
443
- <KeyboardArrowUp />
444
- </Fab>
445
- </Zoom>
250
+ <ScrollToTopFab
251
+ visible={showScrollToTop}
252
+ glass={variant === 'glass'}
253
+ onClick={scrollToTop}
254
+ />
446
255
  )}
447
256
  </Box>
448
257
  );
@@ -0,0 +1,70 @@
1
+ import { Box, useTheme } from '@mui/material';
2
+ import type { FC, ReactNode } from 'react';
3
+ import React from 'react';
4
+
5
+ const EMPTY_MIN_HEIGHT = 200;
6
+
7
+ const EmptyState: FC<{ children: ReactNode }> = ({ children }) => {
8
+ const theme = useTheme();
9
+
10
+ return (
11
+ <Box
12
+ sx={{
13
+ display: 'flex',
14
+ alignItems: 'center',
15
+ justifyContent: 'center',
16
+ height: '100%',
17
+ minHeight: EMPTY_MIN_HEIGHT,
18
+ color: theme.palette.text.secondary,
19
+ }}
20
+ >
21
+ {children}
22
+ </Box>
23
+ );
24
+ };
25
+
26
+ // VirtualList and VirtualGrid scroll themselves by default. When one is nested
27
+ // here that would mean two scrollers, so they are handed this container instead
28
+ // and told to stop scrolling internally. They are recognised by the props they
29
+ // accept rather than by identity, so a wrapper around one still works.
30
+ const wantsScrollContainer = (props: Record<string, unknown>): boolean =>
31
+ 'disableInternalScroll' in props || props.scrollContainerRef !== undefined;
32
+
33
+ export interface ScrollAreaContentProps {
34
+ children: ReactNode;
35
+ emptyContent?: ReactNode;
36
+ scrollRef: React.RefObject<HTMLDivElement | null> | ((node: HTMLDivElement | null) => void);
37
+ containerWidth: number;
38
+ }
39
+
40
+ export const ScrollAreaContent: FC<ScrollAreaContentProps> = ({
41
+ children,
42
+ emptyContent,
43
+ scrollRef,
44
+ containerWidth,
45
+ }) => {
46
+ if (!children && emptyContent) return <EmptyState>{emptyContent}</EmptyState>;
47
+
48
+ return (
49
+ <>
50
+ {React.Children.map(children, (child) => {
51
+ if (!React.isValidElement(child)) return child;
52
+
53
+ const childProps = child.props as Record<string, unknown>;
54
+ if (!wantsScrollContainer(childProps)) return child;
55
+
56
+ const enhanced: Record<string, unknown> = {
57
+ scrollContainerRef: scrollRef,
58
+ disableInternalScroll: true,
59
+ };
60
+
61
+ // Only fill in a measured width where the child is still at its default.
62
+ if (containerWidth > 0 && childProps.width === '100%') {
63
+ enhanced.width = containerWidth;
64
+ }
65
+
66
+ return React.cloneElement(child, enhanced);
67
+ })}
68
+ </>
69
+ );
70
+ };