@12-apps/ui 1.0.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/components-catalog.md +14 -0
  2. package/package.json +42 -27
  3. package/src/__tests__/data-grid.test.tsx +125 -0
  4. package/src/__tests__/package-wiring.test.ts +12 -8
  5. package/src/__tests__/social-login-button.test.tsx +5 -5
  6. package/src/__tests__/viewport.test.ts +50 -0
  7. package/src/charts/index.ts +8 -0
  8. package/src/components/data-display/Alert/Alert.md +1 -1
  9. package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
  10. package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
  11. package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
  12. package/src/components/data-display/Alert/Alert.tsx +135 -328
  13. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
  14. package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
  15. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
  16. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
  17. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
  18. package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
  19. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
  20. package/src/components/data-display/Avatar/Avatar.tsx +154 -450
  21. package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
  22. package/src/components/data-display/Badge/Badge.animations.ts +67 -0
  23. package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
  24. package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
  25. package/src/components/data-display/Badge/Badge.styles.ts +261 -0
  26. package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
  27. package/src/components/data-display/Badge/Badge.tsx +151 -557
  28. package/src/components/data-display/Badge/Badge.variants.ts +106 -0
  29. package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
  30. package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
  31. package/src/components/data-display/Banner/Banner.styles.ts +120 -0
  32. package/src/components/data-display/Banner/Banner.tsx +179 -224
  33. package/src/components/data-display/Chart/Chart.md +48 -1
  34. package/src/components/data-display/Chart/Chart.tsx +82 -500
  35. package/src/components/data-display/Chart/Chart.types.ts +2 -0
  36. package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
  37. package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
  38. package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
  39. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
  40. package/src/components/data-display/Chart/SpecChart.tsx +53 -0
  41. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
  42. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
  43. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
  44. package/src/components/data-display/Chart/chart-format.ts +26 -0
  45. package/src/components/data-display/Chart/chart-internals.ts +148 -0
  46. package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
  47. package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
  48. package/src/components/data-display/Chart/chart-spec.ts +171 -0
  49. package/src/components/data-display/Chart/index.ts +30 -0
  50. package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
  51. package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
  52. package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
  53. package/src/components/data-display/Chip/Chip.tsx +31 -94
  54. package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
  55. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
  56. package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
  57. package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
  58. package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
  59. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
  60. package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
  61. package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
  62. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
  63. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
  64. package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
  65. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
  66. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
  67. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
  68. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
  69. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
  70. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
  71. package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
  72. package/src/components/data-display/DataViews/base-card.tsx +278 -0
  73. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
  74. package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
  75. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
  76. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
  77. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
  78. package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
  79. package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
  80. package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
  81. package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
  82. package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
  83. package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
  84. package/src/components/data-display/DataViews/data-views-types.ts +312 -0
  85. package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
  86. package/src/components/data-display/DataViews/index.ts +33 -0
  87. package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
  88. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
  89. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
  90. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
  91. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
  92. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
  93. package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
  94. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
  95. package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
  98. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
  99. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
  100. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
  101. package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
  102. package/src/components/data-display/LazyImage/LazyImage.md +1 -1
  103. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
  104. package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
  105. package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
  106. package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
  107. package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
  108. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
  109. package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
  110. package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
  111. package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
  112. package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
  113. package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
  114. package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
  115. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
  116. package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
  117. package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
  118. package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
  119. package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
  120. package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
  121. package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
  122. package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
  123. package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
  124. package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
  125. package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
  126. package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
  127. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
  128. package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
  129. package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
  130. package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
  131. package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
  132. package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
  133. package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
  134. package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
  135. package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
  136. package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
  137. package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
  138. package/src/components/data-display/Progress/Progress.styles.ts +101 -0
  139. package/src/components/data-display/Progress/Progress.tsx +185 -213
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
  142. package/src/components/data-display/StatCard/StatCard.md +117 -0
  143. package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
  144. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
  145. package/src/components/data-display/StatCard/StatCard.tsx +236 -0
  146. package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
  147. package/src/components/data-display/StatCard/index.ts +7 -0
  148. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
  149. package/src/components/data-display/Stepper/Stepper.tsx +1 -1
  150. package/src/components/data-display/Table/Table.helpers.ts +31 -0
  151. package/src/components/data-display/Table/Table.hooks.ts +161 -0
  152. package/src/components/data-display/Table/Table.stories.tsx +3 -1
  153. package/src/components/data-display/Table/Table.styles.ts +223 -0
  154. package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
  155. package/src/components/data-display/Table/Table.tsx +291 -748
  156. package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
  157. package/src/components/data-display/Table/TableParts.tsx +298 -0
  158. package/src/components/data-display/Table/TableStates.tsx +21 -0
  159. package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
  160. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
  161. package/src/components/data-display/Timeline/Timeline.tsx +23 -284
  162. package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
  163. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
  164. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
  165. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
  166. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
  167. package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
  168. package/src/components/data-display/index.ts +1 -0
  169. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
  170. package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
  171. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
  172. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
  173. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
  174. package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
  175. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
  176. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
  177. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
  178. package/src/components/feedback/ConfirmAction/index.ts +16 -0
  179. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
  180. package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
  181. package/src/components/feedback/Dialog/Dialog.tsx +26 -1
  182. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
  183. package/src/components/feedback/Modal/Modal.md +1 -1
  184. package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
  185. package/src/components/feedback/Sonner/Sonner.tsx +104 -288
  186. package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
  187. package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
  188. package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
  189. package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
  190. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
  191. package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
  192. package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
  193. package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
  194. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
  195. package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
  196. package/src/components/feedback/Toast/Toast.tsx +92 -81
  197. package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
  198. package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
  199. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
  200. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
  201. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
  202. package/src/components/feedback/index.ts +1 -0
  203. package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
  204. package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
  205. package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
  206. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
  207. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
  208. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
  209. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
  210. package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
  211. package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
  212. package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
  213. package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
  214. package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
  215. package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
  216. package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
  217. package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
  218. package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
  219. package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
  220. package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
  221. package/src/components/form/Button/Button.helpers.ts +36 -0
  222. package/src/components/form/Button/Button.stories.tsx +4 -1
  223. package/src/components/form/Button/Button.styles.ts +225 -0
  224. package/src/components/form/Button/Button.test.stories.tsx +25 -21
  225. package/src/components/form/Button/Button.tsx +45 -252
  226. package/src/components/form/Calendar/Calendar.dates.ts +100 -0
  227. package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
  228. package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
  229. package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
  230. package/src/components/form/Calendar/Calendar.selection.ts +156 -0
  231. package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
  232. package/src/components/form/Calendar/Calendar.tsx +63 -551
  233. package/src/components/form/Calendar/Calendar.types.ts +16 -0
  234. package/src/components/form/Calendar/CalendarDay.tsx +127 -0
  235. package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
  236. package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
  237. package/src/components/form/CepField/CepField.md +138 -0
  238. package/src/components/form/CepField/CepField.stories.tsx +138 -0
  239. package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
  240. package/src/components/form/CepField/CepField.tsx +211 -0
  241. package/src/components/form/CepField/CepField.types.ts +73 -0
  242. package/src/components/form/CepField/index.ts +2 -0
  243. package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
  244. package/src/components/form/Checkbox/Checkbox.tsx +19 -16
  245. package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
  246. package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
  247. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
  248. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
  249. package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
  250. package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
  251. package/src/components/form/Command/Command.hooks.ts +207 -0
  252. package/src/components/form/Command/Command.parts.tsx +58 -0
  253. package/src/components/form/Command/Command.styles.ts +83 -0
  254. package/src/components/form/Command/Command.tsx +61 -270
  255. package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
  256. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
  257. package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
  258. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
  259. package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
  260. package/src/components/form/HeaderButton/index.ts +2 -0
  261. package/src/components/form/Input/Input.stories.tsx +5 -1
  262. package/src/components/form/Input/Input.styles.ts +176 -0
  263. package/src/components/form/Input/Input.test.stories.tsx +30 -23
  264. package/src/components/form/Input/Input.tsx +71 -211
  265. package/src/components/form/Input/Input.types.ts +11 -0
  266. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
  267. package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
  268. package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
  269. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
  270. package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
  271. package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
  272. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
  273. package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
  274. package/src/components/form/PhoneInput/countries.ts +54 -0
  275. package/src/components/form/PhoneInput/phone.ts +47 -0
  276. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
  277. package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
  278. package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
  279. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
  280. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
  281. package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
  282. package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
  283. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
  284. package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
  285. package/src/components/form/Select/Select.test.stories.tsx +35 -27
  286. package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
  287. package/src/components/form/Switch/Switch.md +2 -1
  288. package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
  289. package/src/components/form/Textarea/Textarea.styles.ts +143 -0
  290. package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
  291. package/src/components/form/Textarea/Textarea.tsx +114 -535
  292. package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
  293. package/src/components/form/Toggle/Toggle.styles.ts +211 -0
  294. package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
  295. package/src/components/form/Toggle/Toggle.tsx +10 -185
  296. package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
  297. package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
  298. package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
  299. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
  300. package/src/components/form/UploadButton/UploadButton.tsx +76 -305
  301. package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
  302. package/src/components/form/index.ts +1 -0
  303. package/src/components/form/total-form/Fields/CepField.tsx +143 -0
  304. package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
  305. package/src/components/form/total-form/Fields/index.ts +4 -0
  306. package/src/components/form/total-form/FormContainer.tsx +3 -3
  307. package/src/components/form/total-form/SubmitButton.tsx +25 -2
  308. package/src/components/form/total-form/total-form.test.tsx +118 -1
  309. package/src/components/layout/Accordion/Accordion.md +1 -1
  310. package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
  311. package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
  312. package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
  313. package/src/components/layout/Accordion/Accordion.tsx +2 -75
  314. package/src/components/layout/Card/Card.helpers.ts +30 -0
  315. package/src/components/layout/Card/Card.stories.tsx +9 -11
  316. package/src/components/layout/Card/Card.styles.ts +182 -0
  317. package/src/components/layout/Card/Card.test.stories.tsx +46 -46
  318. package/src/components/layout/Card/Card.tsx +24 -241
  319. package/src/components/layout/CardGrid/CardGrid.md +96 -0
  320. package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
  321. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
  322. package/src/components/layout/CardGrid/index.ts +2 -0
  323. package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
  324. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
  325. package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
  326. package/src/components/layout/Container/Container.test.stories.tsx +11 -16
  327. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
  328. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
  329. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
  330. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
  331. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
  332. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
  333. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
  334. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
  335. package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
  336. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
  337. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
  338. package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
  339. package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
  340. package/src/components/layout/Dashboard/index.ts +2 -1
  341. package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
  342. package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
  343. package/src/components/layout/Drawer/Drawer.tsx +67 -53
  344. package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
  345. package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
  346. package/src/components/layout/Resizable/Resizable.tsx +38 -153
  347. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
  348. package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
  349. package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
  350. package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
  351. package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
  352. package/src/components/layout/Separator/Separator.styles.ts +128 -0
  353. package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
  354. package/src/components/layout/Separator/Separator.tsx +6 -132
  355. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
  356. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
  357. package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
  358. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
  359. package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
  360. package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
  361. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
  362. package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
  363. package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
  364. package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
  365. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
  366. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
  367. package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
  368. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
  369. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
  370. package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
  371. package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
  372. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
  373. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
  374. package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
  375. package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
  376. package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
  377. package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
  378. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
  379. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
  380. package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
  381. package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
  382. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
  383. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
  384. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
  385. package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
  386. package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
  387. package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
  388. package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
  389. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
  390. package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
  391. package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
  392. package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
  393. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
  394. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
  395. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
  396. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
  397. package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
  398. package/src/components/navigation/Pagination/Pagination.md +2 -1
  399. package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
  400. package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
  401. package/src/components/navigation/Pagination/Pagination.tsx +178 -313
  402. package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
  403. package/src/components/navigation/Tabs/Tabs.md +3 -1
  404. package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
  405. package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
  406. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
  407. package/src/components/navigation/Tabs/Tabs.tsx +192 -361
  408. package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
  409. package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
  410. package/src/components/typography/Code/Code.test.stories.tsx +5 -5
  411. package/src/components/typography/Code/Code.tsx +74 -49
  412. package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
  413. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
  414. package/src/components/typography/Text/Text.tsx +84 -77
  415. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
  416. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
  417. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
  418. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
  419. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
  420. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
  421. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
  422. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
  423. package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
  424. package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
  425. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
  426. package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
  427. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
  428. package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
  429. package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
  430. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
  431. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
  432. package/src/components/utility/InstallPrompt/index.ts +10 -0
  433. package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
  434. package/src/components/utility/Transition/Transition.helpers.ts +40 -0
  435. package/src/components/utility/Transition/Transition.tsx +17 -68
  436. package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
  437. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
  438. package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
  439. package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
  440. package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
  441. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
  442. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
  443. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
  444. package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
  445. package/src/components/utility/index.ts +1 -0
  446. package/src/mui/Link.ts +2 -0
  447. package/src/utils/index.ts +2 -1
  448. package/src/utils/viewport.ts +65 -0
