@12-apps/ui 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/components-catalog.md +14 -0
  2. package/package.json +42 -27
  3. package/src/__tests__/data-grid.test.tsx +125 -0
  4. package/src/__tests__/package-wiring.test.ts +12 -8
  5. package/src/__tests__/social-login-button.test.tsx +5 -5
  6. package/src/__tests__/viewport.test.ts +50 -0
  7. package/src/charts/index.ts +8 -0
  8. package/src/components/data-display/Alert/Alert.md +1 -1
  9. package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
  10. package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
  11. package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
  12. package/src/components/data-display/Alert/Alert.tsx +135 -328
  13. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
  14. package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
  15. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
  16. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
  17. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
  18. package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
  19. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
  20. package/src/components/data-display/Avatar/Avatar.tsx +154 -450
  21. package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
  22. package/src/components/data-display/Badge/Badge.animations.ts +67 -0
  23. package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
  24. package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
  25. package/src/components/data-display/Badge/Badge.styles.ts +261 -0
  26. package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
  27. package/src/components/data-display/Badge/Badge.tsx +151 -557
  28. package/src/components/data-display/Badge/Badge.variants.ts +106 -0
  29. package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
  30. package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
  31. package/src/components/data-display/Banner/Banner.styles.ts +120 -0
  32. package/src/components/data-display/Banner/Banner.tsx +179 -224
  33. package/src/components/data-display/Chart/Chart.md +48 -1
  34. package/src/components/data-display/Chart/Chart.tsx +82 -500
  35. package/src/components/data-display/Chart/Chart.types.ts +2 -0
  36. package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
  37. package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
  38. package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
  39. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
  40. package/src/components/data-display/Chart/SpecChart.tsx +53 -0
  41. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
  42. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
  43. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
  44. package/src/components/data-display/Chart/chart-format.ts +26 -0
  45. package/src/components/data-display/Chart/chart-internals.ts +148 -0
  46. package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
  47. package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
  48. package/src/components/data-display/Chart/chart-spec.ts +171 -0
  49. package/src/components/data-display/Chart/index.ts +30 -0
  50. package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
  51. package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
  52. package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
  53. package/src/components/data-display/Chip/Chip.tsx +31 -94
  54. package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
  55. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
  56. package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
  57. package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
  58. package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
  59. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
  60. package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
  61. package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
  62. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
  63. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
  64. package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
  65. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
  66. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
  67. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
  68. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
  69. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
  70. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
  71. package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
  72. package/src/components/data-display/DataViews/base-card.tsx +278 -0
  73. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
  74. package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
  75. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
  76. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
  77. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
  78. package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
  79. package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
  80. package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
  81. package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
  82. package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
  83. package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
  84. package/src/components/data-display/DataViews/data-views-types.ts +312 -0
  85. package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
  86. package/src/components/data-display/DataViews/index.ts +33 -0
  87. package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
  88. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
  89. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
  90. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
  91. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
  92. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
  93. package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
  94. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
  95. package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
  98. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
  99. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
  100. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
  101. package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
  102. package/src/components/data-display/LazyImage/LazyImage.md +1 -1
  103. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
  104. package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
  105. package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
  106. package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
  107. package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
  108. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
  109. package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
  110. package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
  111. package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
  112. package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
  113. package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
  114. package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
  115. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
  116. package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
  117. package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
  118. package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
  119. package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
  120. package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
  121. package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
  122. package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
  123. package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
  124. package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
  125. package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
  126. package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
  127. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
  128. package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
  129. package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
  130. package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
  131. package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
  132. package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
  133. package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
  134. package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
  135. package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
  136. package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
  137. package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
  138. package/src/components/data-display/Progress/Progress.styles.ts +101 -0
  139. package/src/components/data-display/Progress/Progress.tsx +185 -213
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
  142. package/src/components/data-display/StatCard/StatCard.md +117 -0
  143. package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
  144. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
  145. package/src/components/data-display/StatCard/StatCard.tsx +236 -0
  146. package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
  147. package/src/components/data-display/StatCard/index.ts +7 -0
  148. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
  149. package/src/components/data-display/Stepper/Stepper.tsx +1 -1
  150. package/src/components/data-display/Table/Table.helpers.ts +31 -0
  151. package/src/components/data-display/Table/Table.hooks.ts +161 -0
  152. package/src/components/data-display/Table/Table.stories.tsx +3 -1
  153. package/src/components/data-display/Table/Table.styles.ts +223 -0
  154. package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
  155. package/src/components/data-display/Table/Table.tsx +291 -748
  156. package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
  157. package/src/components/data-display/Table/TableParts.tsx +298 -0
  158. package/src/components/data-display/Table/TableStates.tsx +21 -0
  159. package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
  160. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
  161. package/src/components/data-display/Timeline/Timeline.tsx +23 -284
  162. package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
  163. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
  164. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
  165. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
  166. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
  167. package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
  168. package/src/components/data-display/index.ts +1 -0
  169. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
  170. package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
  171. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
  172. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
  173. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
  174. package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
  175. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
  176. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
  177. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
  178. package/src/components/feedback/ConfirmAction/index.ts +16 -0
  179. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
  180. package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
  181. package/src/components/feedback/Dialog/Dialog.tsx +26 -1
  182. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
  183. package/src/components/feedback/Modal/Modal.md +1 -1
  184. package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
  185. package/src/components/feedback/Sonner/Sonner.tsx +104 -288
  186. package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
  187. package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
  188. package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
  189. package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
  190. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
  191. package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
  192. package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
  193. package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
  194. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
  195. package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
  196. package/src/components/feedback/Toast/Toast.tsx +92 -81
  197. package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
  198. package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
  199. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
  200. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
  201. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
  202. package/src/components/feedback/index.ts +1 -0
  203. package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
  204. package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
  205. package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
  206. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
  207. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
  208. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
  209. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
  210. package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
  211. package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
  212. package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
  213. package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
  214. package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
  215. package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
  216. package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
  217. package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
  218. package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
  219. package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
  220. package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
  221. package/src/components/form/Button/Button.helpers.ts +36 -0
  222. package/src/components/form/Button/Button.stories.tsx +4 -1
  223. package/src/components/form/Button/Button.styles.ts +225 -0
  224. package/src/components/form/Button/Button.test.stories.tsx +25 -21
  225. package/src/components/form/Button/Button.tsx +45 -252
  226. package/src/components/form/Calendar/Calendar.dates.ts +100 -0
  227. package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
  228. package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
  229. package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
  230. package/src/components/form/Calendar/Calendar.selection.ts +156 -0
  231. package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
  232. package/src/components/form/Calendar/Calendar.tsx +63 -551
  233. package/src/components/form/Calendar/Calendar.types.ts +16 -0
  234. package/src/components/form/Calendar/CalendarDay.tsx +127 -0
  235. package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
  236. package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
  237. package/src/components/form/CepField/CepField.md +138 -0
  238. package/src/components/form/CepField/CepField.stories.tsx +138 -0
  239. package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
  240. package/src/components/form/CepField/CepField.tsx +211 -0
  241. package/src/components/form/CepField/CepField.types.ts +73 -0
  242. package/src/components/form/CepField/index.ts +2 -0
  243. package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
  244. package/src/components/form/Checkbox/Checkbox.tsx +19 -16
  245. package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
  246. package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
  247. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
  248. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
  249. package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
  250. package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
  251. package/src/components/form/Command/Command.hooks.ts +207 -0
  252. package/src/components/form/Command/Command.parts.tsx +58 -0
  253. package/src/components/form/Command/Command.styles.ts +83 -0
  254. package/src/components/form/Command/Command.tsx +61 -270
  255. package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
  256. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
  257. package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
  258. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
  259. package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
  260. package/src/components/form/HeaderButton/index.ts +2 -0
  261. package/src/components/form/Input/Input.stories.tsx +5 -1
  262. package/src/components/form/Input/Input.styles.ts +176 -0
  263. package/src/components/form/Input/Input.test.stories.tsx +30 -23
  264. package/src/components/form/Input/Input.tsx +71 -211
  265. package/src/components/form/Input/Input.types.ts +11 -0
  266. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
  267. package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
  268. package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
  269. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
  270. package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
  271. package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
  272. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
  273. package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
  274. package/src/components/form/PhoneInput/countries.ts +54 -0
  275. package/src/components/form/PhoneInput/phone.ts +47 -0
  276. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
  277. package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
  278. package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
  279. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
  280. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
  281. package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
  282. package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
  283. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
  284. package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
  285. package/src/components/form/Select/Select.test.stories.tsx +35 -27
  286. package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
  287. package/src/components/form/Switch/Switch.md +2 -1
  288. package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
  289. package/src/components/form/Textarea/Textarea.styles.ts +143 -0
  290. package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
  291. package/src/components/form/Textarea/Textarea.tsx +114 -535
  292. package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
  293. package/src/components/form/Toggle/Toggle.styles.ts +211 -0
  294. package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
  295. package/src/components/form/Toggle/Toggle.tsx +10 -185
  296. package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
  297. package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
  298. package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
  299. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
  300. package/src/components/form/UploadButton/UploadButton.tsx +76 -305
  301. package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
  302. package/src/components/form/index.ts +1 -0
  303. package/src/components/form/total-form/Fields/CepField.tsx +143 -0
  304. package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
  305. package/src/components/form/total-form/Fields/index.ts +4 -0
  306. package/src/components/form/total-form/FormContainer.tsx +3 -3
  307. package/src/components/form/total-form/SubmitButton.tsx +25 -2
  308. package/src/components/form/total-form/total-form.test.tsx +118 -1
  309. package/src/components/layout/Accordion/Accordion.md +1 -1
  310. package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
  311. package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
  312. package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
  313. package/src/components/layout/Accordion/Accordion.tsx +2 -75
  314. package/src/components/layout/Card/Card.helpers.ts +30 -0
  315. package/src/components/layout/Card/Card.stories.tsx +9 -11
  316. package/src/components/layout/Card/Card.styles.ts +182 -0
  317. package/src/components/layout/Card/Card.test.stories.tsx +46 -46
  318. package/src/components/layout/Card/Card.tsx +24 -241
  319. package/src/components/layout/CardGrid/CardGrid.md +96 -0
  320. package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
  321. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
  322. package/src/components/layout/CardGrid/index.ts +2 -0
  323. package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
  324. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
  325. package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
  326. package/src/components/layout/Container/Container.test.stories.tsx +11 -16
  327. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
  328. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
  329. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
  330. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
  331. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
  332. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
  333. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
  334. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
  335. package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
  336. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
  337. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
  338. package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
  339. package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
  340. package/src/components/layout/Dashboard/index.ts +2 -1
  341. package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
  342. package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
  343. package/src/components/layout/Drawer/Drawer.tsx +67 -53
  344. package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
  345. package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
  346. package/src/components/layout/Resizable/Resizable.tsx +38 -153
  347. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
  348. package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
  349. package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
  350. package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
  351. package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
  352. package/src/components/layout/Separator/Separator.styles.ts +128 -0
  353. package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
  354. package/src/components/layout/Separator/Separator.tsx +6 -132
  355. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
  356. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
  357. package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
  358. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
  359. package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
  360. package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
  361. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
  362. package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
  363. package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
  364. package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
  365. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
  366. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
  367. package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
  368. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
  369. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
  370. package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
  371. package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
  372. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
  373. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
  374. package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
  375. package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
  376. package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
  377. package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
  378. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
  379. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
  380. package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
  381. package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
  382. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
  383. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
  384. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
  385. package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
  386. package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
  387. package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
  388. package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
  389. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
  390. package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
  391. package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
  392. package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
  393. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
  394. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
  395. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
  396. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
  397. package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
  398. package/src/components/navigation/Pagination/Pagination.md +2 -1
  399. package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
  400. package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
  401. package/src/components/navigation/Pagination/Pagination.tsx +178 -313
  402. package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
  403. package/src/components/navigation/Tabs/Tabs.md +3 -1
  404. package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
  405. package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
  406. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
  407. package/src/components/navigation/Tabs/Tabs.tsx +192 -361
  408. package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
  409. package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
  410. package/src/components/typography/Code/Code.test.stories.tsx +5 -5
  411. package/src/components/typography/Code/Code.tsx +74 -49
  412. package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
  413. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
  414. package/src/components/typography/Text/Text.tsx +84 -77
  415. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
  416. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
  417. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
  418. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
  419. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
  420. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
  421. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
  422. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
  423. package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
  424. package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
  425. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
  426. package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
  427. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
  428. package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
  429. package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
  430. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
  431. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
  432. package/src/components/utility/InstallPrompt/index.ts +10 -0
  433. package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
  434. package/src/components/utility/Transition/Transition.helpers.ts +40 -0
  435. package/src/components/utility/Transition/Transition.tsx +17 -68
  436. package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
  437. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
  438. package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
  439. package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
  440. package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
  441. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
  442. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
  443. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
  444. package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
  445. package/src/components/utility/index.ts +1 -0
  446. package/src/mui/Link.ts +2 -0
  447. package/src/utils/index.ts +2 -1
  448. package/src/utils/viewport.ts +65 -0
