@12-apps/ui 1.0.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/components-catalog.md +14 -0
  2. package/package.json +42 -27
  3. package/src/__tests__/data-grid.test.tsx +125 -0
  4. package/src/__tests__/package-wiring.test.ts +12 -8
  5. package/src/__tests__/social-login-button.test.tsx +5 -5
  6. package/src/__tests__/viewport.test.ts +50 -0
  7. package/src/charts/index.ts +8 -0
  8. package/src/components/data-display/Alert/Alert.md +1 -1
  9. package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
  10. package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
  11. package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
  12. package/src/components/data-display/Alert/Alert.tsx +135 -328
  13. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
  14. package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
  15. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
  16. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
  17. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
  18. package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
  19. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
  20. package/src/components/data-display/Avatar/Avatar.tsx +154 -450
  21. package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
  22. package/src/components/data-display/Badge/Badge.animations.ts +67 -0
  23. package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
  24. package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
  25. package/src/components/data-display/Badge/Badge.styles.ts +261 -0
  26. package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
  27. package/src/components/data-display/Badge/Badge.tsx +151 -557
  28. package/src/components/data-display/Badge/Badge.variants.ts +106 -0
  29. package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
  30. package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
  31. package/src/components/data-display/Banner/Banner.styles.ts +120 -0
  32. package/src/components/data-display/Banner/Banner.tsx +179 -224
  33. package/src/components/data-display/Chart/Chart.md +48 -1
  34. package/src/components/data-display/Chart/Chart.tsx +82 -500
  35. package/src/components/data-display/Chart/Chart.types.ts +2 -0
  36. package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
  37. package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
  38. package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
  39. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
  40. package/src/components/data-display/Chart/SpecChart.tsx +53 -0
  41. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
  42. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
  43. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
  44. package/src/components/data-display/Chart/chart-format.ts +26 -0
  45. package/src/components/data-display/Chart/chart-internals.ts +148 -0
  46. package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
  47. package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
  48. package/src/components/data-display/Chart/chart-spec.ts +171 -0
  49. package/src/components/data-display/Chart/index.ts +30 -0
  50. package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
  51. package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
  52. package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
  53. package/src/components/data-display/Chip/Chip.tsx +31 -94
  54. package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
  55. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
  56. package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
  57. package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
  58. package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
  59. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
  60. package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
  61. package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
  62. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
  63. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
  64. package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
  65. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
  66. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
  67. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
  68. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
  69. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
  70. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
  71. package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
  72. package/src/components/data-display/DataViews/base-card.tsx +278 -0
  73. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
  74. package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
  75. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
  76. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
  77. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
  78. package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
  79. package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
  80. package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
  81. package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
  82. package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
  83. package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
  84. package/src/components/data-display/DataViews/data-views-types.ts +312 -0
  85. package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
  86. package/src/components/data-display/DataViews/index.ts +33 -0
  87. package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
  88. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
  89. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
  90. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
  91. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
  92. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
  93. package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
  94. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
  95. package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
  98. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
  99. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
  100. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
  101. package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
  102. package/src/components/data-display/LazyImage/LazyImage.md +1 -1
  103. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
  104. package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
  105. package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
  106. package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
  107. package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
  108. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
  109. package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
  110. package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
  111. package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
  112. package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
  113. package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
  114. package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
  115. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
  116. package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
  117. package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
  118. package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
  119. package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
  120. package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
  121. package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
  122. package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
  123. package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
  124. package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
  125. package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
  126. package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
  127. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
  128. package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
  129. package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
  130. package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
  131. package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
  132. package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
  133. package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
  134. package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
  135. package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
  136. package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
  137. package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
  138. package/src/components/data-display/Progress/Progress.styles.ts +101 -0
  139. package/src/components/data-display/Progress/Progress.tsx +185 -213
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
  142. package/src/components/data-display/StatCard/StatCard.md +117 -0
  143. package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
  144. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
  145. package/src/components/data-display/StatCard/StatCard.tsx +236 -0
  146. package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
  147. package/src/components/data-display/StatCard/index.ts +7 -0
  148. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
  149. package/src/components/data-display/Stepper/Stepper.tsx +1 -1
  150. package/src/components/data-display/Table/Table.helpers.ts +31 -0
  151. package/src/components/data-display/Table/Table.hooks.ts +161 -0
  152. package/src/components/data-display/Table/Table.stories.tsx +3 -1
  153. package/src/components/data-display/Table/Table.styles.ts +223 -0
  154. package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
  155. package/src/components/data-display/Table/Table.tsx +291 -748
  156. package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
  157. package/src/components/data-display/Table/TableParts.tsx +298 -0
  158. package/src/components/data-display/Table/TableStates.tsx +21 -0
  159. package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
  160. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
  161. package/src/components/data-display/Timeline/Timeline.tsx +23 -284
  162. package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
  163. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
  164. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
  165. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
  166. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
  167. package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
  168. package/src/components/data-display/index.ts +1 -0
  169. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
  170. package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
  171. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
  172. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
  173. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
  174. package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
  175. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
  176. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
  177. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
  178. package/src/components/feedback/ConfirmAction/index.ts +16 -0
  179. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
  180. package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
  181. package/src/components/feedback/Dialog/Dialog.tsx +26 -1
  182. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
  183. package/src/components/feedback/Modal/Modal.md +1 -1
  184. package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
  185. package/src/components/feedback/Sonner/Sonner.tsx +104 -288
  186. package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
  187. package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
  188. package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
  189. package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
  190. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
  191. package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
  192. package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
  193. package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
  194. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
  195. package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
  196. package/src/components/feedback/Toast/Toast.tsx +92 -81
  197. package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
  198. package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
  199. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
  200. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
  201. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
  202. package/src/components/feedback/index.ts +1 -0
  203. package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
  204. package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
  205. package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
  206. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
  207. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
  208. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
  209. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
  210. package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
  211. package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
  212. package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
  213. package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
  214. package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
  215. package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
  216. package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
  217. package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
  218. package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
  219. package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
  220. package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
  221. package/src/components/form/Button/Button.helpers.ts +36 -0
  222. package/src/components/form/Button/Button.stories.tsx +4 -1
  223. package/src/components/form/Button/Button.styles.ts +225 -0
  224. package/src/components/form/Button/Button.test.stories.tsx +25 -21
  225. package/src/components/form/Button/Button.tsx +45 -252
  226. package/src/components/form/Calendar/Calendar.dates.ts +100 -0
  227. package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
  228. package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
  229. package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
  230. package/src/components/form/Calendar/Calendar.selection.ts +156 -0
  231. package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
  232. package/src/components/form/Calendar/Calendar.tsx +63 -551
  233. package/src/components/form/Calendar/Calendar.types.ts +16 -0
  234. package/src/components/form/Calendar/CalendarDay.tsx +127 -0
  235. package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
  236. package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
  237. package/src/components/form/CepField/CepField.md +138 -0
  238. package/src/components/form/CepField/CepField.stories.tsx +138 -0
  239. package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
  240. package/src/components/form/CepField/CepField.tsx +211 -0
  241. package/src/components/form/CepField/CepField.types.ts +73 -0
  242. package/src/components/form/CepField/index.ts +2 -0
  243. package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
  244. package/src/components/form/Checkbox/Checkbox.tsx +19 -16
  245. package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
  246. package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
  247. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
  248. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
  249. package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
  250. package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
  251. package/src/components/form/Command/Command.hooks.ts +207 -0
  252. package/src/components/form/Command/Command.parts.tsx +58 -0
  253. package/src/components/form/Command/Command.styles.ts +83 -0
  254. package/src/components/form/Command/Command.tsx +61 -270
  255. package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
  256. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
  257. package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
  258. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
  259. package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
  260. package/src/components/form/HeaderButton/index.ts +2 -0
  261. package/src/components/form/Input/Input.stories.tsx +5 -1
  262. package/src/components/form/Input/Input.styles.ts +176 -0
  263. package/src/components/form/Input/Input.test.stories.tsx +30 -23
  264. package/src/components/form/Input/Input.tsx +71 -211
  265. package/src/components/form/Input/Input.types.ts +11 -0
  266. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
  267. package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
  268. package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
  269. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
  270. package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
  271. package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
  272. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
  273. package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
  274. package/src/components/form/PhoneInput/countries.ts +54 -0
  275. package/src/components/form/PhoneInput/phone.ts +47 -0
  276. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
  277. package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
  278. package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
  279. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
  280. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
  281. package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
  282. package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
  283. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
  284. package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
  285. package/src/components/form/Select/Select.test.stories.tsx +35 -27
  286. package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
  287. package/src/components/form/Switch/Switch.md +2 -1
  288. package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
  289. package/src/components/form/Textarea/Textarea.styles.ts +143 -0
  290. package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
  291. package/src/components/form/Textarea/Textarea.tsx +114 -535
  292. package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
  293. package/src/components/form/Toggle/Toggle.styles.ts +211 -0
  294. package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
  295. package/src/components/form/Toggle/Toggle.tsx +10 -185
  296. package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
  297. package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
  298. package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
  299. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
  300. package/src/components/form/UploadButton/UploadButton.tsx +76 -305
  301. package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
  302. package/src/components/form/index.ts +1 -0
  303. package/src/components/form/total-form/Fields/CepField.tsx +143 -0
  304. package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
  305. package/src/components/form/total-form/Fields/index.ts +4 -0
  306. package/src/components/form/total-form/FormContainer.tsx +3 -3
  307. package/src/components/form/total-form/SubmitButton.tsx +25 -2
  308. package/src/components/form/total-form/total-form.test.tsx +118 -1
  309. package/src/components/layout/Accordion/Accordion.md +1 -1
  310. package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
  311. package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
  312. package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
  313. package/src/components/layout/Accordion/Accordion.tsx +2 -75
  314. package/src/components/layout/Card/Card.helpers.ts +30 -0
  315. package/src/components/layout/Card/Card.stories.tsx +9 -11
  316. package/src/components/layout/Card/Card.styles.ts +182 -0
  317. package/src/components/layout/Card/Card.test.stories.tsx +46 -46
  318. package/src/components/layout/Card/Card.tsx +24 -241
  319. package/src/components/layout/CardGrid/CardGrid.md +96 -0
  320. package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
  321. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
  322. package/src/components/layout/CardGrid/index.ts +2 -0
  323. package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
  324. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
  325. package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
  326. package/src/components/layout/Container/Container.test.stories.tsx +11 -16
  327. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
  328. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
  329. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
  330. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
  331. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
  332. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
  333. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
  334. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
  335. package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
  336. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
  337. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
  338. package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
  339. package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
  340. package/src/components/layout/Dashboard/index.ts +2 -1
  341. package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
  342. package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
  343. package/src/components/layout/Drawer/Drawer.tsx +67 -53
  344. package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
  345. package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
  346. package/src/components/layout/Resizable/Resizable.tsx +38 -153
  347. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
  348. package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
  349. package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
  350. package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
  351. package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
  352. package/src/components/layout/Separator/Separator.styles.ts +128 -0
  353. package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
  354. package/src/components/layout/Separator/Separator.tsx +6 -132
  355. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
  356. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
  357. package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
  358. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
  359. package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
  360. package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
  361. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
  362. package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
  363. package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
  364. package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
  365. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
  366. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
  367. package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
  368. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
  369. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
  370. package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
  371. package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
  372. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
  373. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
  374. package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
  375. package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
  376. package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
  377. package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
  378. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
  379. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
  380. package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
  381. package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
  382. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
  383. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
  384. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
  385. package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
  386. package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
  387. package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
  388. package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
  389. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
  390. package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
  391. package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
  392. package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
  393. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
  394. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
  395. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
  396. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
  397. package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
  398. package/src/components/navigation/Pagination/Pagination.md +2 -1
  399. package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
  400. package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
  401. package/src/components/navigation/Pagination/Pagination.tsx +178 -313
  402. package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
  403. package/src/components/navigation/Tabs/Tabs.md +3 -1
  404. package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
  405. package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
  406. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
  407. package/src/components/navigation/Tabs/Tabs.tsx +192 -361
  408. package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
  409. package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
  410. package/src/components/typography/Code/Code.test.stories.tsx +5 -5
  411. package/src/components/typography/Code/Code.tsx +74 -49
  412. package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
  413. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
  414. package/src/components/typography/Text/Text.tsx +84 -77
  415. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
  416. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
  417. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
  418. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
  419. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
  420. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
  421. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
  422. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
  423. package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
  424. package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
  425. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
  426. package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
  427. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
  428. package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
  429. package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
  430. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
  431. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
  432. package/src/components/utility/InstallPrompt/index.ts +10 -0
  433. package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
  434. package/src/components/utility/Transition/Transition.helpers.ts +40 -0
  435. package/src/components/utility/Transition/Transition.tsx +17 -68
  436. package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
  437. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
  438. package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
  439. package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
  440. package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
  441. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
  442. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
  443. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
  444. package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
  445. package/src/components/utility/index.ts +1 -0
  446. package/src/mui/Link.ts +2 -0
  447. package/src/utils/index.ts +2 -1
  448. package/src/utils/viewport.ts +65 -0