@@ -0,0 +1,311 @@
1
+ import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
2
+ import CloseIcon from '@mui/icons-material/Close';
3
+ import {
4
+ Box,
5
+ CircularProgress,
6
+ DialogActions,
7
+ DialogContent,
8
+ DialogTitle,
9
+ IconButton,
10
+ Skeleton,
11
+ styled,
12
+ Typography,
13
+ } from '@mui/material';
14
+ import type { FC, ReactNode } from 'react';
15
+ import React from 'react';
16
+ import { safeAreaBottom } from '../../../utils/viewport';
17
+ import {
18
+ loadingOverlayStyles,
19
+ modalContentStyles,
20
+ titleLeftStyles,
21
+ titleRightStyles,
22
+ titleStyles,
23
+ } from './StackedModal.styles';
24
+
25
+ const StyledDialogTitle = styled(DialogTitle, {
26
+ shouldForwardProp: (prop) => prop !== 'rtl',
27
+ })<{ rtl?: boolean }>(({ theme, rtl }) => titleStyles(theme, rtl));
28
+
29
+ const DialogTitleLeft = styled(Box)(({ theme }) => titleLeftStyles(theme));
30
+ const DialogTitleRight = styled(Box)(({ theme }) => titleRightStyles(theme));
31
+ const LoadingOverlay = styled(Box)(({ theme }) => loadingOverlayStyles(theme));
32
+
33
+ /**
34
+ * The padded content wrapper callers put inside a StackedModal. The explicit
35
+ * `typeof DialogContent` annotation keeps its type nameable across package
36
+ * boundaries (TS2742) now that it is re-exported from the barrel.
37
+ */
38
+ export const StackedModalContent: typeof DialogContent = styled(DialogContent)(({ theme }) =>
39
+ modalContentStyles(theme),
40
+ ) as typeof DialogContent;
41
+
42
+ /** Sub-element test IDs derive from the modal's own, or stay off when it has none. */
43
+ export const testId = (base: string | undefined, suffix: string): string | undefined =>
44
+ base ? `${base}-${suffix}` : undefined;
45
+
46
+ /**
47
+ * A wrapper marking the subtree that should render as modal actions — the
48
+ * StackedModal pulls it out of `children` and places it by device.
49
+ */
50
+ export const StackedModalActions: FC<{ children?: ReactNode }> = ({ children }) => <>{children}</>;
51
+
52
+ /** Separates the `StackedModalActions` subtree from the rest of the content. */
53
+ const splitModalChildren = (children: ReactNode): { content: ReactNode; actions: ReactNode } => {
54
+ let actions: ReactNode = null;
55
+
56
+ React.Children.forEach(children, (child) => {
57
+ if (React.isValidElement<{ children?: ReactNode }>(child) && child.type === StackedModalActions) {
58
+ actions = child.props.children;
59
+ }
60
+ });
61
+
62
+ const content = React.Children.toArray(children).filter(
63
+ (child) => !(React.isValidElement(child) && child.type === StackedModalActions),
64
+ );
65
+
66
+ return { content, actions };
67
+ };
68
+
69
+ /**
70
+ * Works out what renders where: a `StackedModalActions` child wins over the
71
+ * `actions` prop, and on phones those actions move out of the header into a
72
+ * pinned bottom bar.
73
+ */
74
+ export const resolveModalContent = (
75
+ children: ReactNode,
76
+ actions: ReactNode,
77
+ isMobile: boolean,
78
+ ): {
79
+ content: ReactNode;
80
+ modalActions: ReactNode;
81
+ headerActions: ReactNode;
82
+ hasMobileActions: boolean;
83
+ } => {
84
+ const { content, actions: childActions } = splitModalChildren(children);
85
+ const modalActions = childActions ?? actions;
86
+ return {
87
+ content,
88
+ modalActions,
89
+ headerActions: isMobile ? null : modalActions,
90
+ hasMobileActions: Boolean(isMobile && modalActions),
91
+ };
92
+ };
93
+
94
+ /** The panel's own ARIA ids, unless the caller wired it to its own labels. */
95
+ export const modalAriaIds = (
96
+ modalId: string,
97
+ ariaLabelledBy?: string,
98
+ ariaDescribedBy?: string,
99
+ ): { titleId: string; descId: string } => ({
100
+ titleId: ariaLabelledBy || `modal-title-${modalId}`,
101
+ descId: ariaDescribedBy || `modal-desc-${modalId}`,
102
+ });
103
+
104
+ export const ModalLoadingOverlay: FC<{ loadingText?: string; dataTestId?: string }> = ({
105
+ loadingText,
106
+ dataTestId,
107
+ }) => (
108
+ <LoadingOverlay data-testid={testId(dataTestId, 'loading-overlay')}>
109
+ <CircularProgress size={40} data-testid={testId(dataTestId, 'loading-spinner')} />
110
+ {loadingText && (
111
+ <Typography variant="body2" sx={{ mt: 2 }} data-testid={testId(dataTestId, 'loading-text')}>
112
+ {loadingText}
113
+ </Typography>
114
+ )}
115
+ </LoadingOverlay>
116
+ );
117
+
118
+ interface ModalHeaderProps {
119
+ titleId: string;
120
+ navigationTitle?: ReactNode;
121
+ /** Deeper than the first panel, so the leading button goes back instead of closing. */
122
+ canGoBack: boolean;
123
+ onBack: () => void;
124
+ onClose: () => void;
125
+ /** Renders the bar without its ✕ — the panel's content owns the dismiss. */
126
+ hideClose?: boolean;
127
+ /** Header actions — desktop only; on phones they move to the footer. */
128
+ headerActions?: ReactNode;
129
+ rtl?: boolean;
130
+ dataTestId?: string;
131
+ }
132
+
133
+ /**
134
+ * The bar's leading control: back at depth ≥2, otherwise close — and nothing at
135
+ * all when the panel's content carries its own ✕ (`hideClose`).
136
+ */
137
+ const HeaderLeadingButton: FC<
138
+ Pick<ModalHeaderProps, 'canGoBack' | 'onBack' | 'onClose' | 'hideClose' | 'rtl' | 'dataTestId'>
139
+ > = ({ canGoBack, onBack, onClose, hideClose, rtl, dataTestId }) => {
140
+ if (canGoBack) {
141
+ return (
142
+ <IconButton
143
+ edge="start"
144
+ color="inherit"
145
+ onClick={onBack}
146
+ aria-label="go back"
147
+ size="small"
148
+ sx={{ transform: rtl ? 'rotate(180deg)' : 'none' }}
149
+ data-testid={testId(dataTestId, 'back-button')}
150
+ >
151
+ <ChevronLeftIcon />
152
+ </IconButton>
153
+ );
154
+ }
155
+ if (hideClose) return null;
156
+ return (
157
+ <IconButton
158
+ edge="start"
159
+ color="inherit"
160
+ onClick={onClose}
161
+ aria-label="close"
162
+ size="small"
163
+ data-testid={testId(dataTestId, 'close-button')}
164
+ >
165
+ <CloseIcon />
166
+ </IconButton>
167
+ );
168
+ };
169
+
170
+ export const ModalHeader: FC<ModalHeaderProps> = ({
171
+ titleId,
172
+ navigationTitle,
173
+ canGoBack,
174
+ onBack,
175
+ onClose,
176
+ hideClose,
177
+ headerActions,
178
+ rtl,
179
+ dataTestId,
180
+ }) => (
181
+ <StyledDialogTitle id={titleId} rtl={rtl} data-testid={testId(dataTestId, 'header')}>
182
+ <DialogTitleLeft>
183
+ <HeaderLeadingButton
184
+ canGoBack={canGoBack}
185
+ onBack={onBack}
186
+ onClose={onClose}
187
+ hideClose={hideClose}
188
+ rtl={rtl}
189
+ dataTestId={dataTestId}
190
+ />
191
+ {navigationTitle && (
192
+ <Typography
193
+ variant="h6"
194
+ component="h2"
195
+ noWrap
196
+ sx={{ ml: canGoBack || !hideClose ? 1 : 0 }}
197
+ data-testid={testId(dataTestId, 'title')}
198
+ >
199
+ {navigationTitle}
200
+ </Typography>
201
+ )}
202
+ </DialogTitleLeft>
203
+ <DialogTitleRight data-testid={testId(dataTestId, 'header-actions')}>
204
+ {headerActions}
205
+ </DialogTitleRight>
206
+ </StyledDialogTitle>
207
+ );
208
+
209
+ const ContentSkeleton: FC = () => (
210
+ <Box sx={{ p: 3 }}>
211
+ <Skeleton variant="text" width="60%" height={32} />
212
+ <Skeleton variant="text" width="100%" />
213
+ <Skeleton variant="text" width="100%" />
214
+ <Skeleton variant="rectangular" height={200} sx={{ mt: 2 }} />
215
+ </Box>
216
+ );
217
+
218
+ interface ModalBodyProps {
219
+ descId: string;
220
+ showSkeleton: boolean;
221
+ /** When there is no action bar, the body is what reaches the bottom of the panel. */
222
+ endsPanel: boolean;
223
+ dataTestId?: string;
224
+ children?: ReactNode;
225
+ }
226
+
227
+ export const ModalBody: FC<ModalBodyProps> = ({
228
+ descId,
229
+ showSkeleton,
230
+ endsPanel,
231
+ dataTestId,
232
+ children,
233
+ }) => (
234
+ <Box
235
+ id={descId}
236
+ sx={{
237
+ position: 'relative',
238
+ flex: 1,
239
+ overflow: 'auto',
240
+ // iOS momentum scrolling, and no scroll-chaining to the page behind —
241
+ // without `contain`, an overscroll at the end of the list rubber-bands the
242
+ // whole panel and springs back before the last row can be tapped.
243
+ WebkitOverflowScrolling: 'touch',
244
+ overscrollBehavior: 'contain',
245
+ // The content itself ends the panel when there is no action bar, so it has
246
+ // to clear the home indicator on its own.
247
+ ...(endsPanel ? safeAreaBottom(0) : {}),
248
+ }}
249
+ data-testid={testId(dataTestId, 'content')}
250
+ >
251
+ {showSkeleton ? <ContentSkeleton /> : children}
252
+ </Box>
253
+ );
254
+
255
+ /** The phone-only pinned action bar; on desktop the actions live in the header. */
256
+ export const ModalFooter: FC<{ dataTestId?: string; children?: ReactNode }> = ({
257
+ dataTestId,
258
+ children,
259
+ }) => (
260
+ <DialogActions
261
+ sx={{
262
+ borderTop: (theme) => `1px solid ${theme.palette.divider}`,
263
+ padding: 2,
264
+ // Never let the action row sit under the iOS home indicator.
265
+ flexShrink: 0,
266
+ ...safeAreaBottom(16),
267
+ }}
268
+ data-testid={testId(dataTestId, 'footer')}
269
+ >
270
+ {children}
271
+ </DialogActions>
272
+ );
273
+
274
+ interface PanelContentsProps extends ModalHeaderProps {
275
+ showSkeleton: boolean;
276
+ loadingText?: string;
277
+ descId: string;
278
+ content: ReactNode;
279
+ /** The resolved actions, already placed in the header or destined for the footer. */
280
+ modalActions: ReactNode;
281
+ hasMobileActions: boolean;
282
+ }
283
+
284
+ /** Everything inside the sliding panel: the loading veil, header, body and action bar. */
285
+ export const ModalPanelContents: FC<PanelContentsProps> = ({
286
+ showSkeleton,
287
+ loadingText,
288
+ descId,
289
+ content,
290
+ modalActions,
291
+ hasMobileActions,
292
+ ...header
293
+ }) => (
294
+ <>
295
+ {showSkeleton && (
296
+ <ModalLoadingOverlay loadingText={loadingText} dataTestId={header.dataTestId} />
297
+ )}
298
+ <ModalHeader {...header} />
299
+ <ModalBody
300
+ descId={descId}
301
+ showSkeleton={showSkeleton}
302
+ endsPanel={!hasMobileActions}
303
+ dataTestId={header.dataTestId}
304
+ >
305
+ {content}
306
+ </ModalBody>
307
+ {hasMobileActions && (
308
+ <ModalFooter dataTestId={header.dataTestId}>{modalActions}</ModalFooter>
309
+ )}
310
+ </>
311
+ );
@@ -1,18 +1,16 @@
1
- import {
2
- Add as AddIcon,
3
- CheckCircle as CheckCircleIcon,
4
- CloudUpload as CloudUploadIcon,
5
- Delete as DeleteIcon,
6
- Download as DownloadIcon,
7
- Edit as EditIcon,
8
- FilterList as FilterListIcon,
9
- Info as InfoIcon,
10
- MoreVert as MoreVertIcon,
11
- Save as SaveIcon,
12
- Search as SearchIcon,
13
- Settings as SettingsIcon,
14
- Share as ShareIcon,
15
- } from '@mui/icons-material';
1
+ import AddIcon from '@mui/icons-material/Add';
2
+ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
3
+ import CloudUploadIcon from '@mui/icons-material/CloudUpload';
4
+ import DeleteIcon from '@mui/icons-material/Delete';
5
+ import DownloadIcon from '@mui/icons-material/Download';
6
+ import EditIcon from '@mui/icons-material/Edit';
7
+ import FilterListIcon from '@mui/icons-material/FilterList';
8
+ import InfoIcon from '@mui/icons-material/Info';
9
+ import MoreVertIcon from '@mui/icons-material/MoreVert';
10
+ import SaveIcon from '@mui/icons-material/Save';
11
+ import SearchIcon from '@mui/icons-material/Search';
12
+ import SettingsIcon from '@mui/icons-material/Settings';
13
+ import ShareIcon from '@mui/icons-material/Share';
16
14
  import {
17
15
  Alert,
18
16
  Avatar,
@@ -0,0 +1,193 @@
1
+ import { alpha } from '@mui/material';
2
+ import type { CSSObject, Theme } from '@mui/material/styles';
3
+ import { dynamicViewportHeight } from '../../../utils/viewport';
4
+ import type { ModalPanelRole, PanelMaxWidth } from './StackedModal.types';
5
+
6
+ /** Props that drive the panel's look but must not reach the DOM. */
7
+ export interface PanelStyleProps {
8
+ modalRole?: ModalPanelRole;
9
+ isAnimating?: boolean;
10
+ glass?: boolean;
11
+ rtl?: boolean;
12
+ customMaxWidth?: PanelMaxWidth;
13
+ }
14
+
15
+ /** Style-only props, filtered out before they can land on a DOM node. */
16
+ export const STYLE_ONLY_PROPS = ['modalRole', 'isAnimating', 'glass', 'rtl', 'customMaxWidth'];
17
+
18
+ /** MUI breakpoint names mapped to the pixel width they cap the panel at. */
19
+ const MAX_WIDTH_PX: Record<Exclude<PanelMaxWidth, false>, number> = {
20
+ xs: 444,
21
+ sm: 600,
22
+ md: 960,
23
+ lg: 1280,
24
+ xl: 1920,
25
+ };
26
+
27
+ const BACKDROP_BY_ROLE: Partial<Record<ModalPanelRole, string>> = {
28
+ secondary: 'rgba(0, 0, 0, 0.3)',
29
+ background: 'rgba(0, 0, 0, 0.1)',
30
+ };
31
+
32
+ const ANIMATION_BY_ROLE: Partial<Record<ModalPanelRole, string>> = {
33
+ secondary: 'expandModal 300ms ease-in-out forwards',
34
+ primary: 'contractModal 300ms ease-in-out forwards',
35
+ };
36
+
37
+ // Animation endpoints use the common lg width (60vw); the role styles set the
38
+ // exact per-breakpoint width once the animation settles.
39
+ const KEYFRAMES: CSSObject = {
40
+ '@keyframes expandModal': {
41
+ from: { width: '60vw', transform: 'translateX(0)' },
42
+ to: { width: '100vw', transform: 'translateX(0)' },
43
+ },
44
+ '@keyframes contractModal': {
45
+ from: { width: '100vw', transform: 'translateX(0)' },
46
+ to: { width: '60vw', transform: 'translateX(0)' },
47
+ },
48
+ };
49
+
50
+ const cap = (customMaxWidth?: PanelMaxWidth): number | null =>
51
+ customMaxWidth ? MAX_WIDTH_PX[customMaxWidth] : null;
52
+
53
+ /** One breakpoint's width: the viewport share, held under the optional px cap. */
54
+ const panelWidth = (share: string, capPx: number | null): CSSObject =>
55
+ capPx
56
+ ? { width: `min(${share}, ${capPx}px)`, maxWidth: `${capPx}px` }
57
+ : { width: share, maxWidth: share };
58
+
59
+ const backdropStyles = (modalRole?: ModalPanelRole): CSSObject => ({
60
+ backgroundColor: (modalRole && BACKDROP_BY_ROLE[modalRole]) ?? 'rgba(0, 0, 0, 0.5)',
61
+ backdropFilter: modalRole === 'primary' ? 'blur(4px)' : 'none',
62
+ });
63
+
64
+ /**
65
+ * The top panel is viewport-aware and narrows as the screen grows: full width on
66
+ * mobile, 80vw on tablet/small desktop, 60vw on regular desktops (lg up —
67
+ * including ~1080p/1440p/1080-wide), and 40vw only on ultra-wide screens
68
+ * (≥2200px) so the receding panel stays visible on huge monitors. A `maxWidth`
69
+ * prop, when given, caps it further.
70
+ */
71
+ const primaryPanelStyles = (theme: Theme, capPx: number | null): CSSObject => ({
72
+ [theme.breakpoints.down('sm')]: panelWidth('100%', capPx),
73
+ [theme.breakpoints.between('sm', 'lg')]: panelWidth('80vw', capPx),
74
+ [theme.breakpoints.up('lg')]: panelWidth('60vw', capPx),
75
+ '@media (min-width:2200px)': panelWidth('40vw', capPx),
76
+ });
77
+
78
+ /** Panels below the top one expand to full width, producing the GTM stacking effect. */
79
+ const secondaryPanelStyles = (): CSSObject => ({
80
+ width: '100vw !important',
81
+ maxWidth: '100vw !important',
82
+ right: '0 !important',
83
+ top: '0 !important',
84
+ ...dynamicViewportHeight('height', 'maxHeight'),
85
+ borderRadius: '0 !important',
86
+ opacity: 0.95,
87
+ transform: 'scale(1)',
88
+ });
89
+
90
+ const rolePanelStyles = (theme: Theme, role: ModalPanelRole | undefined, capPx: number | null): CSSObject => {
91
+ if (role === 'primary') return primaryPanelStyles(theme, capPx);
92
+ if (role === 'secondary') return secondaryPanelStyles();
93
+ // Background modals stay mounted but hidden, for performance.
94
+ if (role === 'background') return { display: 'none' };
95
+ return {};
96
+ };
97
+
98
+ const glassStyles = (theme: Theme, glass?: boolean, role?: ModalPanelRole): CSSObject =>
99
+ glass && role === 'primary'
100
+ ? {
101
+ backgroundColor: alpha(theme.palette.background.paper, 0.85),
102
+ backdropFilter: 'blur(10px)',
103
+ WebkitBackdropFilter: 'blur(10px)',
104
+ border: `1px solid ${alpha(theme.palette.divider, 0.18)}`,
105
+ }
106
+ : {};
107
+
108
+ const animationStyles = (isAnimating?: boolean, role?: ModalPanelRole): CSSObject =>
109
+ isAnimating ? { animation: (role && ANIMATION_BY_ROLE[role]) ?? 'none' } : {};
110
+
111
+ const panelBaseStyles = (theme: Theme): CSSObject => ({
112
+ margin: 0,
113
+ position: 'fixed',
114
+ right: 0,
115
+ top: 0,
116
+ // Pinned to the DYNAMIC viewport: on iOS a `100vh` panel runs underneath the
117
+ // browser toolbar, which parks the tail of the scroll area (the submit row)
118
+ // out of reach. See `dynamicViewportHeight`.
119
+ ...dynamicViewportHeight('height', 'maxHeight'),
120
+ borderRadius: 0,
121
+ willChange: 'transform, width, border-radius',
122
+ transition: theme.transitions.create(
123
+ ['width', 'max-width', 'border-radius', 'transform', 'opacity'],
124
+ { duration: 300, easing: theme.transitions.easing.easeInOut },
125
+ ),
126
+ });
127
+
128
+ const panelStyles = (theme: Theme, props: PanelStyleProps): CSSObject => {
129
+ const capPx = cap(props.customMaxWidth);
130
+ return {
131
+ ...panelBaseStyles(theme),
132
+ ...rolePanelStyles(theme, props.modalRole, capPx),
133
+ ...glassStyles(theme, props.glass, props.modalRole),
134
+ ...animationStyles(props.isAnimating, props.modalRole),
135
+ };
136
+ };
137
+
138
+ /** The full rule set for the sliding panel's Dialog root. */
139
+ export const dialogRootStyles = (theme: Theme, props: PanelStyleProps): CSSObject => ({
140
+ direction: props.rtl ? 'rtl' : 'ltr',
141
+ '& .MuiBackdrop-root': backdropStyles(props.modalRole),
142
+ '& .MuiDialog-container': { alignItems: 'flex-start', justifyContent: 'flex-end' },
143
+ '& .MuiDialog-paper': panelStyles(theme, props),
144
+ ...KEYFRAMES,
145
+ });
146
+
147
+ export const titleStyles = (theme: Theme, rtl?: boolean): CSSObject => ({
148
+ display: 'flex',
149
+ alignItems: 'center',
150
+ justifyContent: 'space-between',
151
+ padding: theme.spacing(2, 2.5),
152
+ borderBottom: `1px solid ${theme.palette.divider}`,
153
+ direction: rtl ? 'rtl' : 'ltr',
154
+ });
155
+
156
+ export const titleLeftStyles = (theme: Theme): CSSObject => ({
157
+ display: 'flex',
158
+ alignItems: 'center',
159
+ gap: theme.spacing(1.5),
160
+ flex: 1,
161
+ });
162
+
163
+ export const titleRightStyles = (theme: Theme): CSSObject => ({
164
+ display: 'flex',
165
+ alignItems: 'center',
166
+ gap: theme.spacing(1),
167
+ });
168
+
169
+ export const loadingOverlayStyles = (theme: Theme): CSSObject => ({
170
+ position: 'absolute',
171
+ top: 0,
172
+ left: 0,
173
+ right: 0,
174
+ bottom: 0,
175
+ display: 'flex',
176
+ flexDirection: 'column',
177
+ alignItems: 'center',
178
+ justifyContent: 'center',
179
+ backgroundColor: alpha(theme.palette.background.paper, 0.8),
180
+ zIndex: 9999,
181
+ });
182
+
183
+ export const modalContentStyles = (theme: Theme): CSSObject => ({
184
+ padding: theme.spacing(3),
185
+ // MUI's DialogContent defaults to `overflow-y: auto`, but inside a panel it is
186
+ // NOT the element that scrolls — ModalBody above it is, and this box always
187
+ // ends up exactly as tall as its own content. A scroll container that never
188
+ // scrolls is still the containing block for every `position: sticky`
189
+ // descendant, so a sticky header anchored here gets zero travel and rides the
190
+ // content out of view: sticky, and pinned to nothing. Handing the overflow
191
+ // back to ModalBody makes the panel's own scroller the anchor.
192
+ overflowY: 'visible',
193
+ });