@12-apps/ui 1.0.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/components-catalog.md +14 -0
  2. package/package.json +42 -27
  3. package/src/__tests__/data-grid.test.tsx +125 -0
  4. package/src/__tests__/package-wiring.test.ts +12 -8
  5. package/src/__tests__/social-login-button.test.tsx +5 -5
  6. package/src/__tests__/viewport.test.ts +50 -0
  7. package/src/charts/index.ts +8 -0
  8. package/src/components/data-display/Alert/Alert.md +1 -1
  9. package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
  10. package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
  11. package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
  12. package/src/components/data-display/Alert/Alert.tsx +135 -328
  13. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
  14. package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
  15. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
  16. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
  17. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
  18. package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
  19. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
  20. package/src/components/data-display/Avatar/Avatar.tsx +154 -450
  21. package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
  22. package/src/components/data-display/Badge/Badge.animations.ts +67 -0
  23. package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
  24. package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
  25. package/src/components/data-display/Badge/Badge.styles.ts +261 -0
  26. package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
  27. package/src/components/data-display/Badge/Badge.tsx +151 -557
  28. package/src/components/data-display/Badge/Badge.variants.ts +106 -0
  29. package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
  30. package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
  31. package/src/components/data-display/Banner/Banner.styles.ts +120 -0
  32. package/src/components/data-display/Banner/Banner.tsx +179 -224
  33. package/src/components/data-display/Chart/Chart.md +48 -1
  34. package/src/components/data-display/Chart/Chart.tsx +82 -500
  35. package/src/components/data-display/Chart/Chart.types.ts +2 -0
  36. package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
  37. package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
  38. package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
  39. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
  40. package/src/components/data-display/Chart/SpecChart.tsx +53 -0
  41. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
  42. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
  43. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
  44. package/src/components/data-display/Chart/chart-format.ts +26 -0
  45. package/src/components/data-display/Chart/chart-internals.ts +148 -0
  46. package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
  47. package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
  48. package/src/components/data-display/Chart/chart-spec.ts +171 -0
  49. package/src/components/data-display/Chart/index.ts +30 -0
  50. package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
  51. package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
  52. package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
  53. package/src/components/data-display/Chip/Chip.tsx +31 -94
  54. package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
  55. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
  56. package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
  57. package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
  58. package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
  59. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
  60. package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
  61. package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
  62. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
  63. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
  64. package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
  65. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
  66. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
  67. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
  68. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
  69. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
  70. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
  71. package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
  72. package/src/components/data-display/DataViews/base-card.tsx +278 -0
  73. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
  74. package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
  75. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
  76. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
  77. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
  78. package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
  79. package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
  80. package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
  81. package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
  82. package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
  83. package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
  84. package/src/components/data-display/DataViews/data-views-types.ts +312 -0
  85. package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
  86. package/src/components/data-display/DataViews/index.ts +33 -0
  87. package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
  88. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
  89. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
  90. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
  91. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
  92. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
  93. package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
  94. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
  95. package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
  98. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
  99. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
  100. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
  101. package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
  102. package/src/components/data-display/LazyImage/LazyImage.md +1 -1
  103. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
  104. package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
  105. package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
  106. package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
  107. package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
  108. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
  109. package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
  110. package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
  111. package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
  112. package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
  113. package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
  114. package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
  115. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
  116. package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
  117. package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
  118. package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
  119. package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
  120. package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
  121. package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
  122. package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
  123. package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
  124. package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
  125. package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
  126. package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
  127. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
  128. package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
  129. package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
  130. package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
  131. package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
  132. package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
  133. package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
  134. package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
  135. package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
  136. package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
  137. package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
  138. package/src/components/data-display/Progress/Progress.styles.ts +101 -0
  139. package/src/components/data-display/Progress/Progress.tsx +185 -213
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
  142. package/src/components/data-display/StatCard/StatCard.md +117 -0
  143. package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
  144. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
  145. package/src/components/data-display/StatCard/StatCard.tsx +236 -0
  146. package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
  147. package/src/components/data-display/StatCard/index.ts +7 -0
  148. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
  149. package/src/components/data-display/Stepper/Stepper.tsx +1 -1
  150. package/src/components/data-display/Table/Table.helpers.ts +31 -0
  151. package/src/components/data-display/Table/Table.hooks.ts +161 -0
  152. package/src/components/data-display/Table/Table.stories.tsx +3 -1
  153. package/src/components/data-display/Table/Table.styles.ts +223 -0
  154. package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
  155. package/src/components/data-display/Table/Table.tsx +291 -748
  156. package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
  157. package/src/components/data-display/Table/TableParts.tsx +298 -0
  158. package/src/components/data-display/Table/TableStates.tsx +21 -0
  159. package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
  160. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
  161. package/src/components/data-display/Timeline/Timeline.tsx +23 -284
  162. package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
  163. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
  164. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
  165. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
  166. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
  167. package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
  168. package/src/components/data-display/index.ts +1 -0
  169. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
  170. package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
  171. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
  172. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
  173. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
  174. package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
  175. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
  176. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
  177. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
  178. package/src/components/feedback/ConfirmAction/index.ts +16 -0
  179. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
  180. package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
  181. package/src/components/feedback/Dialog/Dialog.tsx +26 -1
  182. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
  183. package/src/components/feedback/Modal/Modal.md +1 -1
  184. package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
  185. package/src/components/feedback/Sonner/Sonner.tsx +104 -288
  186. package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
  187. package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
  188. package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
  189. package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
  190. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
  191. package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
  192. package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
  193. package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
  194. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
  195. package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
  196. package/src/components/feedback/Toast/Toast.tsx +92 -81
  197. package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
  198. package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
  199. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
  200. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
  201. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
  202. package/src/components/feedback/index.ts +1 -0
  203. package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
  204. package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
  205. package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
  206. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
  207. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
  208. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
  209. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
  210. package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
  211. package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
  212. package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
  213. package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
  214. package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
  215. package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
  216. package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
  217. package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
  218. package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
  219. package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
  220. package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
  221. package/src/components/form/Button/Button.helpers.ts +36 -0
  222. package/src/components/form/Button/Button.stories.tsx +4 -1
  223. package/src/components/form/Button/Button.styles.ts +225 -0
  224. package/src/components/form/Button/Button.test.stories.tsx +25 -21
  225. package/src/components/form/Button/Button.tsx +45 -252
  226. package/src/components/form/Calendar/Calendar.dates.ts +100 -0
  227. package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
  228. package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
  229. package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
  230. package/src/components/form/Calendar/Calendar.selection.ts +156 -0
  231. package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
  232. package/src/components/form/Calendar/Calendar.tsx +63 -551
  233. package/src/components/form/Calendar/Calendar.types.ts +16 -0
  234. package/src/components/form/Calendar/CalendarDay.tsx +127 -0
  235. package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
  236. package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
  237. package/src/components/form/CepField/CepField.md +138 -0
  238. package/src/components/form/CepField/CepField.stories.tsx +138 -0
  239. package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
  240. package/src/components/form/CepField/CepField.tsx +211 -0
  241. package/src/components/form/CepField/CepField.types.ts +73 -0
  242. package/src/components/form/CepField/index.ts +2 -0
  243. package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
  244. package/src/components/form/Checkbox/Checkbox.tsx +19 -16
  245. package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
  246. package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
  247. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
  248. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
  249. package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
  250. package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
  251. package/src/components/form/Command/Command.hooks.ts +207 -0
  252. package/src/components/form/Command/Command.parts.tsx +58 -0
  253. package/src/components/form/Command/Command.styles.ts +83 -0
  254. package/src/components/form/Command/Command.tsx +61 -270
  255. package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
  256. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
  257. package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
  258. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
  259. package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
  260. package/src/components/form/HeaderButton/index.ts +2 -0
  261. package/src/components/form/Input/Input.stories.tsx +5 -1
  262. package/src/components/form/Input/Input.styles.ts +176 -0
  263. package/src/components/form/Input/Input.test.stories.tsx +30 -23
  264. package/src/components/form/Input/Input.tsx +71 -211
  265. package/src/components/form/Input/Input.types.ts +11 -0
  266. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
  267. package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
  268. package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
  269. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
  270. package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
  271. package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
  272. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
  273. package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
  274. package/src/components/form/PhoneInput/countries.ts +54 -0
  275. package/src/components/form/PhoneInput/phone.ts +47 -0
  276. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
  277. package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
  278. package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
  279. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
  280. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
  281. package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
  282. package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
  283. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
  284. package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
  285. package/src/components/form/Select/Select.test.stories.tsx +35 -27
  286. package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
  287. package/src/components/form/Switch/Switch.md +2 -1
  288. package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
  289. package/src/components/form/Textarea/Textarea.styles.ts +143 -0
  290. package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
  291. package/src/components/form/Textarea/Textarea.tsx +114 -535
  292. package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
  293. package/src/components/form/Toggle/Toggle.styles.ts +211 -0
  294. package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
  295. package/src/components/form/Toggle/Toggle.tsx +10 -185
  296. package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
  297. package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
  298. package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
  299. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
  300. package/src/components/form/UploadButton/UploadButton.tsx +76 -305
  301. package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
  302. package/src/components/form/index.ts +1 -0
  303. package/src/components/form/total-form/Fields/CepField.tsx +143 -0
  304. package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
  305. package/src/components/form/total-form/Fields/index.ts +4 -0
  306. package/src/components/form/total-form/FormContainer.tsx +3 -3
  307. package/src/components/form/total-form/SubmitButton.tsx +25 -2
  308. package/src/components/form/total-form/total-form.test.tsx +118 -1
  309. package/src/components/layout/Accordion/Accordion.md +1 -1
  310. package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
  311. package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
  312. package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
  313. package/src/components/layout/Accordion/Accordion.tsx +2 -75
  314. package/src/components/layout/Card/Card.helpers.ts +30 -0
  315. package/src/components/layout/Card/Card.stories.tsx +9 -11
  316. package/src/components/layout/Card/Card.styles.ts +182 -0
  317. package/src/components/layout/Card/Card.test.stories.tsx +46 -46
  318. package/src/components/layout/Card/Card.tsx +24 -241
  319. package/src/components/layout/CardGrid/CardGrid.md +96 -0
  320. package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
  321. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
  322. package/src/components/layout/CardGrid/index.ts +2 -0
  323. package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
  324. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
  325. package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
  326. package/src/components/layout/Container/Container.test.stories.tsx +11 -16
  327. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
  328. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
  329. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
  330. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
  331. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
  332. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
  333. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
  334. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
  335. package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
  336. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
  337. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
  338. package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
  339. package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
  340. package/src/components/layout/Dashboard/index.ts +2 -1
  341. package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
  342. package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
  343. package/src/components/layout/Drawer/Drawer.tsx +67 -53
  344. package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
  345. package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
  346. package/src/components/layout/Resizable/Resizable.tsx +38 -153
  347. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
  348. package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
  349. package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
  350. package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
  351. package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
  352. package/src/components/layout/Separator/Separator.styles.ts +128 -0
  353. package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
  354. package/src/components/layout/Separator/Separator.tsx +6 -132
  355. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
  356. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
  357. package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
  358. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
  359. package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
  360. package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
  361. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
  362. package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
  363. package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
  364. package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
  365. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
  366. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
  367. package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
  368. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
  369. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
  370. package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
  371. package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
  372. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
  373. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
  374. package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
  375. package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
  376. package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
  377. package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
  378. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
  379. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
  380. package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
  381. package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
  382. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
  383. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
  384. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
  385. package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
  386. package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
  387. package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
  388. package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
  389. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
  390. package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
  391. package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
  392. package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
  393. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
  394. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
  395. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
  396. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
  397. package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
  398. package/src/components/navigation/Pagination/Pagination.md +2 -1
  399. package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
  400. package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
  401. package/src/components/navigation/Pagination/Pagination.tsx +178 -313
  402. package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
  403. package/src/components/navigation/Tabs/Tabs.md +3 -1
  404. package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
  405. package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
  406. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
  407. package/src/components/navigation/Tabs/Tabs.tsx +192 -361
  408. package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
  409. package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
  410. package/src/components/typography/Code/Code.test.stories.tsx +5 -5
  411. package/src/components/typography/Code/Code.tsx +74 -49
  412. package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
  413. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
  414. package/src/components/typography/Text/Text.tsx +84 -77
  415. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
  416. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
  417. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
  418. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
  419. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
  420. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
  421. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
  422. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
  423. package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
  424. package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
  425. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
  426. package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
  427. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
  428. package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
  429. package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
  430. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
  431. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
  432. package/src/components/utility/InstallPrompt/index.ts +10 -0
  433. package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
  434. package/src/components/utility/Transition/Transition.helpers.ts +40 -0
  435. package/src/components/utility/Transition/Transition.tsx +17 -68
  436. package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
  437. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
  438. package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
  439. package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
  440. package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
  441. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
  442. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
  443. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
  444. package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
  445. package/src/components/utility/index.ts +1 -0
  446. package/src/mui/Link.ts +2 -0
  447. package/src/utils/index.ts +2 -1
  448. package/src/utils/viewport.ts +65 -0
