@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
@@ -0,0 +1,112 @@
1
+ import type React from 'react';
2
+ import { useCallback } from 'react';
3
+
4
+ import { TableDataRow } from './TableParts';
5
+ import type { TableBodyProps } from './Table.types';
6
+
7
+ // Row identity, selection and the row element itself. Split out of
8
+ // EnhancedTableBody so that component is just the virtualised/plain choice.
9
+ // A row's identity: the caller's extractor, else its id, else its position.
10
+ const useRowKey = (rowKeyExtractor: TableBodyProps['rowKeyExtractor']) =>
11
+ useCallback(
12
+ (rowData: Record<string, unknown>, index: number): string | number =>
13
+ rowKeyExtractor ? rowKeyExtractor(rowData, index) : (rowData.id as string | number) || index,
14
+ [rowKeyExtractor],
15
+ );
16
+
17
+ const useRowSelection = ({
18
+ selectedRows,
19
+ onSelectionChange,
20
+ }: {
21
+ selectedRows: Array<string | number>;
22
+ onSelectionChange: TableBodyProps['onSelectionChange'];
23
+ }) =>
24
+ useCallback(
25
+ (event: React.MouseEvent | React.ChangeEvent, rowKey: string | number) => {
26
+ // Stop propagation so selecting does not also fire the row click.
27
+ event.stopPropagation();
28
+ if (!onSelectionChange) return;
29
+ onSelectionChange(rowKey, !selectedRows.includes(rowKey));
30
+ },
31
+ [onSelectionChange, selectedRows],
32
+ );
33
+
34
+ export const useTableRowRenderer = ({
35
+ columns,
36
+ selectedRows,
37
+ onRowClick,
38
+ onRowFocus,
39
+ onRowBlur,
40
+ onSelectionChange,
41
+ rowKeyExtractor,
42
+ selectable,
43
+ renderRow,
44
+ renderCell,
45
+ virtualScrolling,
46
+ rowHeight,
47
+ }: Pick<
48
+ TableBodyProps,
49
+ | 'columns'
50
+ | 'onRowClick'
51
+ | 'onRowFocus'
52
+ | 'onRowBlur'
53
+ | 'onSelectionChange'
54
+ | 'rowKeyExtractor'
55
+ | 'selectable'
56
+ | 'renderRow'
57
+ | 'renderCell'
58
+ | 'virtualScrolling'
59
+ | 'rowHeight'
60
+ > & { selectedRows: Array<string | number> }) => {
61
+ const getRowKey = useRowKey(rowKeyExtractor);
62
+ const isRowSelected = useCallback(
63
+ (rowKey: string | number) => selectedRows.includes(rowKey),
64
+ [selectedRows],
65
+ );
66
+ const handleRowSelection = useRowSelection({ selectedRows, onSelectionChange });
67
+
68
+ const renderTableRow = useCallback(
69
+ (rowData: Record<string, unknown>, index: number, offsetY: number = 0) => {
70
+ const rowKey = getRowKey(rowData, index);
71
+ const selected = isRowSelected(rowKey);
72
+
73
+ if (renderRow) return renderRow(rowData, index, selected);
74
+
75
+ return (
76
+ <TableDataRow
77
+ key={rowKey}
78
+ rowData={rowData}
79
+ rowKey={rowKey}
80
+ index={index}
81
+ offsetY={offsetY}
82
+ columns={columns}
83
+ selected={selected}
84
+ selectable={selectable}
85
+ rowHeight={rowHeight}
86
+ onRowClick={onRowClick}
87
+ onRowFocus={onRowFocus}
88
+ onRowBlur={onRowBlur}
89
+ onSelect={handleRowSelection}
90
+ virtualScrolling={virtualScrolling}
91
+ renderCell={renderCell}
92
+ />
93
+ );
94
+ },
95
+ [
96
+ columns,
97
+ getRowKey,
98
+ isRowSelected,
99
+ handleRowSelection,
100
+ onRowClick,
101
+ onRowFocus,
102
+ onRowBlur,
103
+ renderRow,
104
+ renderCell,
105
+ rowHeight,
106
+ selectable,
107
+ virtualScrolling,
108
+ ],
109
+ );
110
+
111
+ return renderTableRow;
112
+ };
@@ -0,0 +1,298 @@
1
+ import {
2
+ Box,
3
+ Checkbox,
4
+ TableBody,
5
+ TableCell,
6
+ TableHead,
7
+ TableRow,
8
+ TableSortLabel } from '@mui/material';
9
+ import React, { useCallback } from 'react';
10
+
11
+ import { useVirtualScrolling } from './Table.hooks';
12
+ import { useTableRowRenderer } from './TableParts.hooks';
13
+ import type { ColumnConfig, TableBodyProps, TableHeaderProps } from './Table.types';
14
+
15
+ // Mirrors the visible sort indicator for assistive technology; undefined when
16
+ // the column is not sorted, which is what removes the attribute entirely.
17
+ const ariaSortFor = (
18
+ canSort: boolean,
19
+ isSorted: boolean,
20
+ direction?: 'asc' | 'desc',
21
+ ): 'ascending' | 'descending' | undefined => {
22
+ if (!canSort || !isSorted) return undefined;
23
+
24
+ return direction === 'asc' ? 'ascending' : 'descending';
25
+ };
26
+
27
+ // One header cell. Sorting is offered when the table is sortable and the column
28
+ // has not opted out; aria-sort mirrors the visible indicator.
29
+ const HeaderCell: React.FC<{
30
+ column: ColumnConfig;
31
+ sortable?: boolean;
32
+ sortConfig?: { key: string; direction: 'asc' | 'desc' };
33
+ onSort: (columnKey: string) => void;
34
+ }> = ({ column, sortable, sortConfig, onSort }) => {
35
+ const canSort = Boolean(sortable) && column.sortable !== false;
36
+ const isSorted = sortConfig?.key === column.key;
37
+
38
+ return (
39
+ <TableCell
40
+ align={column.align || 'left'}
41
+ style={{ minWidth: column.minWidth, width: column.width }}
42
+ aria-sort={ariaSortFor(canSort, isSorted, sortConfig?.direction)}
43
+ >
44
+ {canSort ? (
45
+ <TableSortLabel
46
+ active={isSorted}
47
+ direction={isSorted ? sortConfig?.direction : 'asc'}
48
+ onClick={() => onSort(column.key)}
49
+ data-testid="sort-indicator"
50
+ aria-label={`Sort by ${column.label}`}
51
+ >
52
+ {column.label}
53
+ </TableSortLabel>
54
+ ) : (
55
+ column.label
56
+ )}
57
+ </TableCell>
58
+ );
59
+ };
60
+
61
+ export const EnhancedTableHeader: React.FC<TableHeaderProps> = React.memo(({
62
+ columns,
63
+ data,
64
+ sortable,
65
+ sortConfig,
66
+ onSortChange,
67
+ selectable,
68
+ selectedRows = [],
69
+ onSelectAll }) => {
70
+ const handleSort = useCallback(
71
+ (columnKey: string) => {
72
+ if (!sortable || !onSortChange) return;
73
+
74
+ const direction =
75
+ sortConfig?.key === columnKey && sortConfig.direction === 'asc' ? 'desc' : 'asc';
76
+ onSortChange(columnKey, direction);
77
+ },
78
+ [sortable, onSortChange, sortConfig]
79
+ );
80
+
81
+ const handleSelectAll = useCallback(
82
+ (event: React.ChangeEvent<globalThis.HTMLInputElement>) => {
83
+ if (!onSelectAll) return;
84
+ onSelectAll(event.target.checked);
85
+ },
86
+ [onSelectAll]
87
+ );
88
+
89
+ return (
90
+ <TableHead>
91
+ <TableRow>
92
+ {selectable && (
93
+ <TableCell padding="checkbox">
94
+ <Checkbox
95
+ indeterminate={selectedRows.length > 0 && selectedRows.length < data.length}
96
+ checked={selectedRows.length === data.length && data.length > 0}
97
+ onChange={handleSelectAll}
98
+ inputProps={{ 'aria-label': 'select all' }}
99
+ />
100
+ </TableCell>
101
+ )}
102
+ {columns.map((column) => (
103
+ <HeaderCell
104
+ key={column.key}
105
+ column={column}
106
+ sortable={sortable}
107
+ sortConfig={sortConfig}
108
+ onSort={handleSort}
109
+ />
110
+ ))}
111
+ </TableRow>
112
+ </TableHead>
113
+ );
114
+ });
115
+
116
+ EnhancedTableHeader.displayName = 'EnhancedTableHeader';
117
+
118
+ // One data row. Split out of the memoised renderTableRow callback so the
119
+ // callback stays a short dispatch and the row markup is readable on its own.
120
+ export const TableDataRow: React.FC<{
121
+ rowData: Record<string, unknown>;
122
+ rowKey: string | number;
123
+ index: number;
124
+ offsetY: number;
125
+ columns: ColumnConfig[];
126
+ selected: boolean;
127
+ selectable?: boolean;
128
+ rowHeight?: number;
129
+ onRowClick?: TableBodyProps['onRowClick'];
130
+ onRowFocus?: TableBodyProps['onRowFocus'];
131
+ onRowBlur?: TableBodyProps['onRowBlur'];
132
+ onSelect: (event: React.MouseEvent | React.ChangeEvent, rowKey: string | number) => void;
133
+ virtualScrolling?: boolean;
134
+ renderCell?: TableBodyProps['renderCell'];
135
+ }> = ({
136
+ rowData,
137
+ rowKey,
138
+ index,
139
+ offsetY,
140
+ columns,
141
+ selected,
142
+ selectable,
143
+ rowHeight,
144
+ onRowClick,
145
+ onRowFocus,
146
+ onRowBlur,
147
+ onSelect,
148
+ virtualScrolling,
149
+ renderCell }) => (
150
+
151
+ <TableRow
152
+ key={String(rowKey)}
153
+ selected={selected}
154
+ className={selected ? 'selected' : ''}
155
+ onClick={(event: React.MouseEvent<globalThis.HTMLTableRowElement>) => onRowClick?.(event, rowData)}
156
+ onFocus={(event: React.FocusEvent<globalThis.HTMLTableRowElement>) => onRowFocus?.(event, rowData)}
157
+ onBlur={(event: React.FocusEvent<globalThis.HTMLTableRowElement>) => onRowBlur?.(event, rowData)}
158
+ style={virtualScrolling ? {
159
+ transform: `translateY(${offsetY}px)`,
160
+ position: 'absolute',
161
+ top: 0,
162
+ left: 0,
163
+ right: 0,
164
+ height: rowHeight } : undefined}
165
+ >
166
+ {selectable && (
167
+ <TableCell padding="checkbox">
168
+ <Checkbox
169
+ checked={selected}
170
+ onChange={(event) => onSelect(event, rowKey)}
171
+ onClick={(event) => event.stopPropagation()}
172
+ inputProps={{ 'aria-label': `select row ${index + 1}` }}
173
+ />
174
+ </TableCell>
175
+ )}
176
+ {columns.map((column) => {
177
+ const value = rowData[column.key];
178
+ return (
179
+ <TableCell key={column.key} align={column.align || 'left'}>
180
+ {renderCell
181
+ ? renderCell(value, column, rowData, index)
182
+ : column.render
183
+ ? column.render(value, rowData)
184
+ : (value as React.ReactNode)
185
+ }
186
+ </TableCell>
187
+ );
188
+ })}
189
+ </TableRow>
190
+ );
191
+
192
+ // Only the rows in view are rendered, positioned by absolute offset inside a
193
+ // spacer sized to the full data set.
194
+ const VirtualisedBody: React.FC<{
195
+ visibleItems: {
196
+ items: Record<string, unknown>[];
197
+ startIndex: number;
198
+ offsetY: number;
199
+ totalHeight: number;
200
+ };
201
+ rowHeight: number;
202
+ containerHeight: number;
203
+ onScroll: (event: React.UIEvent<HTMLDivElement>) => void;
204
+ renderTableRow: (
205
+ rowData: Record<string, unknown>,
206
+ index: number,
207
+ offsetY?: number,
208
+ ) => React.ReactNode;
209
+ }> = ({ visibleItems, rowHeight, containerHeight, onScroll, renderTableRow }) => (
210
+
211
+ <Box
212
+ onScroll={onScroll}
213
+ style={{
214
+ height: containerHeight,
215
+ overflow: 'auto',
216
+ position: 'relative' }}
217
+ >
218
+ <TableBody
219
+ style={{
220
+ height: visibleItems.totalHeight,
221
+ position: 'relative' }}
222
+ >
223
+ {visibleItems.items.map((rowData, index) =>
224
+ renderTableRow(rowData, visibleItems.startIndex + index, visibleItems.offsetY + index * rowHeight)
225
+ )}
226
+ </TableBody>
227
+ </Box>
228
+
229
+ );
230
+
231
+ const PlainBody: React.FC<{
232
+ data: TableBodyProps['data'];
233
+ renderTableRow: (rowData: Record<string, unknown>, index: number) => React.ReactNode;
234
+ }> = ({ data, renderTableRow }) => (
235
+
236
+ <TableBody>
237
+ {data.map((rowData, index) => renderTableRow(rowData, index))}
238
+ </TableBody>
239
+ );
240
+
241
+ // Enhanced Table Body Component
242
+ export const EnhancedTableBody: React.FC<TableBodyProps> = React.memo(({
243
+ data,
244
+ columns,
245
+ selectedRows = [],
246
+ onRowClick,
247
+ onRowFocus,
248
+ onRowBlur,
249
+ onSelectionChange,
250
+ rowKeyExtractor,
251
+ selectable,
252
+ renderRow,
253
+ renderCell,
254
+ virtualScrolling,
255
+ containerHeight,
256
+ rowHeight,
257
+ overscan = 5 }) => {
258
+ const renderTableRow = useTableRowRenderer({
259
+ columns,
260
+ selectedRows,
261
+ onRowClick,
262
+ onRowFocus,
263
+ onRowBlur,
264
+ onSelectionChange,
265
+ rowKeyExtractor,
266
+ selectable,
267
+ renderRow,
268
+ renderCell,
269
+ virtualScrolling,
270
+ rowHeight });
271
+
272
+ const { visibleItems, handleScroll } = useVirtualScrolling(
273
+ data,
274
+ rowHeight || 40,
275
+ typeof containerHeight === 'number' ? containerHeight : 400,
276
+ overscan
277
+ );
278
+
279
+ if (virtualScrolling && containerHeight && rowHeight) {
280
+ return (
281
+ <VirtualisedBody
282
+ visibleItems={visibleItems}
283
+ rowHeight={rowHeight}
284
+ containerHeight={containerHeight}
285
+ onScroll={handleScroll}
286
+ renderTableRow={renderTableRow}
287
+ />
288
+ );
289
+ }
290
+
291
+ return (
292
+ <PlainBody data={data} renderTableRow={renderTableRow} />
293
+ );
294
+ });
295
+
296
+ EnhancedTableBody.displayName = 'EnhancedTableBody';
297
+
298
+ // Main Table Component
@@ -0,0 +1,21 @@
1
+ import { Box, TableBody, TableCell, TableRow } from '@mui/material';
2
+ import React from 'react';
3
+
4
+
5
+ export const NoDataPlaceholder: React.FC = () => (
6
+ <Box py={4} color="text.secondary">
7
+ No data available
8
+ </Box>
9
+ );
10
+
11
+ export const EmptyRow: React.FC<{ colSpan: number; children: React.ReactNode }> = ({
12
+ colSpan,
13
+ children }) => (
14
+ <TableBody>
15
+ <TableRow>
16
+ <TableCell colSpan={colSpan} align="center">
17
+ {children}
18
+ </TableCell>
19
+ </TableRow>
20
+ </TableBody>
21
+ );
@@ -1,15 +1,13 @@
1
- import {
2
- CheckCircle,
3
- Error,
4
- Flag,
5
- Inventory,
6
- LocalShipping,
7
- Payment,
8
- Person,
9
- Schedule,
10
- Star,
11
- Warning,
12
- } from '@mui/icons-material';
1
+ import CheckCircle from '@mui/icons-material/CheckCircle';
2
+ import Error from '@mui/icons-material/Error';
3
+ import Flag from '@mui/icons-material/Flag';
4
+ import Inventory from '@mui/icons-material/Inventory';
5
+ import LocalShipping from '@mui/icons-material/LocalShipping';
6
+ import Payment from '@mui/icons-material/Payment';
7
+ import Person from '@mui/icons-material/Person';
8
+ import Schedule from '@mui/icons-material/Schedule';
9
+ import Star from '@mui/icons-material/Star';
10
+ import Warning from '@mui/icons-material/Warning';
13
11
  import { Box, Stack, Typography } from '@mui/material';