@@ -1,4 +1,5 @@
1
- import { ChevronRight, MoreVert } from '@mui/icons-material';
1
+ import ChevronRight from '@mui/icons-material/ChevronRight';
2
+ import MoreVert from '@mui/icons-material/MoreVert';
2
3
  import {
3
4
  alpha,
4
5
  Box,
@@ -10,10 +11,60 @@ import {
10
11
  Typography,
11
12
  } from '@mui/material';
12
13
  import { styled } from '@mui/material/styles';
14
+ import type { CSSObject, Theme } from '@mui/material/styles';
13
15
  import React, { cloneElement, isValidElement,useRef, useState } from 'react';
14
16
 
15
17
  import type { DropdownMenuItem,DropdownMenuProps } from './DropdownMenu.types';
16
18
 
19
+ // Resolves every light/dark decision once. The inline version repeated
20
+ // `theme.palette.mode === 'dark' ? … : …` nine times, and two of those had the
21
+ // SAME expression on both branches (background.paper, and common.white for the
22
+ // inset highlight) — so they read as mode-dependent while never varying.
23
+ const glassTokens = (theme: Theme) => {
24
+ const isDark = theme.palette.mode === 'dark';
25
+
26
+ return {
27
+ edge: isDark ? theme.palette.common.white : theme.palette.common.black,
28
+ dropShadowAlpha: isDark ? 0.4 : 0.12,
29
+ insetHighlightAlpha: isDark ? 0.2 : 0.8,
30
+ sheenAlpha: isDark ? 0.1 : 0.8,
31
+ };
32
+ };
33
+
34
+ const glassMenuStyles = (theme: Theme): CSSObject => {
35
+ const { edge, dropShadowAlpha, insetHighlightAlpha, sheenAlpha } = glassTokens(theme);
36
+
37
+ return {
38
+ backgroundColor: alpha(theme.palette.background.paper, 0.75),
39
+ backdropFilter: 'blur(24px) saturate(1.8)',
40
+ WebkitBackdropFilter: 'blur(24px) saturate(1.8)', // Safari support
41
+ border: `1px solid ${alpha(edge, 0.12)}`,
42
+ boxShadow: [
43
+ `0 8px 32px ${alpha(theme.palette.common.black, dropShadowAlpha)}`,
44
+ `0 0 0 1px ${alpha(edge, 0.05)}`,
45
+ `inset 0 1px 0 ${alpha(theme.palette.common.white, insetHighlightAlpha)}`,
46
+ ].join(', '),
47
+ // Enhanced glass morphism with subtle gradient overlay
48
+ '&::before': {
49
+ content: '""',
50
+ position: 'absolute',
51
+ top: 0,
52
+ left: 0,
53
+ right: 0,
54
+ bottom: 0,
55
+ background: `linear-gradient(135deg, ${alpha(theme.palette.common.white, sheenAlpha)} 0%, transparent 50%)`,
56
+ borderRadius: 'inherit',
57
+ pointerEvents: 'none',
58
+ zIndex: 1,
59
+ },
60
+ // Ensure content appears above the overlay
61
+ '& .MuiList-root': {
62
+ position: 'relative',
63
+ zIndex: 2,
64
+ },
65
+ };
66
+ };
67
+
17
68
  const StyledMenu = styled(Menu, {
18
69
  shouldForwardProp: (prop) => prop !== 'customVariant' && prop !== 'size',
19
70
  })<{ customVariant?: string; size?: string }>(({ theme, customVariant, size }) => ({
@@ -21,52 +72,7 @@ const StyledMenu = styled(Menu, {
21
72
  minWidth: 180,
22
73
  borderRadius: theme.spacing(1),
23
74
 
24
- ...(customVariant === 'glass' && {
25
- backgroundColor: alpha(
26
- theme.palette.mode === 'dark'
27
- ? theme.palette.background.paper
28
- : theme.palette.background.paper,
29
- 0.75,
30
- ),
31
- backdropFilter: 'blur(24px) saturate(1.8)',
32
- WebkitBackdropFilter: 'blur(24px) saturate(1.8)', // Safari support
33
- border: `1px solid ${alpha(
34
- theme.palette.mode === 'dark' ? theme.palette.common.white : theme.palette.common.black,
35
- 0.12,
36
- )}`,
37
- boxShadow: [
38
- `0 8px 32px ${alpha(theme.palette.common.black, theme.palette.mode === 'dark' ? 0.4 : 0.12)}`,
39
- `0 0 0 1px ${alpha(
40
- theme.palette.mode === 'dark' ? theme.palette.common.white : theme.palette.common.black,
41
- 0.05,
42
- )}`,
43
- `inset 0 1px 0 ${alpha(
44
- theme.palette.mode === 'dark' ? theme.palette.common.white : theme.palette.common.white,
45
- theme.palette.mode === 'dark' ? 0.2 : 0.8,
46
- )}`,
47
- ].join(', '),
48
- // Enhanced glass morphism with subtle gradient overlay
49
- '&::before': {
50
- content: '""',
51
- position: 'absolute',
52
- top: 0,
53
- left: 0,
54
- right: 0,
55
- bottom: 0,
56
- background:
57
- theme.palette.mode === 'dark'
58
- ? `linear-gradient(135deg, ${alpha(theme.palette.common.white, 0.1)} 0%, transparent 50%)`
59
- : `linear-gradient(135deg, ${alpha(theme.palette.common.white, 0.8)} 0%, transparent 50%)`,
60
- borderRadius: 'inherit',
61
- pointerEvents: 'none',
62
- zIndex: 1,
63
- },
64
- // Ensure content appears above the overlay
65
- '& .MuiList-root': {
66
- position: 'relative',
67
- zIndex: 2,
68
- },
69
- }),
75
+ ...(customVariant === 'glass' && glassMenuStyles(theme)),
70
76
 
71
77
  ...(customVariant === 'minimal' && {
72
78
  boxShadow: `0 2px 8px ${alpha(theme.palette.common.black, 0.08)}`,
@@ -164,6 +170,15 @@ const renderMenuItem = (
164
170
  );
165
171
  }
166
172
 
173
+ return renderLeafMenuItem(item, handleItemClick, showIconSpace, size);
174
+ };
175
+
176
+ const renderLeafMenuItem = (
177
+ item: DropdownMenuItem,
178
+ handleItemClick: (item: DropdownMenuItem) => void,
179
+ showIconSpace?: boolean,
180
+ size?: string,
181
+ ) => {
167
182
  const hasIcon = !!item.icon;
168
183
  const hasChildren = item.children && item.children.length > 0;
169
184
 
@@ -187,6 +202,113 @@ const renderMenuItem = (
187
202
  );
188
203
  };
189
204
 
205
+ // Open state and anchor are each either caller-supplied or ours. Resolving both
206
+ // here keeps those four branches out of the render body.
207
+ const resolveMenuState = (
208
+ controlledOpen: boolean | undefined,
209
+ internalOpen: boolean,
210
+ providedAnchorEl: DropdownMenuProps['anchorEl'],
211
+ anchorRef: React.RefObject<HTMLElement | null>,
212
+ ) => {
213
+ const isControlled = controlledOpen !== undefined;
214
+ const open = isControlled ? controlledOpen : internalOpen;
215
+ const anchorEl = providedAnchorEl || anchorRef.current;
216
+
217
+ return { isControlled, open, anchorEl, isOpen: Boolean(anchorEl) && open };
218
+ };
219
+
220
+ // Open/close state is either ours or the caller's; every handler has to respect
221
+ // that, so they are grouped here rather than repeating the isControlled check
222
+ // inline four times in the render.
223
+ const useDropdownHandlers = ({
224
+ isControlled,
225
+ open,
226
+ setInternalOpen,
227
+ onOpen,
228
+ onClose,
229
+ closeOnItemClick,
230
+ anchorRef,
231
+ }: {
232
+ isControlled: boolean;
233
+ open: boolean;
234
+ setInternalOpen: (value: boolean) => void;
235
+ onOpen?: () => void;
236
+ onClose?: () => void;
237
+ closeOnItemClick?: boolean;
238
+ anchorRef: React.RefObject<HTMLElement | null>;
239
+ }) => {
240
+ const handleOpen = () => {
241
+ if (!isControlled) {
242
+ setInternalOpen(true);
243
+ }
244
+ onOpen?.();
245
+ };
246
+
247
+ const handleClose = () => {
248
+ if (!isControlled) {
249
+ setInternalOpen(false);
250
+ }
251
+ onClose?.();
252
+ };
253
+
254
+ const handleItemClick = (item: DropdownMenuItem) => {
255
+ item.onClick?.();
256
+ if (closeOnItemClick && !item.children?.length) {
257
+ handleClose();
258
+ }
259
+ };
260
+
261
+ const handleTriggerClick = (event: React.MouseEvent<HTMLElement>) => {
262
+ if (isControlled) return;
263
+
264
+ if (open) {
265
+ handleClose();
266
+ return;
267
+ }
268
+
269
+ (anchorRef as React.MutableRefObject<HTMLElement>).current = event.currentTarget;
270
+ handleOpen();
271
+ };
272
+
273
+ return { handleClose, handleItemClick, handleTriggerClick };
274
+ };
275
+
276
+ // The trigger is either a caller-supplied element we clone to attach our click
277
+ // handler and ref, arbitrary children we wrap, or the default kebab icon.
278
+ const DropdownTrigger: React.FC<{
279
+ trigger: DropdownMenuProps['trigger'];
280
+ anchorRef: React.RefObject<HTMLElement | null>;
281
+ onTriggerClick: (event: React.MouseEvent<HTMLElement>) => void;
282
+ }> = ({ trigger, anchorRef, onTriggerClick }) => {
283
+ if (isValidElement(trigger)) {
284
+ return cloneElement(
285
+ trigger as React.ReactElement<{
286
+ onClick?: (event: React.MouseEvent<HTMLElement>) => void;
287
+ ref?: React.Ref<HTMLElement>;
288
+ }>,
289
+ { onClick: onTriggerClick, ref: anchorRef },
290
+ );
291
+ }
292
+
293
+ if (trigger) {
294
+ return (
295
+ <Box ref={anchorRef} onClick={onTriggerClick}>
296
+ {trigger}
297
+ </Box>
298
+ );
299
+ }
300
+
301
+ return (
302
+ <Box
303
+ ref={anchorRef}
304
+ onClick={onTriggerClick}
305
+ sx={{ cursor: 'pointer', display: 'inline-flex' }}
306
+ >
307
+ <MoreVert />
308
+ </Box>
309
+ );
310
+ };
311
+
190
312
  export const DropdownMenu = React.forwardRef<HTMLDivElement, DropdownMenuProps>(
191
313
  (
192
314
  {
@@ -209,69 +331,25 @@ export const DropdownMenu = React.forwardRef<HTMLDivElement, DropdownMenuProps>(
209
331
  const [internalOpen, setInternalOpen] = useState(false);
210
332
  const anchorRef = useRef<HTMLElement>(null);
211
333
 
212
- const isControlled = controlledOpen !== undefined;
213
- const open = isControlled ? controlledOpen : internalOpen;
214
- const anchorEl = providedAnchorEl || anchorRef.current;
215
-
216
- const handleOpen = () => {
217
- if (!isControlled) {
218
- setInternalOpen(true);
219
- }
220
- onOpen?.();
221
- };
222
-
223
- const handleClose = () => {
224
- if (!isControlled) {
225
- setInternalOpen(false);
226
- }
227
- onClose?.();
228
- };
229
-
230
- const handleItemClick = (item: DropdownMenuItem) => {
231
- if (item.onClick) {
232
- item.onClick();
233
- }
234
- if (closeOnItemClick && !item.children?.length) {
235
- handleClose();
236
- }
237
- };
238
-
239
- const handleTriggerClick = (event: React.MouseEvent<HTMLElement>) => {
240
- if (!isControlled) {
241
- if (open) {
242
- handleClose();
243
- } else {
244
- (anchorRef as React.MutableRefObject<HTMLElement>).current = event.currentTarget;
245
- handleOpen();
246
- }
247
- }
248
- };
249
-
250
- const triggerElement = trigger ? (
251
- isValidElement(trigger) ? (
252
- cloneElement(
253
- trigger as React.ReactElement<{
254
- onClick?: (event: React.MouseEvent<HTMLElement>) => void;
255
- ref?: React.Ref<HTMLElement>;
256
- }>,
257
- {
258
- onClick: handleTriggerClick,
259
- ref: anchorRef,
260
- }
261
- )
262
- ) : (
263
- <Box ref={anchorRef} onClick={handleTriggerClick}>
264
- {trigger}
265
- </Box>
266
- )
267
- ) : (
268
- <Box
269
- ref={anchorRef}
270
- onClick={handleTriggerClick}
271
- sx={{ cursor: 'pointer', display: 'inline-flex' }}
272
- >
273
- <MoreVert />
274
- </Box>
334
+ const { isControlled, open, anchorEl, isOpen } = resolveMenuState(
335
+ controlledOpen,
336
+ internalOpen,
337
+ providedAnchorEl,
338
+ anchorRef,
339
+ );
340
+
341
+ const { handleClose, handleItemClick, handleTriggerClick } = useDropdownHandlers({
342
+ isControlled,
343
+ open,
344
+ setInternalOpen,
345
+ onOpen,
346
+ onClose,
347
+ closeOnItemClick,
348
+ anchorRef,
349
+ });
350
+
351
+ const triggerElement = (
352
+ <DropdownTrigger trigger={trigger} anchorRef={anchorRef} onTriggerClick={handleTriggerClick} />
275
353
  );
276
354
 
277
355
  return (
@@ -280,7 +358,7 @@ export const DropdownMenu = React.forwardRef<HTMLDivElement, DropdownMenuProps>(
280
358
  <StyledMenu
281
359
  ref={ref}
282
360
  anchorEl={anchorEl}
283
- open={Boolean(anchorEl) && open}
361
+ open={isOpen}
284
362
  onClose={handleClose}
285
363
  customVariant={variant}
286
364
  size={size}
@@ -0,0 +1,66 @@
1
+ import { Box, List, Typography } from '@mui/material';
2
+ import type { FC } from 'react';
3
+ import React from 'react';
4
+
5
+ import { MegaSection } from './NavigationMenu.shell';
6
+ import { slideIn } from './NavigationMenu.styles';
7
+ import type { NavigationMenuItem } from './NavigationMenu.types';
8
+ import { renderMenuItem } from './NavigationMenuItem';
9
+
10
+ const SECTION_TITLE_SX = {
11
+ mb: 2.5,
12
+ color: 'primary.main',
13
+ fontWeight: 600,
14
+ position: 'relative',
15
+ paddingBottom: 1,
16
+ // The short rule under each section heading.
17
+ '&::after': {
18
+ content: '""',
19
+ position: 'absolute',
20
+ bottom: 0,
21
+ left: 0,
22
+ width: '40px',
23
+ height: '3px',
24
+ background: (theme: { palette: { primary: { main: string } } }) =>
25
+ `linear-gradient(90deg, ${theme.palette.primary.main} 0%, transparent 100%)`,
26
+ borderRadius: '2px',
27
+ },
28
+ } as const;
29
+
30
+ export interface NavigationMegaSectionProps {
31
+ section: NavigationMenuItem;
32
+ sectionIndex: number;
33
+ variant?: string;
34
+ size?: string;
35
+ minimal?: boolean;
36
+ }
37
+
38
+ // One column of the mega menu: a heading and its children, each staggered so the
39
+ // grid fills in rather than appearing all at once.
40
+ export const NavigationMegaSection: FC<NavigationMegaSectionProps> = ({
41
+ section,
42
+ sectionIndex,
43
+ variant,
44
+ size,
45
+ minimal,
46
+ }) => (
47
+ <MegaSection>
48
+ <Typography variant="h6" sx={SECTION_TITLE_SX}>
49
+ {section.label}
50
+ </Typography>
51
+ <List sx={{ p: 0 }}>
52
+ {section.children?.map((item, itemIndex) => (
53
+ <Box
54
+ key={item.id}
55
+ sx={{
56
+ animation: `${slideIn} 0.4s ease-out`,
57
+ animationDelay: `${sectionIndex * 0.1 + itemIndex * 0.05}s`,
58
+ animationFillMode: 'both',
59
+ }}
60
+ >
61
+ {renderMenuItem(item, variant, size, false, minimal, 0)}
62
+ </Box>
63
+ ))}
64
+ </List>
65
+ </MegaSection>
66
+ );
@@ -56,7 +56,9 @@ A flexible and feature-rich navigation menu component that supports horizontal,
56
56
 
57
57
  ```tsx
58
58
  import { NavigationMenu } from '@procurement/ui';
59
- import { Dashboard, ShoppingCart, People } from '@mui/icons-material';
59
+ import Dashboard from '@mui/icons-material/Dashboard';
60
+ import ShoppingCart from '@mui/icons-material/ShoppingCart';
61
+ import People from '@mui/icons-material/People';
60
62
 
61
63
  const items = [
62
64
  {
@@ -129,7 +131,10 @@ function TopNav() {
129
131
 
130
132
  ```tsx
131
133
  import { NavigationMenu } from '@procurement/ui';
132
- import { Home, ShoppingCart, Business, Analytics } from '@mui/icons-material';
134
+ import Home from '@mui/icons-material/Home';
135
+ import ShoppingCart from '@mui/icons-material/ShoppingCart';
136
+ import Business from '@mui/icons-material/Business';
137
+ import Analytics from '@mui/icons-material/Analytics';
133
138
 
134
139
  const horizontalWithDropdowns = [
135
140
  {
@@ -0,0 +1,218 @@
1
+ import { Box, List, ListItemButton } from '@mui/material';
2
+ import { alpha, keyframes, styled } from '@mui/material/styles';
3
+ import type { CSSProperties, PropsWithChildren, ReactNode } from 'react';
4
+ import React from 'react';
5
+
6
+ import { slideIn } from './NavigationMenu.styles';
7
+
8
+ const megaMenuSlide = keyframes`
9
+ from {
10
+ opacity: 0;
11
+ transform: translateY(20px);
12
+ }
13
+ to {
14
+ opacity: 1;
15
+ transform: translateY(0);
16
+ }
17
+ `;
18
+
19
+ // These styled() components stay module-local: their inferred types cannot be
20
+ // named across a module boundary here (TS2742). The plain components exported
21
+ // below are what the layouts import.
22
+ const NavigationContainer = styled(Box, {
23
+ shouldForwardProp: (prop) => !['variant', 'collapsed', 'minimal'].includes(prop as string),
24
+ })<{ variant?: string; collapsed?: boolean; minimal?: boolean }>(({ theme, variant, collapsed, minimal }) => ({
25
+ display: 'flex',
26
+ position: 'relative',
27
+ animation: `${slideIn} 0.4s ease-out`,
28
+ ...(variant === 'horizontal' && {
29
+ flexDirection: 'row',
30
+ alignItems: 'center',
31
+ width: '100%',
32
+ ...(!minimal && {
33
+ background: `linear-gradient(135deg, ${alpha(theme.palette.background.paper, 0.95)} 0%, ${alpha(theme.palette.background.paper, 0.98)} 100%)`,
34
+ backdropFilter: 'blur(10px)',
35
+ borderRadius: theme.spacing(2),
36
+ boxShadow: `0 8px 32px ${alpha(theme.palette.common.black, 0.08)}`,
37
+ }),
38
+ }),
39
+ ...(variant === 'vertical' && {
40
+ flexDirection: 'column',
41
+ width: collapsed ? 80 : 280,
42
+ transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
43
+ height: '100%',
44
+ ...(!minimal && {
45
+ background: `linear-gradient(180deg, ${alpha(theme.palette.background.paper, 0.98)} 0%, ${alpha(theme.palette.background.paper, 0.95)} 100%)`,
46
+ backdropFilter: 'blur(12px)',
47
+ borderRadius: theme.spacing(2),
48
+ boxShadow: `0 12px 40px ${alpha(theme.palette.common.black, 0.1)}`,
49
+ '&::before': {
50
+ content: '""',
51
+ position: 'absolute',
52
+ top: 0,
53
+ left: 0,
54
+ right: 0,
55
+ height: '200px',
56
+ background: `radial-gradient(ellipse at top, ${alpha(theme.palette.primary.main, 0.05)} 0%, transparent 70%)`,
57
+ pointerEvents: 'none',
58
+ },
59
+ }),
60
+ }),
61
+ ...(variant === 'mega' && {
62
+ flexDirection: 'column',
63
+ width: '100%',
64
+ ...(!minimal && {
65
+ background: `linear-gradient(135deg, ${alpha(theme.palette.background.paper, 0.98)} 0%, ${alpha(theme.palette.background.default, 0.95)} 100%)`,
66
+ backdropFilter: 'blur(15px)',
67
+ borderRadius: theme.spacing(3),
68
+ overflow: 'hidden',
69
+ boxShadow: `0 20px 60px ${alpha(theme.palette.common.black, 0.12)}`,
70
+ }),
71
+ }),
72
+ }));
73
+
74
+ const StyledList = styled(List, {
75
+ shouldForwardProp: (prop) => !['variant', 'size'].includes(prop as string),
76
+ })<{ variant?: string; size?: string }>(({ theme, variant }) => ({
77
+ padding: 0,
78
+ width: '100%',
79
+ ...(variant === 'horizontal' && {
80
+ display: 'flex',
81
+ flexDirection: 'row',
82
+ alignItems: 'center',
83
+ }),
84
+ ...(variant === 'mega' && {
85
+ display: 'grid',
86
+ gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
87
+ gap: theme.spacing(2),
88
+ padding: theme.spacing(2),
89
+ }),
90
+ }));
91
+
92
+ const LogoContainer = styled(Box)(({ theme }) => ({
93
+ padding: theme.spacing(2.5),
94
+ marginBottom: theme.spacing(2),
95
+ position: 'relative',
96
+ background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.08)} 0%, ${alpha(theme.palette.primary.dark, 0.04)} 100%)`,
97
+ borderBottom: `2px solid ${alpha(theme.palette.primary.main, 0.2)}`,
98
+ overflow: 'hidden',
99
+
100
+ '&::before': {
101
+ content: '""',
102
+ position: 'absolute',
103
+ top: '-50%',
104
+ right: '-50%',
105
+ width: '200%',
106
+ height: '200%',
107
+ background: `radial-gradient(circle, ${alpha(theme.palette.primary.light, 0.1)} 0%, transparent 70%)`,
108
+ animation: `${slideIn} 1s ease-out`,
109
+ },
110
+
111
+ '& > *': {
112
+ position: 'relative',
113
+ zIndex: 1,
114
+ },
115
+ }));
116
+
117
+ const CollapseButton = styled(ListItemButton)(({ theme }) => ({
118
+ borderRadius: theme.spacing(1.5),
119
+ margin: theme.spacing(1),
120
+ background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.08)} 0%, ${alpha(theme.palette.primary.dark, 0.04)} 100%)`,
121
+ border: `1px solid ${alpha(theme.palette.primary.main, 0.2)}`,
122
+ transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
123
+
124
+ '&:hover': {
125
+ backgroundColor: alpha(theme.palette.primary.main, 0.12),
126
+ transform: 'scale(1.05)',
127
+ boxShadow: `0 6px 20px ${alpha(theme.palette.primary.main, 0.2)}`,
128
+
129
+ '& .MuiListItemIcon-root': {
130
+ transform: 'rotate(180deg)',
131
+ transition: 'transform 0.3s ease',
132
+ },
133
+ },
134
+
135
+ '&:active': {
136
+ transform: 'scale(0.98)',
137
+ },
138
+ }));
139
+
140
+ const MegaMenuSection = styled(Box)(({ theme }) => ({
141
+ padding: theme.spacing(3),
142
+ borderRadius: theme.spacing(2),
143
+ background: `linear-gradient(145deg, ${theme.palette.background.paper} 0%, ${alpha(theme.palette.background.default, 0.9)} 100%)`,
144
+ boxShadow: `0 10px 30px ${alpha(theme.palette.common.black, 0.08)}`,
145
+ border: `1px solid ${alpha(theme.palette.divider, 0.08)}`,
146
+ position: 'relative',
147
+ overflow: 'hidden',
148
+ animation: `${megaMenuSlide} 0.5s ease-out`,
149
+ animationFillMode: 'both',
150
+
151
+ '&::before': {
152
+ content: '""',
153
+ position: 'absolute',
154
+ top: 0,
155
+ left: 0,
156
+ right: 0,
157
+ height: '3px',
158
+ background: `linear-gradient(90deg, ${theme.palette.primary.main} 0%, ${theme.palette.primary.light} 50%, ${theme.palette.primary.main} 100%)`,
159
+ backgroundSize: '200% 100%',
160
+ animation: 'shimmer 3s ease-in-out infinite',
161
+ },
162
+
163
+ '@keyframes shimmer': {
164
+ '0%': {
165
+ backgroundPosition: '200% 0',
166
+ },
167
+ '100%': {
168
+ backgroundPosition: '-200% 0',
169
+ },
170
+ },
171
+
172
+ '&:hover': {
173
+ transform: 'translateY(-4px)',
174
+ boxShadow: `0 15px 40px ${alpha(theme.palette.common.black, 0.12)}`,
175
+ transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
176
+ },
177
+
178
+ '&:nth-of-type(1)': { animationDelay: '0.1s' },
179
+ '&:nth-of-type(2)': { animationDelay: '0.2s' },
180
+ '&:nth-of-type(3)': { animationDelay: '0.3s' },
181
+ '&:nth-of-type(4)': { animationDelay: '0.4s' },
182
+ }));
183
+
184
+ export interface NavigationShellProps extends PropsWithChildren {
185
+ variant?: string;
186
+ collapsed?: boolean;
187
+ minimal?: boolean;
188
+ className?: string;
189
+ style?: CSSProperties;
190
+ }
191
+
192
+ export const NavigationShell = React.forwardRef<HTMLDivElement, NavigationShellProps>(
193
+ ({ children, ...props }, ref) => (
194
+ <NavigationContainer ref={ref} {...props}>
195
+ {children}
196
+ </NavigationContainer>
197
+ ),
198
+ );
199
+
200
+ NavigationShell.displayName = 'NavigationShell';
201
+
202
+ export const LogoBar: React.FC<PropsWithChildren> = ({ children }) => (
203
+ <LogoContainer>{children}</LogoContainer>
204
+ );
205
+
206
+ export const MenuList: React.FC<PropsWithChildren<{ variant?: string; size?: string }>> = ({
207
+ children,
208
+ ...props
209
+ }) => <StyledList {...props}>{children}</StyledList>;
210
+
211
+ export const CollapseToggle: React.FC<PropsWithChildren<{ onClick: () => void }>> = ({
212
+ children,
213
+ onClick,
214
+ }) => <CollapseButton onClick={onClick}>{children}</CollapseButton>;
215
+
216
+ export const MegaSection: React.FC<{ children: ReactNode }> = ({ children }) => (
217
+ <MegaMenuSection>{children}</MegaMenuSection>
218
+ );