@@ -0,0 +1,127 @@
1
+ import type { SxProps, Theme } from '@mui/material';
2
+ import { Box } from '@mui/material';
3
+ import type { FC } from 'react';
4
+ import React from 'react';
5
+
6
+ import type { DayRenderArgs } from './Calendar.types';
7
+
8
+ const CELL_SIZE = 40;
9
+
10
+ interface DayState extends DayRenderArgs {
11
+ outside: boolean;
12
+ focused: boolean;
13
+ }
14
+
15
+ // Order matters: these land on the element in the order listed.
16
+ const CLASS_FLAGS: Array<[keyof DayState, string]> = [
17
+ ['selected', 'selected'],
18
+ ['inRange', 'in-range'],
19
+ ['rangeStart', 'range-start'],
20
+ ['rangeEnd', 'range-end'],
21
+ ['disabled', 'disabled'],
22
+ ['today', 'today'],
23
+ ['outside', 'outside'],
24
+ ['hovered', 'hovered'],
25
+ ['focused', 'focused'],
26
+ ];
27
+
28
+ const dayClassNames = (state: DayState, custom?: string): string =>
29
+ [
30
+ 'calendar-day',
31
+ ...CLASS_FLAGS.filter(([flag]) => state[flag]).map(([, name]) => name),
32
+ ...(custom ? [custom] : []),
33
+ ].join(' ');
34
+
35
+ const isEndpoint = (day: DayRenderArgs): boolean =>
36
+ day.selected || day.rangeStart || day.rangeEnd;
37
+
38
+ const backgroundFor = (day: DayRenderArgs): string => {
39
+ if (isEndpoint(day)) return 'primary.main';
40
+ if (day.inRange || day.hovered) return 'primary.light';
41
+ return 'transparent';
42
+ };
43
+
44
+ const colorFor = (day: DayRenderArgs, visible: boolean): string => {
45
+ if (isEndpoint(day)) return 'primary.contrastText';
46
+ if (day.disabled) return 'text.disabled';
47
+ // Outside days that are switched off still occupy the grid, they just have
48
+ // nothing to show.
49
+ if (!visible) return 'transparent';
50
+ return 'text.primary';
51
+ };
52
+
53
+ const hoverBackgroundFor = (day: DayRenderArgs): string | undefined => {
54
+ if (day.disabled) return undefined;
55
+ return day.selected ? 'primary.dark' : 'action.hover';
56
+ };
57
+
58
+ const dayCellSx = (day: DayRenderArgs, visible: boolean): SxProps<Theme> => ({
59
+ display: 'flex',
60
+ alignItems: 'center',
61
+ justifyContent: 'center',
62
+ width: CELL_SIZE,
63
+ height: CELL_SIZE,
64
+ border: 'none',
65
+ borderRadius: 1,
66
+ cursor: day.disabled ? 'not-allowed' : 'pointer',
67
+ backgroundColor: backgroundFor(day),
68
+ color: colorFor(day, visible),
69
+ opacity: !day.inCurrentMonth && visible ? 0.5 : 1,
70
+ fontWeight: day.today ? 'bold' : 'normal',
71
+ '&:hover': {
72
+ backgroundColor: hoverBackgroundFor(day),
73
+ },
74
+ '&:focus': {
75
+ outline: '2px solid',
76
+ outlineColor: 'primary.main',
77
+ outlineOffset: 1,
78
+ },
79
+ });
80
+
81
+ export interface CalendarDayProps {
82
+ day: DayRenderArgs;
83
+ focused: boolean;
84
+ showOutsideDays: boolean;
85
+ dayClassName?: (args: DayRenderArgs) => string;
86
+ onSelect: (date: Date) => void;
87
+ onHover: (date: Date) => void;
88
+ onHoverEnd: () => void;
89
+ }
90
+
91
+ export const CalendarDay: FC<CalendarDayProps> = ({
92
+ day,
93
+ focused,
94
+ showOutsideDays,
95
+ dayClassName,
96
+ onSelect,
97
+ onHover,
98
+ onHoverEnd,
99
+ }) => {
100
+ const visible = day.inCurrentMonth || showOutsideDays;
101
+ const state: DayState = { ...day, outside: !day.inCurrentMonth, focused };
102
+
103
+ return (
104
+ <Box
105
+ component="button"
106
+ role="gridcell"
107
+ tabIndex={focused ? 0 : -1}
108
+ aria-selected={day.selected}
109
+ aria-disabled={day.disabled}
110
+ aria-current={day.today ? 'date' : undefined}
111
+ className={dayClassNames(state, dayClassName?.(day))}
112
+ data-testid={`calendar-date-${day.date.getDate()}`}
113
+ onClick={() => onSelect(day.date)}
114
+ onMouseEnter={() => onHover(day.date)}
115
+ onMouseLeave={onHoverEnd}
116
+ sx={dayCellSx(day, visible)}
117
+ >
118
+ {day.selected && (
119
+ <Box component="span" data-testid="calendar-selected-date" sx={{ display: 'none' }} />
120
+ )}
121
+ {day.today && (
122
+ <Box component="span" data-testid="calendar-today" sx={{ display: 'none' }} />
123
+ )}
124
+ {visible ? day.date.getDate() : ''}
125
+ </Box>
126
+ );
127
+ };
@@ -0,0 +1,52 @@
1
+ import type { FC } from 'react';
2
+ import React from 'react';
3
+
4
+ import { isSameDay } from './Calendar.dates';
5
+ import { buildDayArgs } from './Calendar.selection';
6
+ import type { CalendarProps, DateRange, MonthMatrixDay, SelectionMode } from './Calendar.types';
7
+ import { CalendarDay } from './CalendarDay';
8
+
9
+ // Everything a cell needs that is the same for every cell in the calendar.
10
+ export interface DayCellContext {
11
+ selectionMode: SelectionMode;
12
+ value: Date | null;
13
+ range: DateRange;
14
+ hoveredDate: Date | null;
15
+ focusedDate: Date;
16
+ today: Date;
17
+ showOutsideDays: boolean;
18
+ isDisabled: (date: Date) => boolean;
19
+ renderDay?: CalendarProps['renderDay'];
20
+ dayClassName?: CalendarProps['dayClassName'];
21
+ onSelect: (date: Date) => void;
22
+ onHover: (date: Date) => void;
23
+ onHoverEnd: () => void;
24
+ }
25
+
26
+ export const CalendarDayCell: FC<DayCellContext & { day: MonthMatrixDay }> = ({
27
+ day,
28
+ focusedDate,
29
+ showOutsideDays,
30
+ renderDay,
31
+ dayClassName,
32
+ onSelect,
33
+ onHover,
34
+ onHoverEnd,
35
+ ...context
36
+ }) => {
37
+ const args = buildDayArgs({ day, ...context });
38
+
39
+ if (renderDay) return <>{renderDay(args)}</>;
40
+
41
+ return (
42
+ <CalendarDay
43
+ day={args}
44
+ focused={isSameDay(args.date, focusedDate)}
45
+ showOutsideDays={showOutsideDays}
46
+ dayClassName={dayClassName}
47
+ onSelect={onSelect}
48
+ onHover={onHover}
49
+ onHoverEnd={onHoverEnd}
50
+ />
51
+ );
52
+ };
@@ -0,0 +1,128 @@
1
+ import ChevronLeft from '@mui/icons-material/ChevronLeft';
2
+ import ChevronRight from '@mui/icons-material/ChevronRight';
3
+ import { Box, IconButton, Typography } from '@mui/material';
4
+ import type { FC } from 'react';
5
+ import React from 'react';
6
+
7
+ import { getMonthName } from './Calendar.dates';
8
+ import type { CalendarProps, MonthMatrix } from './Calendar.types';
9
+ import type { DayCellContext } from './CalendarDayCell';
10
+ import { CalendarDayCell } from './CalendarDayCell';
11
+
12
+ const SPACER_WIDTH = 32;
13
+
14
+ const GRID_SX = { display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 0.5 } as const;
15
+
16
+ // Only the outermost months carry arrows; the ones between get a spacer so their
17
+ // titles stay centred.
18
+ const MonthNavHeader: FC<{
19
+ title: React.ReactNode;
20
+ showPrevious: boolean;
21
+ showNext: boolean;
22
+ onPreviousMonth: () => void;
23
+ onNextMonth: () => void;
24
+ }> = ({ title, showPrevious, showNext, onPreviousMonth, onNextMonth }) => (
25
+ <Box
26
+ sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}
27
+ data-testid="calendar-header"
28
+ >
29
+ {showPrevious && (
30
+ <IconButton onClick={onPreviousMonth} size="small" data-testid="calendar-prev-month">
31
+ <ChevronLeft />
32
+ </IconButton>
33
+ )}
34
+
35
+ <Typography
36
+ variant="h6"
37
+ component="h2"
38
+ sx={{ fontWeight: 'bold', flex: 1, textAlign: 'center' }}
39
+ >
40
+ {title}
41
+ </Typography>
42
+
43
+ {showNext && (
44
+ <IconButton onClick={onNextMonth} size="small" data-testid="calendar-next-month">
45
+ <ChevronRight />
46
+ </IconButton>
47
+ )}
48
+
49
+ {!showPrevious && !showNext && <Box sx={{ width: SPACER_WIDTH }} />}
50
+ </Box>
51
+ );
52
+
53
+ const WeekdayHeader: FC<{ weekdayNames: string[] }> = ({ weekdayNames }) => (
54
+ <Box sx={{ ...GRID_SX, mb: 1 }}>
55
+ {weekdayNames.map((weekday, index) => (
56
+ <Box
57
+ // Narrow weekday names repeat within a week ('S', 'T'), so position is
58
+ // the only stable key here.
59
+ key={`weekday-${index}`}
60
+ role="columnheader"
61
+ data-testid={`calendar-weekday-${index}`}
62
+ sx={{
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ justifyContent: 'center',
66
+ height: SPACER_WIDTH,
67
+ fontSize: '0.875rem',
68
+ fontWeight: 'bold',
69
+ color: 'text.secondary',
70
+ }}
71
+ >
72
+ {weekday}
73
+ </Box>
74
+ ))}
75
+ </Box>
76
+ );
77
+
78
+ export interface CalendarMonthProps {
79
+ matrix: MonthMatrix;
80
+ monthIndex: number;
81
+ monthsToShow: number;
82
+ locale: string;
83
+ weekdayNames: string[];
84
+ renderHeader?: CalendarProps['renderHeader'];
85
+ onPreviousMonth: () => void;
86
+ onNextMonth: () => void;
87
+ dayContext: DayCellContext;
88
+ }
89
+
90
+ export const CalendarMonth: FC<CalendarMonthProps> = ({
91
+ matrix,
92
+ monthIndex,
93
+ monthsToShow,
94
+ locale,
95
+ weekdayNames,
96
+ renderHeader,
97
+ onPreviousMonth,
98
+ onNextMonth,
99
+ dayContext,
100
+ }) => {
101
+ const monthName = getMonthName(matrix.month, matrix.year, locale);
102
+ const title = renderHeader ? renderHeader({ month: matrix.month, year: matrix.year }) : monthName;
103
+
104
+ return (
105
+ <Box sx={{ minWidth: 280 }}>
106
+ <MonthNavHeader
107
+ title={title}
108
+ showPrevious={monthIndex === 0}
109
+ showNext={monthIndex === monthsToShow - 1}
110
+ onPreviousMonth={onPreviousMonth}
111
+ onNextMonth={onNextMonth}
112
+ />
113
+
114
+ <WeekdayHeader weekdayNames={weekdayNames} />
115
+
116
+ <Box
117
+ role="grid"
118
+ aria-labelledby={`month-${monthIndex}`}
119
+ data-testid="calendar-grid"
120
+ sx={GRID_SX}
121
+ >
122
+ {matrix.weeks.flat().map((day) => (
123
+ <CalendarDayCell key={day.key} day={day} {...dayContext} />
124
+ ))}
125
+ </Box>
126
+ </Box>
127
+ );
128
+ };
@@ -0,0 +1,138 @@
1
+ # CepField Component
2
+
3
+ ## Purpose
4
+
5
+ A CEP input that fills the rest of the address in — the autofill pattern every
6
+ Brazilian form has used for twenty years. The user types eight digits and the
7
+ logradouro, bairro, cidade and UF arrive on their own; only `número` and
8
+ `complemento` are left to type, because no CEP database holds them.
9
+
10
+ The component owns the *interaction* — masking, validation, debouncing,
11
+ race-safety, status — and takes the *lookup* as a prop. It therefore knows
12
+ nothing about providers, transport or authentication, and the same component
13
+ serves a supplier form, a store-location form or a delivery checkout.
14
+
15
+ ## Features
16
+
17
+ - Masks to `#####-###` on every keystroke, tolerant of pasted/messy input
18
+ - Fires the lookup only once the CEP is complete, after a debounce
19
+ - Never re-queries a CEP it already resolved
20
+ - Race-safe: a slow response for a since-edited CEP can never overwrite a newer one
21
+ - Degrades to a plain masked input when the lookup fails, throws, or is absent
22
+ - Accessible status via `role="status"` / `aria-live="polite"` and `aria-busy`
23
+ - Works uncontrolled-by-a-form (props) or bound to `total-form` (`Fields.CepField`)
24
+
25
+ ## Props Documentation
26
+
27
+ ### Core Props
28
+
29
+ - `value`: Current value, masked or bare — the field re-masks it
30
+ - `onChange`: Called on every keystroke with the **masked** value
31
+ - `onLookup`: `(cep: string) => Promise<CepAddress | null>` — resolve a complete
32
+ CEP. Omit for a masked, validated input with no lookup at all
33
+ - `onResolved`: `(address: CepAddress) => void` — called once a CEP resolves.
34
+ This is where the caller fills its address fields
35
+ - `onNotFound`: `() => void` — called when a **complete** CEP fails to resolve.
36
+ The counterpart to `onResolved`: a caller that auto-filled from a previous CEP
37
+ should undo that here (see *Behaviour notes*)
38
+
39
+ ### Display Props
40
+
41
+ - `label`: Visible label (default `CEP`)
42
+ - `placeholder`: Placeholder text (default `00000-000`)
43
+ - `name`: Field name / input id (default `postalCode`)
44
+ - `dataTestId`: Test id for the input (default `cep-field-<name>`)
45
+
46
+ ### State Props
47
+
48
+ - `error`: Validation error from the caller's form, shown below the input
49
+ - `disabled`: Disables the input and suppresses lookups
50
+ - `debounceMs`: Delay after the last keystroke before looking up (default `500`)
51
+
52
+ ### The `CepAddress` shape
53
+
54
+ ```ts
55
+ interface CepAddress {
56
+ cep: string; // bare digits
57
+ street: string | null; // logradouro
58
+ neighborhood: string | null; // bairro
59
+ city: string | null; // município
60
+ state: string | null; // UF
61
+ }
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ### Standalone
67
+
68
+ ```tsx
69
+ const [cep, setCep] = useState('');
70
+
71
+ <CepField
72
+ value={cep}
73
+ onChange={setCep}
74
+ onLookup={(c) =>
75
+ fetch(`/api/admin/${slug}/lookup/cep/${c}`)
76
+ .then((r) => (r.ok ? r.json() : null))
77
+ .then((body) => body?.data ?? null)
78
+ }
79
+ onResolved={(address) => {
80
+ setStreet(address.street ?? '');
81
+ setCity(address.city ?? '');
82
+ }}
83
+ />
84
+ ```
85
+
86
+ ### Bound to `total-form`
87
+
88
+ `Fields.CepField` wires the field to the surrounding `FormContainer` and writes
89
+ the resolved parts straight into sibling fields:
90
+
91
+ ```tsx
92
+ <Fields.CepField
93
+ name="postalCode"
94
+ lookup={lookupCep}
95
+ fills={{
96
+ street: 'addressLine1',
97
+ neighborhood: 'neighborhood',
98
+ city: 'city',
99
+ state: 'state',
100
+ }}
101
+ />
102
+ ```
103
+
104
+ Omit a key from `fills` to leave that part alone — a form with no bairro column
105
+ simply doesn't map `neighborhood`.
106
+
107
+ ## Behaviour notes
108
+
109
+ **Autofill never blocks.** A provider outage, an unknown CEP, a timeout or a
110
+ lookup that throws all land in the same place: a `notfound` status and a field
111
+ that behaves exactly like a plain text input. Saving is never gated on a
112
+ third-party service being up.
113
+
114
+ **It will not overwrite the user's work.** `Fields.CepField` writes a target
115
+ field only when it is empty, or when it still holds the exact value that the
116
+ component put there. So correcting the CEP re-fills the address, but a
117
+ hand-edited street survives the next lookup.
118
+
119
+ **It will not leave one CEP's address under another's.** When a complete CEP
120
+ fails to resolve, `Fields.CepField` undoes its own autofill (again, only the
121
+ fields still holding what it wrote). Otherwise typing CEP A, getting a hit, then
122
+ correcting to an unknown CEP B would silently save A's street and city against
123
+ B — a plausible wrong address, which is worse than an empty one. The same rule
124
+ governs the CNPJ autofill on the fornecedores form.
125
+
126
+ **Validation is shape-only.** A CEP is a postal range, not a checksummed
127
+ document — there is no check digit to verify. Whether it *exists* is answered by
128
+ the lookup. The pure helpers (`formatCep`, `isValidCep`) live in
129
+ `@12-apps/forms-core` so the browser mask and any server-side guard share one rule.
130
+
131
+ ## Accessibility
132
+
133
+ - The status line is a `role="status"` live region, so screen readers announce
134
+ "Buscando endereço…" / "Endereço preenchido pelo CEP" without stealing focus
135
+ - `aria-busy` reflects the in-flight lookup
136
+ - `aria-describedby` links the input to its status region
137
+ - `inputMode="numeric"` brings up the numeric keypad on mobile
138
+ - `autoComplete="postal-code"` lets the browser's own autofill participate
@@ -0,0 +1,138 @@
1
+ import { Paper, Stack, Typography } from '@mui/material';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ import React, { useState } from 'react';
4
+
5
+ import { CepField } from './CepField';
6
+ import type { CepAddress } from './CepField.types';
7
+
8
+ const meta: Meta<typeof CepField> = {
9
+ title: 'Form/CepField',
10
+ component: CepField,
11
+ parameters: {
12
+ layout: 'padded',
13
+ docs: {
14
+ description: {
15
+ component:
16
+ 'A CEP input that fills the rest of the address in. Masks to `#####-###`, waits for a complete CEP, then calls the injected `onLookup` and hands the result to `onResolved`. The lookup is injected, so the component works with any backend — or none.',
17
+ },
18
+ },
19
+ },
20
+ tags: ['autodocs', 'component:CepField'],
21
+ argTypes: {
22
+ value: { control: 'text', description: 'Current value (masked or bare)' },
23
+ label: { control: 'text', description: 'Visible label' },
24
+ placeholder: { control: 'text', description: 'Placeholder text' },
25
+ error: { control: 'text', description: 'Validation error from the caller' },
26
+ disabled: { control: 'boolean', description: 'Disable input and lookups' },
27
+ debounceMs: { control: 'number', description: 'Delay before looking up' },
28
+ name: { control: 'text', description: 'Field name / input id' },
29
+ },
30
+ };
31
+
32
+ export default meta;
33
+ type Story = StoryObj<typeof meta>;
34
+
35
+ /** Stand-in for a real provider — resolves one CEP, rejects everything else. */
36
+ const FIXTURES: Record<string, CepAddress> = {
37
+ '01310100': {
38
+ cep: '01310100',
39
+ street: 'Avenida Paulista',
40
+ neighborhood: 'Bela Vista',
41
+ city: 'São Paulo',
42
+ state: 'SP',
43
+ },
44
+ '20040020': {
45
+ cep: '20040020',
46
+ street: 'Avenida Rio Branco',
47
+ neighborhood: 'Centro',
48
+ city: 'Rio de Janeiro',
49
+ state: 'RJ',
50
+ },
51
+ };
52
+
53
+ const fakeLookup = async (cep: string): Promise<CepAddress | null> => {
54
+ await new Promise((resolve) => setTimeout(resolve, 400));
55
+ return FIXTURES[cep] ?? null;
56
+ };
57
+
58
+ /** The whole point: type a CEP, watch the address fields fill themselves. */
59
+ function Demo({
60
+ lookup = fakeLookup,
61
+ ...props
62
+ }: {
63
+ lookup?: (cep: string) => Promise<CepAddress | null>;
64
+ label?: string;
65
+ disabled?: boolean;
66
+ }): React.ReactElement {
67
+ const [cep, setCep] = useState('');
68
+ const [address, setAddress] = useState<CepAddress | null>(null);
69
+
70
+ return (
71
+ <Stack spacing={2} sx={{ maxWidth: 420 }}>
72
+ <CepField
73
+ {...props}
74
+ value={cep}
75
+ onChange={setCep}
76
+ onLookup={lookup}
77
+ onResolved={setAddress}
78
+ />
79
+ <Paper variant="outlined" sx={{ p: 2 }}>
80
+ <Typography variant="caption" color="text.secondary">
81
+ Endereço resolvido
82
+ </Typography>
83
+ <Typography variant="body2">{address?.street ?? '—'}</Typography>
84
+ <Typography variant="body2">{address?.neighborhood ?? '—'}</Typography>
85
+ <Typography variant="body2">
86
+ {address ? `${address.city ?? '—'} / ${address.state ?? '—'}` : '—'}
87
+ </Typography>
88
+ </Paper>
89
+ <Typography variant="caption" color="text.secondary">
90
+ Try 01310-100 or 20040-020. Anything else resolves to “não encontrado”.
91
+ </Typography>
92
+ </Stack>
93
+ );
94
+ }
95
+
96
+ export const Default: Story = {
97
+ render: () => <Demo />,
98
+ };
99
+
100
+ export const CustomLabel: Story = {
101
+ render: () => <Demo label="CEP do fornecedor" />,
102
+ };
103
+
104
+ export const Disabled: Story = {
105
+ render: () => <Demo disabled />,
106
+ };
107
+
108
+ /** Every provider is down. The field degrades to a plain masked input. */
109
+ export const LookupUnavailable: Story = {
110
+ render: () => <Demo lookup={async () => null} />,
111
+ };
112
+
113
+ /** No `onLookup` at all — just the mask and validation. */
114
+ export const MaskOnly: Story = {
115
+ render: function MaskOnlyStory() {
116
+ const [cep, setCep] = useState('');
117
+ return (
118
+ <Stack sx={{ maxWidth: 420 }}>
119
+ <CepField value={cep} onChange={setCep} />
120
+ </Stack>
121
+ );
122
+ },
123
+ };
124
+
125
+ export const WithError: Story = {
126
+ render: function WithErrorStory() {
127
+ const [cep, setCep] = useState('123');
128
+ return (
129
+ <Stack sx={{ maxWidth: 420 }}>
130
+ <CepField
131
+ value={cep}
132
+ onChange={setCep}
133
+ error="CEP inválido — use o formato 00000-000."
134
+ />
135
+ </Stack>
136
+ );
137
+ },
138
+ };