@@ -1,31 +1,18 @@
1
- import {
2
- alpha,
3
- CircularProgress,
4
- InputAdornment,
5
- keyframes,
6
- styled,
7
- TextField,
8
- } from '@mui/material';
1
+ import { CircularProgress, InputAdornment, styled, TextField } from '@mui/material';
9
2
  import React from 'react';
10
3
 
4
+ import {
5
+ filledStyles,
6
+ floatingLabelStyles,
7
+ glowStyles,
8
+ inputBaseStyles,
9
+ muiVariantFor,
10
+ outlinedStyles,
11
+ pulseStyles,
12
+ SIZE_MAP,
13
+ } from './Input.styles';
11
14
  import type { InputProps } from './Input.types';
12
15
 
13
- // Define pulse animation
14
- const pulseAnimation = keyframes`
15
- 0% {
16
- box-shadow: 0 0 0 0 currentColor;
17
- opacity: 1;
18
- }
19
- 70% {
20
- box-shadow: 0 0 0 10px currentColor;
21
- opacity: 0;
22
- }
23
- 100% {
24
- box-shadow: 0 0 0 0 currentColor;
25
- opacity: 0;
26
- }
27
- `;
28
-
29
16
  const StyledTextField = styled(TextField, {
30
17
  shouldForwardProp: (prop) =>
31
18
  !['customVariant', 'floating', 'glow', 'pulse', 'loading'].includes(prop as string),
@@ -39,141 +26,47 @@ const StyledTextField = styled(TextField, {
39
26
  position: 'relative',
40
27
  opacity: loading ? 0.7 : 1,
41
28
 
42
- // Glow effect
43
- ...(glow && {
44
- '& .MuiInputBase-root': {
45
- boxShadow: `0 0 15px ${alpha(theme.palette.primary.main, 0.3)}`,
46
- '&.Mui-focused': {
47
- boxShadow: `0 0 20px ${alpha(theme.palette.primary.main, 0.5)}`,
48
- },
49
- },
50
- }),
51
-
52
- // Pulse animation
53
- ...(pulse && {
54
- '&::after': {
55
- content: '""',
56
- position: 'absolute',
57
- top: '50%',
58
- left: '0',
59
- right: '0',
60
- height: '56px',
61
- transform: 'translateY(-50%)',
62
- borderRadius: theme.spacing(0.5),
63
- backgroundColor: theme.palette.primary.main,
64
- opacity: 0.3,
65
- animation: `${pulseAnimation} 2s infinite`,
66
- pointerEvents: 'none',
67
- zIndex: -1,
68
- },
69
- }),
29
+ ...(glow ? glowStyles(theme) : {}),
30
+ ...(pulse ? pulseStyles(theme) : {}),
31
+ ...(floating ? floatingLabelStyles(theme) : {}),
70
32
 
71
33
  '& .MuiInputBase-root': {
72
34
  transition: 'all 0.3s ease',
73
-
74
- ...(customVariant === 'glass' && {
75
- backgroundColor: alpha(theme.palette.background.paper, 0.1),
76
- backdropFilter: 'blur(20px)',
77
- border: `1px solid ${alpha(theme.palette.divider, 0.2)}`,
78
- '&:hover': {
79
- backgroundColor: alpha(theme.palette.background.paper, 0.15),
80
- borderColor: alpha(theme.palette.primary.main, 0.3),
81
- },
82
- '&.Mui-focused': {
83
- backgroundColor: alpha(theme.palette.background.paper, 0.2),
84
- borderColor: theme.palette.primary.main,
85
- boxShadow: `0 0 0 2px ${alpha(theme.palette.primary.main, 0.1)}`,
86
- },
87
- }),
88
-
89
- ...(customVariant === 'underline' && {
90
- '&:before': {
91
- borderBottomColor: alpha(theme.palette.divider, 0.42),
92
- },
93
- '&:hover:not(.Mui-disabled):before': {
94
- borderBottomColor: theme.palette.primary.main,
95
- },
96
- '&:after': {
97
- borderBottomColor: theme.palette.primary.main,
98
- },
99
- }),
100
-
101
- ...(customVariant === 'gradient' && {
102
- background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.1)}, ${alpha(theme.palette.secondary.main, 0.1)})`,
103
- border: `2px solid transparent`,
104
- backgroundOrigin: 'border-box',
105
- backgroundClip: 'padding-box, border-box',
106
- position: 'relative',
107
- '&::before': {
108
- content: '""',
109
- position: 'absolute',
110
- top: 0,
111
- left: 0,
112
- right: 0,
113
- bottom: 0,
114
- borderRadius: 'inherit',
115
- background: `linear-gradient(135deg, ${theme.palette.primary.main}, ${theme.palette.secondary.main})`,
116
- mask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)',
117
- maskComposite: 'exclude',
118
- padding: '2px',
119
- zIndex: -1,
120
- },
121
- '&:hover': {
122
- background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.15)}, ${alpha(theme.palette.secondary.main, 0.15)})`,
123
- },
124
- '&.Mui-focused': {
125
- background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.2)}, ${alpha(theme.palette.secondary.main, 0.2)})`,
126
- '&::before': {
127
- background: `linear-gradient(135deg, ${theme.palette.primary.dark}, ${theme.palette.secondary.dark})`,
128
- },
129
- },
130
- }),
35
+ ...inputBaseStyles(theme, customVariant),
131
36
  },
132
37
 
133
- ...(floating && {
134
- '& .MuiInputLabel-root': {
135
- transform: 'translate(14px, 16px) scale(1)',
136
- '&.MuiInputLabel-shrink': {
137
- transform: 'translate(14px, -9px) scale(0.75)',
138
- backgroundColor: theme.palette.background.paper,
139
- padding: '0 4px',
140
- },
141
- },
142
- }),
38
+ '& .MuiOutlinedInput-root': outlinedStyles(theme),
39
+ '& .MuiFilledInput-root': filledStyles(theme),
40
+ }));
143
41
 
144
- '& .MuiOutlinedInput-root': {
145
- '& fieldset': {
146
- borderColor: alpha(theme.palette.divider, 0.23),
147
- },
148
- '&:hover fieldset': {
149
- borderColor: theme.palette.primary.main,
150
- },
151
- '&.Mui-focused fieldset': {
152
- borderColor: theme.palette.primary.main,
153
- borderWidth: 2,
154
- },
155
- '&.Mui-error fieldset': {
156
- borderColor: theme.palette.error.main,
157
- },
158
- },
42
+ /** Only one adornment shows at a time: the spinner replaces the caller's while loading. */
43
+ const EndAdornment: React.FC<{ loading: boolean; endAdornment?: React.ReactNode }> = ({
44
+ loading,
45
+ endAdornment,
46
+ }) => {
47
+ if (loading) {
48
+ return (
49
+ <InputAdornment position="end">
50
+ <CircularProgress size={20} />
51
+ </InputAdornment>
52
+ );
53
+ }
159
54
 
160
- '& .MuiFilledInput-root': {
161
- backgroundColor: alpha(theme.palette.action.hover, 0.04),
162
- '&:hover': {
163
- backgroundColor: alpha(theme.palette.action.hover, 0.08),
164
- },
165
- '&.Mui-focused': {
166
- backgroundColor: alpha(theme.palette.action.hover, 0.12),
167
- },
168
- },
169
- }));
55
+ if (!endAdornment) return null;
170
56
 
171
- const sizeMap = {
172
- sm: { size: 'small' as const },
173
- md: { size: 'medium' as const },
174
- lg: { size: 'medium' as const, sx: { '& .MuiInputBase-input': { padding: '16px 14px' } } },
57
+ return <InputAdornment position="end">{endAdornment}</InputAdornment>;
175
58
  };
176
59
 
60
+ /** While loading the field is inert: no clicks, and disabled to assistive tech. */
61
+ const interactionProps = (
62
+ loading: boolean,
63
+ onClick: InputProps['onClick'],
64
+ disabled?: boolean,
65
+ ) => ({
66
+ disabled: loading || disabled,
67
+ onClick: loading ? undefined : onClick,
68
+ });
69
+
177
70
  export const Input = React.forwardRef<HTMLInputElement, InputProps>(
178
71
  (
179
72
  {
@@ -196,68 +89,35 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
196
89
  ...props
197
90
  },
198
91
  ref,
199
- ) => {
200
- const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
201
- onFocus?.(e);
202
- };
203
-
204
- const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
205
- onBlur?.(e);
206
- };
207
-
208
- const muiVariant =
209
- variant === 'glass'
210
- ? 'outlined'
211
- : variant === 'underline'
212
- ? 'standard'
213
- : variant === 'gradient'
214
- ? 'outlined'
215
- : variant;
216
-
217
- const sizeProps = sizeMap[size];
218
-
219
- return (
220
- <StyledTextField
221
- ref={ref}
222
- variant={muiVariant as 'outlined' | 'filled' | 'standard'}
223
- customVariant={variant}
224
- floating={floating}
225
- glow={glow}
226
- pulse={pulse}
227
- loading={loading}
228
- label={label}
229
- error={error}
230
- helperText={helperText}
231
- fullWidth={fullWidth}
232
- disabled={loading || props.disabled}
233
- onClick={!loading ? onClick : undefined}
234
- onFocus={handleFocus}
235
- onBlur={handleBlur}
236
- inputProps={{
237
- 'data-testid': dataTestId,
238
- }}
239
- InputProps={{
240
- startAdornment: startAdornment && (
241
- <InputAdornment position="start">{startAdornment}</InputAdornment>
242
- ),
243
- endAdornment: (
244
- <>
245
- {loading && (
246
- <InputAdornment position="end">
247
- <CircularProgress size={20} />
248
- </InputAdornment>
249
- )}
250
- {!loading && endAdornment && (
251
- <InputAdornment position="end">{endAdornment}</InputAdornment>
252
- )}
253
- </>
254
- ),
255
- }}
256
- {...sizeProps}
257
- {...props}
258
- />
259
- );
260
- },
92
+ ) => (
93
+ <StyledTextField
94
+ ref={ref}
95
+ variant={muiVariantFor(variant)}
96
+ customVariant={variant}
97
+ floating={floating}
98
+ glow={glow}
99
+ pulse={pulse}
100
+ loading={loading}
101
+ label={label}
102
+ error={error}
103
+ helperText={helperText}
104
+ fullWidth={fullWidth}
105
+ {...interactionProps(loading, onClick, props.disabled)}
106
+ onFocus={onFocus}
107
+ onBlur={onBlur}
108
+ inputProps={{
109
+ 'data-testid': dataTestId,
110
+ }}
111
+ InputProps={{
112
+ startAdornment: startAdornment && (
113
+ <InputAdornment position="start">{startAdornment}</InputAdornment>
114
+ ),
115
+ endAdornment: <EndAdornment loading={loading} endAdornment={endAdornment} />,
116
+ }}
117
+ {...SIZE_MAP[size]}
118
+ {...props}
119
+ />
120
+ ),
261
121
  );
262
122
 
263
123
  Input.displayName = 'Input';
@@ -1,3 +1,4 @@
1
+ import type { InputLabelProps as MuiInputLabelProps } from '@mui/material';
1
2
  import type { InputHTMLAttributes, ReactNode } from 'react';
2
3
  import type React from 'react';
3
4
 
@@ -21,4 +22,14 @@ export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
21
22
  onFocus?: React.FocusEventHandler<HTMLInputElement>;
22
23
  onBlur?: React.FocusEventHandler<HTMLInputElement>;
23
24
  'data-testid'?: string;
25
+ /**
26
+ * Props for the floating label. The one that matters is `shrink`: a native
27
+ * `type="date"` (or `time`) input always paints its own `dd/mm/aaaa` hint,
28
+ * empty or not, while the label only floats once the field is focused or
29
+ * filled — so at rest the two overlap and neither reads. `shrink: true`
30
+ * pins the label up. Callers already passed this and it already worked
31
+ * (the component spreads the rest of its props onto the TextField); only
32
+ * the TYPE was missing, so it failed to compile. FUT-729.
33
+ */
34
+ InputLabelProps?: Partial<MuiInputLabelProps>;
24
35
  }
@@ -1,5 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { expect, fn,userEvent, waitFor, within } from 'storybook/test';
2
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
3
3
 
4
4
  import { InputOTP } from './InputOTP';
5
5
 
@@ -168,14 +168,14 @@ export const ScreenReader: Story = {
168
168
  const inputs = canvas.getAllByRole('textbox');
169
169
 
170
170
  // Check that inputs are accessible
171
- inputs.forEach((input) => {
171
+ inputs.forEach(async (input) => {
172
172
  expect(input).toBeInTheDocument();
173
173
  expect(input).toHaveAttribute('maxLength', '1');
174
174
 
175
175
  // Verify inputs can receive focus
176
- input.focus();
177
- expect(input).toHaveFocus();
178
- input.blur();
176
+ await userEvent.click(input);
177
+ await waitFor(() => expect(input).toHaveFocus());
178
+ await input.blur();
179
179
  });
180
180
 
181
181
  // Test ARIA attributes
@@ -260,7 +260,7 @@ export const ResponsiveDesign: Story = {
260
260
 
261
261
  // Test touch interaction
262
262
  await userEvent.click(inputs[0]);
263
- expect(inputs[0]).toHaveFocus();
263
+ await waitFor(() => expect(inputs[0]).toHaveFocus());
264
264
 
265
265
  await userEvent.type(inputs[0], '1');
266
266
  await waitFor(() => {
@@ -334,7 +334,7 @@ export const VisualStates: Story = {
334
334
 
335
335
  // Test focus state
336
336
  await userEvent.click(inputs[3]);
337
- expect(inputs[3]).toHaveFocus();
337
+ await waitFor(() => expect(inputs[3]).toHaveFocus());
338
338
  },
339
339
  };
340
340
 
@@ -350,19 +350,11 @@ export const Performance: Story = {
350
350
  const canvas = within(canvasElement);
351
351
  const inputs = canvas.getAllByRole('textbox');
352
352
 
353
- const startTime = Date.now();
354
-
355
353
  // Rapid input simulation
356
354
  for (let i = 0; i < inputs.length; i++) {
357
355
  await userEvent.type(inputs[i], String(i + 1));
358
356
  }
359
357
 
360
- const endTime = Date.now();
361
- const duration = endTime - startTime;
362
-
363
- // Performance threshold (should complete within 3 seconds)
364
- expect(duration).toBeLessThan(3000);
365
-
366
358
  // Verify all changes were captured
367
359
  expect(args.onChange).toHaveBeenCalledTimes(8);
368
360
  expect(args.onChange).toHaveBeenLastCalledWith('12345678');
@@ -565,8 +557,8 @@ export const TestIDWithDifferentLengths: Story = {
565
557
  }
566
558
 
567
559
  // Verify no extra slots exist
568
- expect(canvas.queryByTestId('short-otp-slot-4')).not.toBeInTheDocument();
569
- expect(canvas.queryByTestId('short-otp-slot-5')).not.toBeInTheDocument();
560
+ await waitFor(() => expect(canvas.queryByTestId('short-otp-slot-4')).not.toBeInTheDocument());
561
+ await waitFor(() => expect(canvas.queryByTestId('short-otp-slot-5')).not.toBeInTheDocument());
570
562
  },
571
563
  };
572
564
 
@@ -174,12 +174,12 @@ export const KeyboardNavigation: Story = {
174
174
  const editButton = canvas.getByRole('button', { name: /edit/i });
175
175
 
176
176
  // Focus the first button explicitly
177
- fileButton.focus();
178
- await expect(fileButton).toHaveFocus();
177
+ await userEvent.click(fileButton);
178
+ await waitFor(() => expect(fileButton).toHaveFocus());
179
179
 
180
180
  // Tab to next button
181
181
  await userEvent.keyboard('{Tab}');
182
- await expect(editButton).toHaveFocus();
182
+ await waitFor(() => expect(editButton).toHaveFocus());
183
183
  });
184
184
 
185
185
  await step('Enter key opens menu', async () => {
@@ -280,7 +280,7 @@ export const FocusManagement: Story = {
280
280
  await step('End content focus', async () => {
281
281
  const notificationBtn = canvas.getByTestId('notifications-btn');
282
282
  await userEvent.click(notificationBtn);
283
- await expect(notificationBtn).toHaveFocus();
283
+ await waitFor(() => expect(notificationBtn).toHaveFocus());
284
284
  });
285
285
  },
286
286
  };
@@ -464,7 +464,6 @@ export const Performance: Story = {
464
464
  const canvas = within(canvasElement);
465
465
 
466
466
  await step('Many items render performance', async () => {
467
- const startTime = Date.now();
468
467
 
469
468
  const firstMenuItem = canvas.getByRole('button', { name: 'Menu Item 1' });
470
469
  await expect(firstMenuItem).toBeInTheDocument();
@@ -477,9 +476,6 @@ export const Performance: Story = {
477
476
  expect(menuItems.length).toBeGreaterThan(0);
478
477
  });
479
478
 
480
- const endTime = Date.now();
481
- const renderTime = endTime - startTime;
482
- expect(renderTime).toBeLessThan(1000);
483
479
  });
484
480
 
485
481
  await step('Menu closes quickly', async () => {
@@ -0,0 +1,117 @@
1
+ import SecurityIcon from '@mui/icons-material/Security';
2
+ import SuccessIcon from '@mui/icons-material/CheckCircle';
3
+ import WarningIcon from '@mui/icons-material/Warning';
4
+ import { Box, Typography } from '@mui/material';
5
+ import React from 'react';
6
+
7
+ import type { PasswordRequirements } from './PasswordStrength.types';
8
+
9
+ export const defaultRequirements: PasswordRequirements = {
10
+ minLength: 8,
11
+ uppercase: true,
12
+ lowercase: true,
13
+ numbers: true,
14
+ special: true,
15
+ };
16
+
17
+
18
+ const SPECIAL_CHARACTERS = /[!@#$%^&*(),.?":{}|<>]/;
19
+ const DEFAULT_MIN_LENGTH = 8;
20
+
21
+ // Points awarded per satisfied requirement.
22
+ const REQUIREMENT_POINTS = {
23
+ length: 20,
24
+ uppercase: 10,
25
+ lowercase: 10,
26
+ numbers: 15,
27
+ special: 15,
28
+ } as const;
29
+
30
+ export type RequirementChecks = Record<keyof typeof REQUIREMENT_POINTS, boolean>;
31
+
32
+ // A requirement that is switched off counts as satisfied. This was previously
33
+ // written out twice — once to score the password and once to render the
34
+ // checklist — so the two could drift.
35
+ export const evaluateRequirements = (
36
+ password: string,
37
+ requirements: PasswordRequirements,
38
+ ): RequirementChecks => {
39
+ if (!password) {
40
+ return { length: false, uppercase: false, lowercase: false, numbers: false, special: false };
41
+ }
42
+
43
+ return {
44
+ length: password.length >= (requirements.minLength || DEFAULT_MIN_LENGTH),
45
+ uppercase: !requirements.uppercase || /[A-Z]/.test(password),
46
+ lowercase: !requirements.lowercase || /[a-z]/.test(password),
47
+ numbers: !requirements.numbers || /\d/.test(password),
48
+ special: !requirements.special || SPECIAL_CHARACTERS.test(password),
49
+ };
50
+ };
51
+
52
+ const lengthBonus = (length: number): number => {
53
+ const base = Math.min(length * 3, 30);
54
+ const over12 = length > 12 ? 10 : 0;
55
+ const over16 = length > 16 ? 10 : 0;
56
+
57
+ return base + over12 + over16;
58
+ };
59
+
60
+ export const calculatePasswordStrength = (
61
+ password: string,
62
+ requirements: PasswordRequirements,
63
+ ): number => {
64
+ if (!password) return 0;
65
+
66
+ const checks = evaluateRequirements(password, requirements);
67
+ const earned = Object.entries(REQUIREMENT_POINTS).reduce(
68
+ (total, [key, points]) => total + (checks[key as keyof RequirementChecks] ? points : 0),
69
+ 0,
70
+ );
71
+
72
+ return Math.min(earned + lengthBonus(password.length), 100);
73
+ };
74
+
75
+ const STRENGTH_LABELS: ReadonlyArray<[number, string]> = [
76
+ [20, 'Very Weak'],
77
+ [40, 'Weak'],
78
+ [60, 'Fair'],
79
+ [80, 'Good'],
80
+ ];
81
+
82
+ export const getStrengthLabel = (strength: number): string =>
83
+ STRENGTH_LABELS.find(([ceiling]) => strength <= ceiling)?.[1] ?? 'Strong';
84
+
85
+ export const getStrengthIcon = (strength: number) => {
86
+ if (strength <= 40) return <WarningIcon />;
87
+ if (strength <= 80) return <SecurityIcon />;
88
+ return <SuccessIcon />;
89
+ };
90
+
91
+ const SUGGESTIONS: ReadonlyArray<[keyof RequirementChecks, string]> = [
92
+ ['length', 'Use at least 8 characters'],
93
+ ['uppercase', 'Add uppercase letters'],
94
+ ['lowercase', 'Add lowercase letters'],
95
+ ['numbers', 'Include numbers'],
96
+ ['special', 'Add special characters'],
97
+ ];
98
+
99
+ export const buildSuggestions = (checks: RequirementChecks): string[] =>
100
+ SUGGESTIONS.filter(([key]) => !checks[key]).map(([, tip]) => tip);
101
+
102
+ // Rendered by PasswordStrength; depends on nothing styled, so it lives beside
103
+ // the pure helpers rather than in the component file.
104
+ export const SuggestionsList: React.FC<{ suggestions: string[] }> = ({ suggestions }) => (
105
+ <Box>
106
+ <Typography variant="caption" color="text.secondary" fontWeight="medium">
107
+ Suggestions:
108
+ </Typography>
109
+ <Box sx={{ mt: 1 }}>
110
+ {suggestions.map((tip) => (
111
+ <Typography key={tip} variant="caption" display="block" color="warning.main" sx={{ ml: 2 }}>
112
+ • {tip}
113
+ </Typography>
114
+ ))}
115
+ </Box>
116
+ </Box>
117
+ );
@@ -1,6 +1,6 @@
1
1
  import { Stack, TextField } from '@mui/material';
2
2
  import type { Meta, StoryObj } from '@storybook/react-vite';
3
- import { userEvent, within, expect } from 'storybook/test';
3
+ import { expect, userEvent, waitFor, within } from 'storybook/test';
4
4
  import React, { useState } from 'react';
5
5
 
6
6
  import { PasswordStrength } from './PasswordStrength';
@@ -98,7 +98,7 @@ export const KeyboardNavigation: Story = {
98
98
 
99
99
  await step('User clears the input', async () => {
100
100
  await userEvent.clear(input);
101
- expect(canvas.queryByText(/Weak|Fair|Good|Strong/i)).not.toBeInTheDocument();
101
+ await waitFor(() => expect(canvas.queryByText(/Weak|Fair|Good|Strong/i)).not.toBeInTheDocument());
102
102
  });
103
103
  },
104
104
  };
@@ -274,7 +274,7 @@ export const EdgeCases: Story = {
274
274
  const emptyContainer = await canvas.findByTestId('empty-password');
275
275
  expect(emptyContainer).toBeInTheDocument();
276
276
  const label = within(emptyContainer).queryByText(/Very Weak|Weak|Fair|Good|Strong/i);
277
- expect(label).not.toBeInTheDocument();
277
+ await waitFor(() => expect(label).not.toBeInTheDocument());
278
278
  });
279
279
 
280
280
  await step('Verify very long password state shows "Strong"', async () => {