14
12
  import type { Meta, StoryObj } from '@storybook/react-vite';
15
13
  import React from 'react';
@@ -1,4 +1,7 @@
1
- import { CheckCircle, Error as ErrorIcon, Info, Warning } from '@mui/icons-material';
1
+ import CheckCircle from '@mui/icons-material/CheckCircle';
2
+ import ErrorIcon from '@mui/icons-material/Error';
3
+ import Info from '@mui/icons-material/Info';
4
+ import Warning from '@mui/icons-material/Warning';
2
5
  import type { Meta, StoryObj } from '@storybook/react-vite';
3
6
  import { expect, fn,Mock,userEvent, waitFor, within } from 'storybook/test';
4
7
 
@@ -101,16 +104,14 @@ export const BasicInteraction: Story = {
101
104
 
102
105
  // Initially collapsed - description should not be visible
103
106
  const firstDescription = sampleItems[0].description!;
104
- let descriptionElement = canvas.queryByText(firstDescription);
105
- await expect(descriptionElement).not.toBeVisible();
107
+ await waitFor(() => expect(canvas.queryByText(firstDescription)).not.toBeVisible());
106
108
 
107
109
  // Click to expand
108
110
  await userEvent.click(expandButtons[0]);
109
111
 
110
112
  // Wait for expansion animation and verify description is now visible
111
113
  await waitFor(() => {
112
- descriptionElement = canvas.getByText(firstDescription);
113
- expect(descriptionElement).toBeVisible();
114
+ expect(canvas.getByText(firstDescription)).toBeVisible();
114
115
  }, { timeout: 3000 });
115
116
 
116
117
  // Verify the expand button rotated (indicates expanded state)
@@ -123,8 +124,7 @@ export const BasicInteraction: Story = {
123
124
 
124
125
  // Wait for collapse animation
125
126
  await waitFor(() => {
126
- descriptionElement = canvas.queryByText(firstDescription);
127
- expect(descriptionElement).not.toBeVisible();
127
+ expect(canvas.queryByText(firstDescription)).not.toBeVisible();
128
128
  }, { timeout: 3000 });
129
129
 
130
130
  // Verify the expand button rotated back
@@ -303,7 +303,7 @@ export const ScreenReader: Story = {
303
303
  for (const button of expandButtons) {
304
304
  // Button should be focusable
305
305
  await expect(button).not.toHaveAttribute('disabled');
306
- await expect(button.tabIndex).toBeGreaterThanOrEqual(0);
306
+ await expect(button).not.toHaveAttribute('tabindex', '-1');
307
307
  }
308
308
 
309
309
  // Verify icons are decorative (aria-hidden) or have labels
@@ -353,14 +353,15 @@ export const FocusManagement: Story = {
353
353
  // Test focus retention on expand/collapse
354
354
  await expect(expandButtons.length).toBeGreaterThan(0);
355
355
 
356
- expandButtons[0].focus();
357
- await expect(document.activeElement).toBe(expandButtons[0]);
356
+ // Tab in from the body to reach the first expand button.
357
+ await userEvent.tab();
358
+ await waitFor(() => expect(expandButtons[0]).toHaveFocus());
358
359
 
359
360
  // Click to expand
360
361
  await userEvent.click(expandButtons[0]);
361
362
 
362
363
  // Focus should remain on the button after expansion
363
- await expect(document.activeElement).toBe(expandButtons[0]);
364
+ await waitFor(() => expect(expandButtons[0]).toHaveFocus());
364
365
 
365
366
  // Wait for expansion to complete
366
367
  await waitFor(() => {
@@ -370,12 +371,10 @@ export const FocusManagement: Story = {
370
371
 
371
372
  // Now action button should be available
372
373
  const actionButton = canvas.getByRole('button', { name: /View Details/i });
373
- actionButton.focus();
374
- await expect(document.activeElement).toBe(actionButton);
375
374
 
376
- // Click action button and verify focus remains
375
+ // Clicking focuses the button, so the pre-focus only asserted focus() works.
377
376
  await userEvent.click(actionButton);
378
- await expect(document.activeElement).toBe(actionButton);
377
+ await waitFor(() => expect(actionButton).toHaveFocus());
379
378
  await expect(args.items[0].action?.onClick).toHaveBeenCalled();
380
379
 
381
380
  // Test focus on card click
@@ -384,19 +383,18 @@ export const FocusManagement: Story = {
384
383
 
385
384
  // Test focus trap prevention (focus can move outside component)
386
385
  const lastExpandButton = expandButtons[expandButtons.length - 1];
387
- lastExpandButton.focus();
386
+
387
+ // Walk the keyboard to the last expand button, then once more: focus has to
388
+ // leave the timeline rather than wrap back into it.
389
+ await userEvent.click(lastExpandButton);
390
+ await waitFor(() => expect(lastExpandButton).toHaveFocus());
391
+
388
392
  await userEvent.tab();
393
+ await waitFor(() => expect(lastExpandButton).not.toHaveFocus());
389
394
 
390
- // Focus should move outside the timeline component
391
- await expect(document.activeElement).not.toBe(lastExpandButton);
392
-
393
- // Test programmatic focus
394
- expandButtons[1].focus();
395
- await expect(document.activeElement).toBe(expandButtons[1]);
396
-
397
- // Click to expand second item
395
+ // Clicking the second item's expand button focuses it and keeps focus there.
398
396
  await userEvent.click(expandButtons[1]);
399
- await expect(document.activeElement).toBe(expandButtons[1]);
397
+ await waitFor(() => expect(expandButtons[1]).toHaveFocus());
400
398
 
401
399
  // Verify multiple items can be expanded simultaneously
402
400
  await waitFor(() => {
@@ -422,17 +420,13 @@ export const ResponsiveDesign: Story = {
422
420
  const canvas = within(canvasElement);
423
421
 
424
422
  // Verify timeline renders on mobile - wait longer for mobile viewport
425
- let container: HTMLElement | null = null;
423
+ // Read the container after the wait rather than assigning to an outer
424
+ // binding from inside the callback — the callback reruns, so the binding
425
+ // held whichever value the last retry happened to leave behind.
426
426
  await waitFor(() => {
427
- container = canvas.getByTestId('timeline-container') as HTMLElement;
428
- expect(container).toBeInTheDocument();
429
- expect(container).not.toBeNull();
427
+ expect(canvas.getByTestId('timeline-container')).toBeInTheDocument();
430
428
  }, { timeout: 5000 });
431
-
432
- // Assert container is not null for TypeScript
433
- if (!container) {
434
- throw new Error('Timeline container not found');
435
- }
429
+ const container = canvas.getByTestId('timeline-container');
436
430
 
437
431
  // Wait for all items to render
438
432
  await waitFor(() => {
@@ -725,20 +719,12 @@ export const Performance: Story = {
725
719
  await expect(style.animation).toContain('none');
726
720
  }
727
721
 
728
- // Test interaction performance with many items
729
- const startTime = Date.now();
730
-
731
- // Click multiple items quickly
722
+ // Click multiple items quickly. No wall-clock budget: a 1s ceiling on three
723
+ // clicks measures how loaded the runner is, not how the component performs.
732
724
  await userEvent.click(items[0]);
733
725
  await userEvent.click(items[10]);
734
726
  await userEvent.click(items[20]);
735
727
 
736
- const endTime = Date.now();
737
- const interactionTime = endTime - startTime;
738
-
739
- // Interactions should be responsive (under 1 second for 3 clicks)
740
- await expect(interactionTime).toBeLessThan(1000);
741
-
742
728
  // Verify clicks were registered
743
729
  await expect(args.onItemClick).toHaveBeenCalledTimes(3);
744
730