@12-apps/ui 1.0.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/components-catalog.md +14 -0
  2. package/package.json +42 -27
  3. package/src/__tests__/data-grid.test.tsx +125 -0
  4. package/src/__tests__/package-wiring.test.ts +12 -8
  5. package/src/__tests__/social-login-button.test.tsx +5 -5
  6. package/src/__tests__/viewport.test.ts +50 -0
  7. package/src/charts/index.ts +8 -0
  8. package/src/components/data-display/Alert/Alert.md +1 -1
  9. package/src/components/data-display/Alert/Alert.stories.tsx +5 -7
  10. package/src/components/data-display/Alert/Alert.styles.tsx +255 -0
  11. package/src/components/data-display/Alert/Alert.test.stories.tsx +11 -13
  12. package/src/components/data-display/Alert/Alert.tsx +135 -328
  13. package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +3 -1
  14. package/src/components/data-display/AlertDialog/AlertDialog.tsx +191 -78
  15. package/src/components/data-display/AlertDialog/AlertDialog.types.ts +8 -1
  16. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +5 -5
  17. package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.tsx +44 -35
  18. package/src/components/data-display/Avatar/Avatar.stories.tsx +4 -1
  19. package/src/components/data-display/Avatar/Avatar.test.stories.tsx +5 -3
  20. package/src/components/data-display/Avatar/Avatar.tsx +154 -450
  21. package/src/components/data-display/Avatar/Avatar.view.tsx +396 -0
  22. package/src/components/data-display/Badge/Badge.animations.ts +67 -0
  23. package/src/components/data-display/Badge/Badge.helpers.ts +74 -0
  24. package/src/components/data-display/Badge/Badge.stories.tsx +14 -16
  25. package/src/components/data-display/Badge/Badge.styles.ts +261 -0
  26. package/src/components/data-display/Badge/Badge.test.stories.tsx +32 -31
  27. package/src/components/data-display/Badge/Badge.tsx +151 -557
  28. package/src/components/data-display/Badge/Badge.variants.ts +106 -0
  29. package/src/components/data-display/Badge/BadgeContent.tsx +107 -0
  30. package/src/components/data-display/Banner/Banner.stories.tsx +5 -1
  31. package/src/components/data-display/Banner/Banner.styles.ts +120 -0
  32. package/src/components/data-display/Banner/Banner.tsx +179 -224
  33. package/src/components/data-display/Chart/Chart.md +48 -1
  34. package/src/components/data-display/Chart/Chart.tsx +82 -500
  35. package/src/components/data-display/Chart/Chart.types.ts +2 -0
  36. package/src/components/data-display/Chart/ChartComposables.tsx +121 -0
  37. package/src/components/data-display/Chart/ChartSpec.types.ts +70 -0
  38. package/src/components/data-display/Chart/SpecChart.stories.tsx +150 -0
  39. package/src/components/data-display/Chart/SpecChart.test.stories.tsx +56 -0
  40. package/src/components/data-display/Chart/SpecChart.tsx +53 -0
  41. package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +60 -0
  42. package/src/components/data-display/Chart/__tests__/chart-format.test.ts +43 -0
  43. package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +119 -0
  44. package/src/components/data-display/Chart/chart-format.ts +26 -0
  45. package/src/components/data-display/Chart/chart-internals.ts +148 -0
  46. package/src/components/data-display/Chart/chart-renderers.tsx +338 -0
  47. package/src/components/data-display/Chart/chart-spec-registry.ts +74 -0
  48. package/src/components/data-display/Chart/chart-spec.ts +171 -0
  49. package/src/components/data-display/Chart/index.ts +30 -0
  50. package/src/components/data-display/Chip/Chip.helpers.tsx +131 -0
  51. package/src/components/data-display/Chip/Chip.stories.tsx +2 -1
  52. package/src/components/data-display/Chip/Chip.test.stories.tsx +11 -8
  53. package/src/components/data-display/Chip/Chip.tsx +31 -94
  54. package/src/components/data-display/DataGrid/DataGrid.body.tsx +141 -0
  55. package/src/components/data-display/DataGrid/DataGrid.cells.tsx +238 -0
  56. package/src/components/data-display/DataGrid/DataGrid.model.ts +315 -0
  57. package/src/components/data-display/DataGrid/DataGrid.rows.ts +112 -0
  58. package/src/components/data-display/DataGrid/DataGrid.states.tsx +102 -0
  59. package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +6 -12
  60. package/src/components/data-display/DataGrid/DataGrid.tsx +129 -725
  61. package/src/components/data-display/DataViews/DataViewsGrid.tsx +187 -0
  62. package/src/components/data-display/DataViews/DataViewsTableBase.tsx +400 -0
  63. package/src/components/data-display/DataViews/ManageViewsDialog.tsx +140 -0
  64. package/src/components/data-display/DataViews/SaveViewModal.tsx +289 -0
  65. package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +271 -0
  66. package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +134 -0
  67. package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +83 -0
  68. package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +115 -0
  69. package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +53 -0
  70. package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +114 -0
  71. package/src/components/data-display/DataViews/base-card.stories.tsx +136 -0
  72. package/src/components/data-display/DataViews/base-card.tsx +278 -0
  73. package/src/components/data-display/DataViews/data-views-filter-panel.tsx +184 -0
  74. package/src/components/data-display/DataViews/data-views-filter.ts +138 -0
  75. package/src/components/data-display/DataViews/data-views-grid-helpers.tsx +248 -0
  76. package/src/components/data-display/DataViews/data-views-grid-parts.tsx +400 -0
  77. package/src/components/data-display/DataViews/data-views-inline-bar.tsx +257 -0
  78. package/src/components/data-display/DataViews/data-views-layout-context.tsx +176 -0
  79. package/src/components/data-display/DataViews/data-views-pagination.tsx +31 -0
  80. package/src/components/data-display/DataViews/data-views-preview.ts +53 -0
  81. package/src/components/data-display/DataViews/data-views-range-pill.tsx +277 -0
  82. package/src/components/data-display/DataViews/data-views-table-parts.tsx +150 -0
  83. package/src/components/data-display/DataViews/data-views-toolbar.tsx +149 -0
  84. package/src/components/data-display/DataViews/data-views-types.ts +312 -0
  85. package/src/components/data-display/DataViews/data-views-view-mutations.ts +68 -0
  86. package/src/components/data-display/DataViews/index.ts +33 -0
  87. package/src/components/data-display/DataViews/use-data-views-state.ts +349 -0
  88. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.hooks.ts +104 -0
  89. package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +68 -118
  90. package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +1 -1
  91. package/src/components/data-display/DescriptionItem/DescriptionItem.tsx +52 -34
  92. package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +6 -6
  93. package/src/components/data-display/EmptyState/EmptyState.tsx +218 -135
  94. package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +2 -2
  95. package/src/components/data-display/ErrorState/ErrorState.tsx +83 -55
  96. package/src/components/data-display/HoverCard/HoverCard.stories.tsx +3 -1
  97. package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +5 -5
  98. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.hooks.ts +99 -0
  99. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.styles.ts +87 -0
  100. package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.tsx +28 -155
  101. package/src/components/data-display/LazyImage/LazyImage.hooks.ts +203 -0
  102. package/src/components/data-display/LazyImage/LazyImage.md +1 -1
  103. package/src/components/data-display/LazyImage/LazyImage.stories.tsx +3 -3
  104. package/src/components/data-display/LazyImage/LazyImage.tsx +144 -243
  105. package/src/components/data-display/Lightbox/Lightbox.constants.ts +53 -0
  106. package/src/components/data-display/Lightbox/Lightbox.helpers.ts +39 -0
  107. package/src/components/data-display/Lightbox/Lightbox.hooks.ts +259 -0
  108. package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +28 -35
  109. package/src/components/data-display/Lightbox/Lightbox.tsx +98 -658
  110. package/src/components/data-display/Lightbox/LightboxControls.tsx +152 -0
  111. package/src/components/data-display/Lightbox/LightboxCurrentMedia.tsx +50 -0
  112. package/src/components/data-display/Lightbox/LightboxMedia.tsx +76 -0
  113. package/src/components/data-display/Lightbox/LightboxOverlay.tsx +83 -0
  114. package/src/components/data-display/Lightbox/LightboxStage.tsx +97 -0
  115. package/src/components/data-display/Lightbox/LightboxThumbnails.tsx +83 -0
  116. package/src/components/data-display/Lightbox/useLightbox.ts +80 -0
  117. package/src/components/data-display/LoadingState/LoadingState.helpers.ts +52 -0
  118. package/src/components/data-display/LoadingState/LoadingState.tsx +117 -87
  119. package/src/components/data-display/MapPreview/MapControlBar.tsx +116 -0
  120. package/src/components/data-display/MapPreview/MapDecorations.tsx +155 -0
  121. package/src/components/data-display/MapPreview/MapLayers.tsx +70 -0
  122. package/src/components/data-display/MapPreview/MapMarkers.tsx +84 -0
  123. package/src/components/data-display/MapPreview/MapOverlays.tsx +68 -0
  124. package/src/components/data-display/MapPreview/MapPreview.constants.ts +19 -0
  125. package/src/components/data-display/MapPreview/MapPreview.helpers.ts +63 -0
  126. package/src/components/data-display/MapPreview/MapPreview.hooks.ts +265 -0
  127. package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +14 -10
  128. package/src/components/data-display/MapPreview/MapPreview.tsx +52 -882
  129. package/src/components/data-display/MapPreview/MapPreview.types.ts +8 -1
  130. package/src/components/data-display/MapPreview/MapSearchBar.tsx +64 -0
  131. package/src/components/data-display/MapPreview/MapTiles.tsx +70 -0
  132. package/src/components/data-display/MapPreview/StaticMapView.tsx +63 -0
  133. package/src/components/data-display/MapPreview/mapProjection.ts +52 -0
  134. package/src/components/data-display/MapPreview/mapSurface.ts +37 -0
  135. package/src/components/data-display/MapPreview/useMapPreview.ts +62 -0
  136. package/src/components/data-display/Popover/Popover.test.stories.tsx +13 -19
  137. package/src/components/data-display/Progress/Progress.helpers.ts +37 -0
  138. package/src/components/data-display/Progress/Progress.styles.ts +101 -0
  139. package/src/components/data-display/Progress/Progress.tsx +185 -213
  140. package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +1 -1
  141. package/src/components/data-display/SectionOnboarding/SectionOnboarding.tsx +1 -1
  142. package/src/components/data-display/StatCard/StatCard.md +117 -0
  143. package/src/components/data-display/StatCard/StatCard.stories.tsx +167 -0
  144. package/src/components/data-display/StatCard/StatCard.test.stories.tsx +240 -0
  145. package/src/components/data-display/StatCard/StatCard.tsx +236 -0
  146. package/src/components/data-display/StatCard/StatCard.types.ts +62 -0
  147. package/src/components/data-display/StatCard/index.ts +7 -0
  148. package/src/components/data-display/Stepper/Stepper.test.stories.tsx +12 -19
  149. package/src/components/data-display/Stepper/Stepper.tsx +1 -1
  150. package/src/components/data-display/Table/Table.helpers.ts +31 -0
  151. package/src/components/data-display/Table/Table.hooks.ts +161 -0
  152. package/src/components/data-display/Table/Table.stories.tsx +3 -1
  153. package/src/components/data-display/Table/Table.styles.ts +223 -0
  154. package/src/components/data-display/Table/Table.test.stories.tsx +4 -4
  155. package/src/components/data-display/Table/Table.tsx +291 -748
  156. package/src/components/data-display/Table/TableParts.hooks.tsx +112 -0
  157. package/src/components/data-display/Table/TableParts.tsx +298 -0
  158. package/src/components/data-display/Table/TableStates.tsx +21 -0
  159. package/src/components/data-display/Timeline/Timeline.stories.tsx +10 -12
  160. package/src/components/data-display/Timeline/Timeline.test.stories.tsx +30 -44
  161. package/src/components/data-display/Timeline/Timeline.tsx +23 -284
  162. package/src/components/data-display/Timeline/TimelineRow.tsx +346 -0
  163. package/src/components/data-display/TimingDiagram/TimingDiagram.tsx +38 -311
  164. package/src/components/data-display/TimingDiagram/TimingDiagram.views.tsx +346 -0
  165. package/src/components/data-display/Tooltip/Tooltip.stories.tsx +4 -1
  166. package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +44 -58
  167. package/src/components/data-display/Tooltip/Tooltip.tsx +67 -62
  168. package/src/components/data-display/index.ts +1 -0
  169. package/src/components/feedback/ConfirmAction/ConfirmAction.hooks.ts +96 -0
  170. package/src/components/feedback/ConfirmAction/ConfirmAction.md +140 -0
  171. package/src/components/feedback/ConfirmAction/ConfirmAction.parts.tsx +154 -0
  172. package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +146 -0
  173. package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +114 -0
  174. package/src/components/feedback/ConfirmAction/ConfirmAction.tsx +46 -0
  175. package/src/components/feedback/ConfirmAction/ConfirmAction.types.ts +111 -0
  176. package/src/components/feedback/ConfirmAction/ConfirmButton.tsx +18 -0
  177. package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +288 -0
  178. package/src/components/feedback/ConfirmAction/index.ts +16 -0
  179. package/src/components/feedback/ConfirmAction/with-confirmation.tsx +112 -0
  180. package/src/components/feedback/Dialog/Dialog.styles.ts +4 -2
  181. package/src/components/feedback/Dialog/Dialog.tsx +26 -1
  182. package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +66 -0
  183. package/src/components/feedback/Modal/Modal.md +1 -1
  184. package/src/components/feedback/Modal/Modal.stories.tsx +2 -2
  185. package/src/components/feedback/Sonner/Sonner.tsx +104 -288
  186. package/src/components/feedback/Sonner/Sonner.types.ts +7 -0
  187. package/src/components/feedback/Sonner/SonnerToast.tsx +216 -0
  188. package/src/components/feedback/StackedModal/StackedModal.hooks.ts +226 -0
  189. package/src/components/feedback/StackedModal/StackedModal.parts.tsx +311 -0
  190. package/src/components/feedback/StackedModal/StackedModal.stories.tsx +13 -15
  191. package/src/components/feedback/StackedModal/StackedModal.styles.ts +193 -0
  192. package/src/components/feedback/StackedModal/StackedModal.tsx +100 -619
  193. package/src/components/feedback/StackedModal/StackedModal.types.ts +17 -3
  194. package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +104 -0
  195. package/src/components/feedback/StackedModal/modal-stack.tsx +119 -0
  196. package/src/components/feedback/Toast/Toast.tsx +92 -81
  197. package/src/components/feedback/TutorialOverlay/TutorialOverlay.geometry.ts +65 -0
  198. package/src/components/feedback/TutorialOverlay/TutorialOverlay.hooks.ts +185 -0
  199. package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +2 -2
  200. package/src/components/feedback/TutorialOverlay/TutorialOverlay.tsx +156 -414
  201. package/src/components/feedback/TutorialOverlay/TutorialStepBody.tsx +255 -0
  202. package/src/components/feedback/index.ts +1 -0
  203. package/src/components/form/AddressAutocomplete/AddressAutocomplete.helpers.ts +58 -0
  204. package/src/components/form/AddressAutocomplete/AddressAutocomplete.hooks.ts +93 -0
  205. package/src/components/form/AddressAutocomplete/AddressAutocomplete.mapper.ts +57 -0
  206. package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +4 -2
  207. package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +20 -16
  208. package/src/components/form/AddressAutocomplete/AddressAutocomplete.tsx +26 -829
  209. package/src/components/form/AddressAutocomplete/AddressAutocomplete.types.ts +11 -0
  210. package/src/components/form/AddressAutocomplete/AddressAutocompleteField.tsx +86 -0
  211. package/src/components/form/AddressAutocomplete/AddressFallbackField.tsx +64 -0
  212. package/src/components/form/AddressAutocomplete/AddressInputField.tsx +80 -0
  213. package/src/components/form/AddressAutocomplete/AddressOption.tsx +83 -0
  214. package/src/components/form/AddressAutocomplete/AddressSuggestionsPaper.tsx +24 -0
  215. package/src/components/form/AddressAutocomplete/AddressTextField.tsx +43 -0
  216. package/src/components/form/AddressAutocomplete/mockPlaces.ts +208 -0
  217. package/src/components/form/AddressAutocomplete/useAddressPredictions.ts +136 -0
  218. package/src/components/form/AddressAutocomplete/useAddressSelection.ts +113 -0
  219. package/src/components/form/AddressAutocomplete/useCurrentLocation.ts +116 -0
  220. package/src/components/form/AddressAutocomplete/useGoogleMapsAPI.ts +75 -0
  221. package/src/components/form/Button/Button.helpers.ts +36 -0
  222. package/src/components/form/Button/Button.stories.tsx +4 -1
  223. package/src/components/form/Button/Button.styles.ts +225 -0
  224. package/src/components/form/Button/Button.test.stories.tsx +25 -21
  225. package/src/components/form/Button/Button.tsx +45 -252
  226. package/src/components/form/Calendar/Calendar.dates.ts +100 -0
  227. package/src/components/form/Calendar/Calendar.helpers.ts +32 -0
  228. package/src/components/form/Calendar/Calendar.hooks.ts +278 -0
  229. package/src/components/form/Calendar/Calendar.keyboard.ts +32 -0
  230. package/src/components/form/Calendar/Calendar.selection.ts +156 -0
  231. package/src/components/form/Calendar/Calendar.test.stories.tsx +33 -34
  232. package/src/components/form/Calendar/Calendar.tsx +63 -551
  233. package/src/components/form/Calendar/Calendar.types.ts +16 -0
  234. package/src/components/form/Calendar/CalendarDay.tsx +127 -0
  235. package/src/components/form/Calendar/CalendarDayCell.tsx +52 -0
  236. package/src/components/form/Calendar/CalendarMonth.tsx +128 -0
  237. package/src/components/form/CepField/CepField.md +138 -0
  238. package/src/components/form/CepField/CepField.stories.tsx +138 -0
  239. package/src/components/form/CepField/CepField.test.stories.tsx +281 -0
  240. package/src/components/form/CepField/CepField.tsx +211 -0
  241. package/src/components/form/CepField/CepField.types.ts +73 -0
  242. package/src/components/form/CepField/index.ts +2 -0
  243. package/src/components/form/Checkbox/Checkbox.helpers.ts +28 -0
  244. package/src/components/form/Checkbox/Checkbox.tsx +19 -16
  245. package/src/components/form/CodeEditor/CodeEditor.helpers.ts +45 -0
  246. package/src/components/form/CodeEditor/CodeEditor.hooks.ts +104 -0
  247. package/src/components/form/CodeEditor/CodeEditor.monaco.ts +109 -0
  248. package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +17 -18
  249. package/src/components/form/CodeEditor/CodeEditor.tsx +81 -330
  250. package/src/components/form/CodeEditor/CodeEditorToolbar.tsx +168 -0
  251. package/src/components/form/Command/Command.hooks.ts +207 -0
  252. package/src/components/form/Command/Command.parts.tsx +58 -0
  253. package/src/components/form/Command/Command.styles.ts +83 -0
  254. package/src/components/form/Command/Command.tsx +61 -270
  255. package/src/components/form/CreatableSelect/CreatableSelect.md +1 -1
  256. package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +1 -1
  257. package/src/components/form/CreatableSelect/CreatableSelect.tsx +152 -71
  258. package/src/components/form/CreatableSelect/CreatableSelect.types.ts +13 -0
  259. package/src/components/form/HeaderButton/HeaderButton.tsx +80 -0
  260. package/src/components/form/HeaderButton/index.ts +2 -0
  261. package/src/components/form/Input/Input.stories.tsx +5 -1
  262. package/src/components/form/Input/Input.styles.ts +176 -0
  263. package/src/components/form/Input/Input.test.stories.tsx +30 -23
  264. package/src/components/form/Input/Input.tsx +71 -211
  265. package/src/components/form/Input/Input.types.ts +11 -0
  266. package/src/components/form/InputOTP/InputOTP.test.stories.tsx +9 -17
  267. package/src/components/form/Menubar/Menubar.test.stories.tsx +4 -8
  268. package/src/components/form/PasswordStrength/PasswordStrength.helpers.tsx +117 -0
  269. package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +3 -3
  270. package/src/components/form/PasswordStrength/PasswordStrength.tsx +202 -255
  271. package/src/components/form/PhoneInput/PhoneInput.hooks.ts +134 -0
  272. package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +4 -4
  273. package/src/components/form/PhoneInput/PhoneInput.tsx +279 -292
  274. package/src/components/form/PhoneInput/countries.ts +54 -0
  275. package/src/components/form/PhoneInput/phone.ts +47 -0
  276. package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +9 -9
  277. package/src/components/form/RichTextEditor/RichTextEditor.dom.ts +124 -0
  278. package/src/components/form/RichTextEditor/RichTextEditor.format.ts +61 -0
  279. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +142 -0
  280. package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +5 -12
  281. package/src/components/form/RichTextEditor/RichTextEditor.tsx +98 -410
  282. package/src/components/form/RichTextEditor/RichTextEditorToolbar.tsx +187 -0
  283. package/src/components/form/SearchPalette/SearchPalette.parts.tsx +22 -0
  284. package/src/components/form/SearchPalette/SearchPalette.tsx +13 -9
  285. package/src/components/form/Select/Select.test.stories.tsx +35 -27
  286. package/src/components/form/Slider/Slider.test.stories.tsx +9 -11
  287. package/src/components/form/Switch/Switch.md +2 -1
  288. package/src/components/form/Switch/Switch.test.stories.tsx +6 -6
  289. package/src/components/form/Textarea/Textarea.styles.ts +143 -0
  290. package/src/components/form/Textarea/Textarea.test.stories.tsx +20 -26
  291. package/src/components/form/Textarea/Textarea.tsx +114 -535
  292. package/src/components/form/Textarea/TextareaRichEditor.tsx +377 -0
  293. package/src/components/form/Toggle/Toggle.styles.ts +211 -0
  294. package/src/components/form/Toggle/Toggle.test.stories.tsx +19 -27
  295. package/src/components/form/Toggle/Toggle.tsx +10 -185
  296. package/src/components/form/UploadButton/UploadButton.hooks.ts +323 -0
  297. package/src/components/form/UploadButton/UploadButton.parts.tsx +210 -0
  298. package/src/components/form/UploadButton/UploadButton.stories.tsx +2 -1
  299. package/src/components/form/UploadButton/UploadButton.test.stories.tsx +123 -4
  300. package/src/components/form/UploadButton/UploadButton.tsx +76 -305
  301. package/src/components/form/UploadButton/UploadButton.types.ts +16 -0
  302. package/src/components/form/index.ts +1 -0
  303. package/src/components/form/total-form/Fields/CepField.tsx +143 -0
  304. package/src/components/form/total-form/Fields/ToggleField.tsx +61 -0
  305. package/src/components/form/total-form/Fields/index.ts +4 -0
  306. package/src/components/form/total-form/FormContainer.tsx +3 -3
  307. package/src/components/form/total-form/SubmitButton.tsx +25 -2
  308. package/src/components/form/total-form/total-form.test.tsx +118 -1
  309. package/src/components/layout/Accordion/Accordion.md +1 -1
  310. package/src/components/layout/Accordion/Accordion.stories.tsx +5 -1
  311. package/src/components/layout/Accordion/Accordion.styles.ts +80 -0
  312. package/src/components/layout/Accordion/Accordion.test.stories.tsx +32 -50
  313. package/src/components/layout/Accordion/Accordion.tsx +2 -75
  314. package/src/components/layout/Card/Card.helpers.ts +30 -0
  315. package/src/components/layout/Card/Card.stories.tsx +9 -11
  316. package/src/components/layout/Card/Card.styles.ts +182 -0
  317. package/src/components/layout/Card/Card.test.stories.tsx +46 -46
  318. package/src/components/layout/Card/Card.tsx +24 -241
  319. package/src/components/layout/CardGrid/CardGrid.md +96 -0
  320. package/src/components/layout/CardGrid/CardGrid.tsx +140 -0
  321. package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +92 -0
  322. package/src/components/layout/CardGrid/index.ts +2 -0
  323. package/src/components/layout/Collapsible/Collapsible.helpers.ts +83 -0
  324. package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +7 -3
  325. package/src/components/layout/Collapsible/Collapsible.tsx +111 -107
  326. package/src/components/layout/Container/Container.test.stories.tsx +11 -16
  327. package/src/components/layout/ContentToolbar/ColumnsMenu.tsx +1 -1
  328. package/src/components/layout/ContentToolbar/ContentToolbar.tsx +120 -44
  329. package/src/components/layout/ContentToolbar/ContentToolbar.types.ts +9 -0
  330. package/src/components/layout/ContentToolbar/FilterTrigger.tsx +1 -1
  331. package/src/components/layout/ContentToolbar/MultiSelectDropdown.tsx +58 -43
  332. package/src/components/layout/ContentToolbar/MultiSelectTriggers.tsx +139 -0
  333. package/src/components/layout/ContentToolbar/SavedViewsMenu.tsx +10 -3
  334. package/src/components/layout/ContentToolbar/SortByDropdown.tsx +35 -11
  335. package/src/components/layout/ContentToolbar/ViewSelector.tsx +5 -6
  336. package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +21 -0
  337. package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +27 -1
  338. package/src/components/layout/Dashboard/Dashboard.tsx +27 -8
  339. package/src/components/layout/Dashboard/DashboardParts.tsx +12 -19
  340. package/src/components/layout/Dashboard/index.ts +2 -1
  341. package/src/components/layout/Drawer/Drawer.stories.tsx +8 -10
  342. package/src/components/layout/Drawer/Drawer.test.stories.tsx +18 -14
  343. package/src/components/layout/Drawer/Drawer.tsx +67 -53
  344. package/src/components/layout/Resizable/Resizable.helpers.ts +133 -0
  345. package/src/components/layout/Resizable/Resizable.hooks.ts +68 -0
  346. package/src/components/layout/Resizable/Resizable.tsx +38 -153
  347. package/src/components/layout/ScrollArea/ScrollArea.helpers.ts +51 -0
  348. package/src/components/layout/ScrollArea/ScrollArea.styles.ts +248 -0
  349. package/src/components/layout/ScrollArea/ScrollArea.tsx +183 -374
  350. package/src/components/layout/ScrollArea/ScrollAreaContent.tsx +70 -0
  351. package/src/components/layout/ScrollArea/ScrollViewport.tsx +90 -0
  352. package/src/components/layout/Separator/Separator.styles.ts +128 -0
  353. package/src/components/layout/Separator/Separator.test.stories.tsx +3 -12
  354. package/src/components/layout/Separator/Separator.tsx +6 -132
  355. package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +2 -1
  356. package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +6 -8
  357. package/src/components/layout/Sidebar/Sidebar.stories.tsx +10 -12
  358. package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +35 -37
  359. package/src/components/layout/Skeleton/Skeleton.helpers.ts +33 -0
  360. package/src/components/layout/Skeleton/Skeleton.styles.ts +114 -0
  361. package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +3 -3
  362. package/src/components/layout/Skeleton/Skeleton.tsx +67 -155
  363. package/src/components/layout/TableFilter/TableFilter.tsx +2 -1
  364. package/src/components/navigation/Breadcrumbs/BreadcrumbEntry.tsx +305 -0
  365. package/src/components/navigation/Breadcrumbs/Breadcrumbs.md +2 -1
  366. package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +12 -14
  367. package/src/components/navigation/Breadcrumbs/Breadcrumbs.styles.tsx +212 -0
  368. package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +62 -61
  369. package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +116 -429
  370. package/src/components/navigation/CommandPalette/CommandPalette.helpers.ts +82 -0
  371. package/src/components/navigation/CommandPalette/CommandPalette.hooks.ts +202 -0
  372. package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +3 -1
  373. package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +3 -5
  374. package/src/components/navigation/CommandPalette/CommandPalette.tsx +108 -341
  375. package/src/components/navigation/CommandPalette/CommandPaletteResults.tsx +182 -0
  376. package/src/components/navigation/CommandPalette/ShortcutChip.tsx +18 -0
  377. package/src/components/navigation/ContextMenu/ContextMenu.md +3 -1
  378. package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +4 -1
  379. package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +19 -24
  380. package/src/components/navigation/ContextMenu/ContextMenu.tsx +70 -54
  381. package/src/components/navigation/DropdownMenu/DropdownMenu.md +3 -1
  382. package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +17 -19
  383. package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +26 -26
  384. package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +189 -111
  385. package/src/components/navigation/NavigationMenu/NavigationMegaSection.tsx +66 -0
  386. package/src/components/navigation/NavigationMenu/NavigationMenu.md +7 -2
  387. package/src/components/navigation/NavigationMenu/NavigationMenu.shell.tsx +218 -0
  388. package/src/components/navigation/NavigationMenu/NavigationMenu.styles.ts +223 -0
  389. package/src/components/navigation/NavigationMenu/NavigationMenu.tsx +119 -808
  390. package/src/components/navigation/NavigationMenu/NavigationMenuItem.hooks.ts +126 -0
  391. package/src/components/navigation/NavigationMenu/NavigationMenuItem.tsx +352 -0
  392. package/src/components/navigation/NavigationMenu/NavigationStandardBody.tsx +148 -0
  393. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +15 -17
  394. package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +27 -23
  395. package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +11 -13
  396. package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +9 -11
  397. package/src/components/navigation/Pagination/Pagination.helpers.tsx +85 -0
  398. package/src/components/navigation/Pagination/Pagination.md +2 -1
  399. package/src/components/navigation/Pagination/Pagination.stories.tsx +4 -6
  400. package/src/components/navigation/Pagination/Pagination.styles.ts +135 -0
  401. package/src/components/navigation/Pagination/Pagination.tsx +178 -313
  402. package/src/components/navigation/Pagination/PaginationParts.tsx +81 -0
  403. package/src/components/navigation/Tabs/Tabs.md +3 -1
  404. package/src/components/navigation/Tabs/Tabs.stories.tsx +21 -23
  405. package/src/components/navigation/Tabs/Tabs.styles.ts +163 -0
  406. package/src/components/navigation/Tabs/Tabs.test.stories.tsx +37 -37
  407. package/src/components/navigation/Tabs/Tabs.tsx +192 -361
  408. package/src/components/navigation/Tabs/TabsPanel.tsx +100 -0
  409. package/src/components/typography/Blockquote/Blockquote.tsx +1 -1
  410. package/src/components/typography/Code/Code.test.stories.tsx +5 -5
  411. package/src/components/typography/Code/Code.tsx +74 -49
  412. package/src/components/typography/Heading/Heading.test.stories.tsx +8 -8
  413. package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +5 -12
  414. package/src/components/typography/Text/Text.tsx +84 -77
  415. package/src/components/utility/AnimatedIcon/AnimatedIcon.md +4 -4
  416. package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +19 -21
  417. package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +19 -12
  418. package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +9 -9
  419. package/src/components/utility/InfiniteScroll/InfiniteScroll.hooks.ts +118 -0
  420. package/src/components/utility/InfiniteScroll/InfiniteScroll.parts.tsx +54 -0
  421. package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +12 -9
  422. package/src/components/utility/InfiniteScroll/InfiniteScroll.tsx +29 -148
  423. package/src/components/utility/InstallPrompt/InstallPrompt.helpers.ts +124 -0
  424. package/src/components/utility/InstallPrompt/InstallPrompt.md +113 -0
  425. package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +118 -0
  426. package/src/components/utility/InstallPrompt/InstallPrompt.styles.ts +50 -0
  427. package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +83 -0
  428. package/src/components/utility/InstallPrompt/InstallPrompt.tsx +192 -0
  429. package/src/components/utility/InstallPrompt/InstallPrompt.types.ts +78 -0
  430. package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +65 -0
  431. package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +271 -0
  432. package/src/components/utility/InstallPrompt/index.ts +10 -0
  433. package/src/components/utility/InstallPrompt/usePwaInstall.ts +171 -0
  434. package/src/components/utility/Transition/Transition.helpers.ts +40 -0
  435. package/src/components/utility/Transition/Transition.tsx +17 -68
  436. package/src/components/utility/VirtualList/VirtualList.hooks.ts +319 -0
  437. package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +49 -38
  438. package/src/components/utility/VirtualList/VirtualList.tsx +110 -315
  439. package/src/components/utility/WorkflowStep/WorkflowStep.helpers.ts +151 -0
  440. package/src/components/utility/WorkflowStep/WorkflowStep.parts.tsx +371 -0
  441. package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +9 -11
  442. package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +7 -7
  443. package/src/components/utility/WorkflowStep/WorkflowStep.tsx +51 -449
  444. package/src/components/utility/WorkflowStep/WorkflowStepRow.tsx +96 -0
  445. package/src/components/utility/index.ts +1 -0
  446. package/src/mui/Link.ts +2 -0
  447. package/src/utils/index.ts +2 -1
  448. package/src/utils/viewport.ts +65 -0
@@ -1,21 +1,16 @@
1
- import {
2
- Fullscreen as FullscreenIcon,
3
- Layers as LayersIcon,
4
- LocationOn as LocationIcon,
5
- MyLocation as CenterIcon,
6
- Navigation as NavigationIcon,
7
- Place as PlaceIcon,
8
- Search as SearchIcon,
9
- ZoomIn as ZoomInIcon,
10
- ZoomOut as ZoomOutIcon,
11
- } from '@mui/icons-material';
12
- import { alpha, Box, IconButton, InputAdornment,Paper, styled, TextField, Tooltip, Typography, useTheme } from '@mui/material';
13
- import type { FC} from 'react';
14
- import React, { useCallback,useEffect, useRef, useState } from 'react';
15
-
16
- import type { HeatmapPoint,MapPreviewProps } from './MapPreview.types';
17
-
18
- // Styled components
1
+ import { alpha, Box, Paper, styled, useTheme } from '@mui/material';
2
+ import type { FC } from 'react';
3
+ import React from 'react';
4
+
5
+ import { glassStyles, resolveMapPreviewProps } from './MapPreview.helpers';
6
+ import type { MapPreviewProps } from './MapPreview.types';
7
+ import { MapLayers } from './MapLayers';
8
+ import { MapCoordinates, MapMarkers } from './MapMarkers';
9
+ import { StaticMapView } from './StaticMapView';
10
+ import { useMapPreview } from './useMapPreview';
11
+
12
+ // Kept module-local: styled() components cannot be exported across a module
13
+ // boundary here without tripping TS2742.
19
14
  const MapContainer = styled(Paper)(({ theme }) => ({
20
15
  position: 'relative',
21
16
  width: '100%',
@@ -31,892 +26,67 @@ const MapWrapper = styled(Box)<{ height: string }>(({ height }) => ({
31
26
  position: 'relative',
32
27
  }));
33
28
 
34
- const MapControls = styled(Box)(({ theme }) => ({
35
- position: 'absolute',
36
- top: theme.spacing(2),
37
- right: theme.spacing(2),
38
- zIndex: 1,
39
- display: 'flex',
40
- flexDirection: 'column',
41
- gap: theme.spacing(1),
42
- }));
43
-
44
- const ControlButton = styled(IconButton)(({ theme }) => ({
45
- background: alpha(theme.palette.background.paper, 0.95),
46
- backdropFilter: 'blur(10px)',
47
- WebkitBackdropFilter: 'blur(10px)',
48
- border: `1px solid ${alpha(theme.palette.divider, 0.2)}`,
49
- boxShadow: theme.shadows[2],
50
- pointerEvents: 'auto',
51
- '&:hover': {
52
- background: theme.palette.background.paper,
53
- transform: 'scale(1.05)',
54
- },
55
- '&:disabled': {
56
- opacity: 0.5,
57
- pointerEvents: 'auto',
58
- },
59
- }));
60
-
61
- const CoordinatesDisplay = styled(Box)(({ theme }) => ({
62
- position: 'absolute',
63
- bottom: theme.spacing(2),
64
- left: theme.spacing(2),
65
- padding: theme.spacing(1, 1.5),
66
- background: alpha(theme.palette.background.paper, 0.95),
67
- backdropFilter: 'blur(10px)',
68
- WebkitBackdropFilter: 'blur(10px)',
69
- border: `1px solid ${alpha(theme.palette.divider, 0.2)}`,
70
- borderRadius: theme.shape.borderRadius,
71
- zIndex: 1,
72
- }));
73
-
74
- // Mock Google Maps Service
75
- class MockGoogleMapsService {
76
- private static readonly TILE_SIZE = 256;
77
- private static readonly MAX_ZOOM = 21;
78
-
79
- // Calculate tile coordinates from lat/lng and zoom
80
- static getTileCoordinates(lat: number, lng: number, zoom: number) {
81
- const scale = 1 << zoom;
82
- const worldCoordinate = this.project(lat, lng);
83
- const pixelCoordinate = {
84
- x: Math.floor(worldCoordinate.x * scale),
85
- y: Math.floor(worldCoordinate.y * scale)
86
- };
87
- const tileCoordinate = {
88
- x: Math.floor(pixelCoordinate.x / this.TILE_SIZE),
89
- y: Math.floor(pixelCoordinate.y / this.TILE_SIZE)
90
- };
91
- return tileCoordinate;
92
- }
93
-
94
- // Mercator projection
95
- static project(lat: number, lng: number) {
96
- const siny = Math.sin((lat * Math.PI) / 180);
97
- const boundedSiny = Math.max(-0.9999, Math.min(0.9999, siny));
98
-
99
- return {
100
- x: this.TILE_SIZE * (0.5 + lng / 360),
101
- y: this.TILE_SIZE * (0.5 - Math.log((1 + boundedSiny) / (1 - boundedSiny)) / (4 * Math.PI))
102
- };
103
- }
104
-
105
- // Convert pixel coordinates back to lat/lng
106
- static unproject(x: number, y: number, zoom: number) {
107
- const scale = 1 << zoom;
108
- const worldCoordinate = {
109
- x: x / scale,
110
- y: y / scale
111
- };
112
-
113
- const lng = (worldCoordinate.x / this.TILE_SIZE - 0.5) * 360;
114
- const latRadians = (0.5 - worldCoordinate.y / this.TILE_SIZE) * 2 * Math.PI;
115
- const lat = (2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2) * 180 / Math.PI;
116
-
117
- return { lat, lng };
118
- }
119
-
120
- // Calculate distance between two points (Haversine formula)
121
- static calculateDistance(lat1: number, lng1: number, lat2: number, lng2: number): number {
122
- const R = 6371; // Earth's radius in km
123
- const dLat = (lat2 - lat1) * Math.PI / 180;
124
- const dLng = (lng2 - lng1) * Math.PI / 180;
125
- const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
126
- Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
127
- Math.sin(dLng/2) * Math.sin(dLng/2);
128
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
129
- return R * c;
130
- }
131
-
132
- // Get scale bar distance based on zoom level
133
- static getScaleDistance(zoom: number): string {
134
- const metersPerPixel = 156543.03392 * Math.cos(0) / Math.pow(2, zoom);
135
- const scaleWidth = 100; // pixels
136
- const distance = metersPerPixel * scaleWidth;
137
-
138
- if (distance >= 1000) {
139
- return `${Math.round(distance / 1000)} km`;
140
- } else if (distance >= 100) {
141
- return `${Math.round(distance / 100) * 100} m`;
142
- } else {
143
- return `${Math.round(distance)} m`;
144
- }
145
- }
146
-
147
- // Simulate geocoding
148
- static async geocode(address: string): Promise<{ lat: number; lng: number } | null> {
149
- // Simulate API delay
150
- await new Promise(resolve => window.setTimeout(resolve, 300));
151
-
152
- // Mock geocoding results
153
- const mockResults: Record<string, { lat: number; lng: number }> = {
154
- 'san francisco': { lat: 37.7749, lng: -122.4194 },
155
- 'new york': { lat: 40.7128, lng: -74.0060 },
156
- 'london': { lat: 51.5074, lng: -0.1278 },
157
- 'tokyo': { lat: 35.6762, lng: 139.6503 },
158
- 'paris': { lat: 48.8566, lng: 2.3522 },
159
- };
160
-
161
- const normalizedAddress = address.toLowerCase().trim();
162
- return mockResults[normalizedAddress] || null;
163
- }
164
- }
165
-
166
- // Static Map Component with realistic map visualization
167
- const StaticMapView: FC<{
168
- coordinates: { lat: number; lng: number };
169
- height: string;
170
- zoom: number;
171
- mapType: string;
172
- marker?: boolean;
173
- markerPosition?: { lat: number; lng: number };
174
- panOffset?: { x: number; y: number };
175
- }> = ({
176
- height,
177
- zoom,
178
- mapType,
179
- marker,
180
- markerPosition,
181
- panOffset = { x: 0, y: 0 },
182
- }) => {
183
- const theme = useTheme();
184
- const mapRef = useRef<HTMLDivElement>(null);
185
-
186
-
187
- // Calculate tile information
188
- const tileInfo = React.useMemo(() => {
189
- if (!markerPosition) return null;
190
- return MockGoogleMapsService.getTileCoordinates(
191
- markerPosition.lat,
192
- markerPosition.lng,
193
- zoom
194
- );
195
- }, [markerPosition, zoom]);
196
-
197
- // Simulate map tiles with realistic grid
198
- const MapTiles = () => {
199
- const tileSize = 256;
200
- const visibleTiles = Math.ceil(800 / tileSize) + 2; // Extra tiles for panning
201
- const tileOpacity = theme.palette.mode === 'dark' ? 0.15 : 0.1;
202
-
203
- return (
204
- <div
205
- style={{
206
- position: 'absolute',
207
- top: '50%',
208
- left: '50%',
209
- transform: `translate(calc(-50% + ${panOffset.x}px), calc(-50% + ${panOffset.y}px))`,
210
- width: tileSize * visibleTiles,
211
- height: tileSize * visibleTiles,
212
- display: 'grid',
213
- gridTemplateColumns: `repeat(${visibleTiles}, ${tileSize}px)`,
214
- gridTemplateRows: `repeat(${visibleTiles}, ${tileSize}px)`,
215
- transition: 'transform 0.1s ease-out',
216
- }}
217
- >
218
- {Array.from({ length: visibleTiles * visibleTiles }).map((_, index) => {
219
- const row = Math.floor(index / visibleTiles);
220
- const col = index % visibleTiles;
221
- const tileX = (tileInfo?.x || 0) + col - Math.floor(visibleTiles / 2);
222
- const tileY = (tileInfo?.y || 0) + row - Math.floor(visibleTiles / 2);
223
-
224
- return (
225
- <div
226
- key={`tile-${tileX}-${tileY}`}
227
- style={{
228
- width: tileSize,
229
- height: tileSize,
230
- border: `1px solid ${alpha(theme.palette.divider, tileOpacity)}`,
231
- background: mapType === 'satellite'
232
- ? `linear-gradient(135deg, ${alpha('#1a1a1a', 0.9)} 0%, ${alpha('#2a2a2a', 0.9)} 100%)`
233
- : mapType === 'terrain'
234
- ? `linear-gradient(135deg, ${alpha('#7cb342', 0.1)} 0%, ${alpha('#558b2f', 0.1)} 100%)`
235
- : `linear-gradient(135deg, ${alpha(theme.palette.grey[100], 0.5)} 0%, ${alpha(theme.palette.grey[200], 0.5)} 100%)`,
236
- display: 'flex',
237
- alignItems: 'center',
238
- justifyContent: 'center',
239
- fontSize: '10px',
240
- color: alpha(theme.palette.text.secondary, 0.3),
241
- fontFamily: 'monospace',
242
- userSelect: 'none',
243
- }}
244
- >
245
- {zoom > 10 && `${tileX},${tileY}`}
246
- </div>
247
- );
248
- })}
249
- </div>
250
- );
251
- };
252
-
253
- // Create a more realistic map visualization
254
- return (
255
- <Box
256
- ref={mapRef}
257
- data-testid="static-map-view"
258
- sx={{
259
- width: '100%',
260
- height,
261
- position: 'relative',
262
- background: mapType === 'satellite'
263
- ? `linear-gradient(135deg, ${theme.palette.grey[900]} 0%, ${theme.palette.grey[800]} 100%)`
264
- : mapType === 'terrain'
265
- ? `linear-gradient(135deg, ${alpha('#8BC34A', 0.2)} 0%, ${alpha('#4CAF50', 0.3)} 100%)`
266
- : theme.palette.mode === 'dark'
267
- ? `linear-gradient(135deg, ${theme.palette.grey[900]} 0%, ${theme.palette.grey[800]} 100%)`
268
- : `linear-gradient(135deg, ${theme.palette.grey[100]} 0%, ${theme.palette.grey[200]} 100%)`,
269
- overflow: 'hidden',
270
- }}
271
- >
272
- {/* Map tiles */}
273
- <MapTiles />
274
-
275
- {/* Simulated map features */}
276
- <Box
277
- sx={{
278
- position: 'absolute',
279
- top: '20%',
280
- left: '15%',
281
- width: '70%',
282
- height: '60%',
283
- opacity: 0.2,
284
- }}
285
- >
286
- {/* Simulated roads */}
287
- <svg width="100%" height="100%" style={{ position: 'absolute' }}>
288
- <path
289
- d={`M 10,50 Q 30,30 50,50 T 90,50`}
290
- stroke={theme.palette.text.secondary}
291
- strokeWidth="2"
292
- fill="none"
293
- opacity="0.3"
294
- />
295
- <path
296
- d={`M 50,10 L 50,90`}
297
- stroke={theme.palette.text.secondary}
298
- strokeWidth="1.5"
299
- fill="none"
300
- opacity="0.3"
301
- />
302
- <path
303
- d={`M 20,30 L 80,70`}
304
- stroke={theme.palette.text.secondary}
305
- strokeWidth="1"
306
- fill="none"
307
- opacity="0.2"
308
- />
309
- </svg>
310
- </Box>
311
-
312
- {/* Center marker */}
313
- {marker && (
314
- <Box
315
- data-testid="map-marker"
316
- sx={{
317
- position: 'absolute',
318
- top: '50%',
319
- left: '50%',
320
- transform: 'translate(-50%, -100%)',
321
- zIndex: 2,
322
- filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.3))',
323
- }}
324
- >
325
- <LocationIcon
326
- sx={{
327
- fontSize: 36,
328
- color: theme.palette.error.main,
329
- animation: 'bounce 2s infinite',
330
- '@keyframes bounce': {
331
- '0%, 100%': { transform: 'translateY(0)' },
332
- '50%': { transform: 'translateY(-10px)' },
333
- },
334
- }}
335
- />
336
- </Box>
337
- )}
338
-
339
- {/* Additional map markers for realism */}
340
- <Box
341
- sx={{
342
- position: 'absolute',
343
- top: '30%',
344
- left: '25%',
345
- opacity: 0.6,
346
- }}
347
- >
348
- <PlaceIcon sx={{ fontSize: 20, color: theme.palette.primary.main }} />
349
- </Box>
350
- <Box
351
- sx={{
352
- position: 'absolute',
353
- top: '65%',
354
- left: '70%',
355
- opacity: 0.6,
356
- }}
357
- >
358
- <PlaceIcon sx={{ fontSize: 20, color: theme.palette.primary.main }} />
359
- </Box>
360
-
361
- {/* Scale indicator */}
362
- <Box
363
- sx={{
364
- position: 'absolute',
365
- bottom: theme.spacing(2),
366
- right: theme.spacing(2),
367
- display: 'flex',
368
- alignItems: 'center',
369
- gap: 0.5,
370
- padding: theme.spacing(0.5, 1),
371
- background: alpha(theme.palette.background.paper, 0.9),
372
- borderRadius: theme.shape.borderRadius,
373
- fontSize: '0.75rem',
374
- color: theme.palette.text.secondary,
375
- }}
376
- >
377
- <Box
378
- sx={{
379
- width: 40,
380
- height: 2,
381
- background: theme.palette.text.secondary,
382
- position: 'relative',
383
- '&::before, &::after': {
384
- content: '""',
385
- position: 'absolute',
386
- width: 2,
387
- height: 6,
388
- background: theme.palette.text.secondary,
389
- },
390
- '&::before': { left: 0, top: -2 },
391
- '&::after': { right: 0, top: -2 },
392
- }}
393
- />
394
- <Typography variant="caption">
395
- {MockGoogleMapsService.getScaleDistance(zoom)}
396
- </Typography>
397
- </Box>
398
-
399
- {/* Compass */}
400
- <Box
401
- sx={{
402
- position: 'absolute',
403
- top: theme.spacing(2),
404
- left: theme.spacing(2),
405
- width: 40,
406
- height: 40,
407
- display: 'flex',
408
- alignItems: 'center',
409
- justifyContent: 'center',
410
- background: alpha(theme.palette.background.paper, 0.9),
411
- borderRadius: '50%',
412
- boxShadow: theme.shadows[2],
413
- }}
414
- >
415
- <NavigationIcon
416
- sx={{
417
- fontSize: 24,
418
- color: theme.palette.primary.main,
419
- transform: 'rotate(-45deg)',
420
- }}
421
- />
422
- </Box>
423
- </Box>
424
- );
29
+ const cursorFor = (grabbing: boolean, interactive: boolean): string => {
30
+ if (grabbing) return 'grabbing';
31
+ return interactive ? 'grab' : 'default';
425
32
  };
426
33
 
427
- // Search bar component
428
- const SearchBar = styled(Box)(({ theme }) => ({
429
- position: 'absolute',
430
- top: theme.spacing(2),
431
- left: '50%',
432
- transform: 'translateX(-50%)',
433
- zIndex: 2,
434
- width: '90%',
435
- maxWidth: 400,
436
- }));
437
-
438
- const SearchField = styled(TextField)(({ theme }) => ({
439
- '& .MuiOutlinedInput-root': {
440
- background: alpha(theme.palette.background.paper, 0.95),
441
- backdropFilter: 'blur(10px)',
442
- WebkitBackdropFilter: 'blur(10px)',
443
- borderRadius: theme.shape.borderRadius * 2,
444
- '& fieldset': {
445
- borderColor: alpha(theme.palette.divider, 0.2),
446
- },
447
- },
448
- }));
449
-
450
- // Heatmap overlay component
451
- const HeatmapOverlay: FC<{ points: HeatmapPoint[]; width: number; height: number }> = ({ points, width, height }) => {
34
+ export const MapPreview: FC<MapPreviewProps> = (componentProps) => {
35
+ const props = resolveMapPreviewProps(componentProps);
452
36
  const theme = useTheme();
453
-
454
- if (!points || points.length === 0) return null;
455
-
456
- return (
457
- <svg
458
- style={{
459
- position: 'absolute',
460
- top: 0,
461
- left: 0,
462
- width: '100%',
463
- height: '100%',
464
- pointerEvents: 'none',
465
- zIndex: 1,
466
- }}
467
- viewBox={`0 0 ${width} ${height}`}
468
- >
469
- {points.map((point, index) => {
470
- const radius = 30 * point.weight;
471
- const opacity = 0.3 * point.weight;
472
- return (
473
- <circle
474
- key={index}
475
- cx={width / 2 + (point.lng * 10)}
476
- cy={height / 2 - (point.lat * 10)}
477
- r={radius}
478
- fill={theme.palette.error.main}
479
- opacity={opacity}
480
- />
481
- );
482
- })}
483
- </svg>
484
- );
485
- };
37
+ const { containerRef, view, controls, pointer, search, handleMapClick } = useMapPreview(props);
486
38
 
487
- // Route overlay component
488
- const RouteOverlay: FC<{ color: string }> = ({ color }) => {
489
- const theme = useTheme();
490
-
491
- return (
492
- <svg
493
- style={{
494
- position: 'absolute',
495
- top: 0,
496
- left: 0,
497
- width: '100%',
498
- height: '100%',
499
- pointerEvents: 'none',
500
- zIndex: 1,
501
- }}
502
- viewBox="0 0 100 100"
503
- >
504
- <path
505
- d="M 20,20 Q 40,10 50,30 T 80,80"
506
- stroke={color || theme.palette.primary.main}
507
- strokeWidth="3"
508
- fill="none"
509
- strokeDasharray="5,5"
510
- opacity="0.8"
511
- >
512
- <animate
513
- attributeName="stroke-dashoffset"
514
- values="0;10"
515
- dur="1s"
516
- repeatCount="indefinite"
517
- />
518
- </path>
519
- </svg>
520
- );
521
- };
522
-
523
- // Main component
524
- export const MapPreview: FC<MapPreviewProps> = ({
525
- center,
526
- coordinates: legacyCoordinates,
527
- markers = [],
528
- marker = true,
529
- height = '400px',
530
- interactive = false,
531
- zoom: initialZoom = 15,
532
- mapType = 'roadmap',
533
- variant = 'default',
534
- showControls = true,
535
- showSearch = false,
536
- searchPlaceholder = 'Search location...',
537
- showRoute = false,
538
- routeColor,
539
- heatmapData = [],
540
- showHeatmap = false,
541
- animated = true,
542
- onMarkerDrag,
543
- onMapClick,
544
- }) => {
545
- // Use center prop if provided, otherwise fall back to coordinates
546
- const coordinates = React.useMemo(() => center || legacyCoordinates || { lat: 0, lng: 0 }, [center, legacyCoordinates]);
547
- const originalCoordinates = React.useRef(coordinates);
548
-
549
- const [currentZoom, setCurrentZoom] = useState(initialZoom);
550
- const [currentMapType, setCurrentMapType] = useState<
551
- 'roadmap' | 'satellite' | 'hybrid' | 'terrain'
552
- >(mapType);
553
- const [markerPosition, setMarkerPosition] = useState(coordinates);
554
- const [isFullscreen, setIsFullscreen] = useState(false);
555
- const [searchValue, setSearchValue] = useState('');
556
- const [isDragging, setIsDragging] = useState(false);
557
- const [isPanning, setIsPanning] = useState(false);
558
- const [panOffset, setPanOffset] = useState({ x: 0, y: 0 });
559
- const [, setSearchResults] = useState<{ lat: number; lng: number } | null>(null);
560
- const [isSearching, setIsSearching] = useState(false);
561
- const mapContainerRef = useRef<HTMLDivElement>(null);
562
- const dragStartRef = useRef<{ x: number; y: number; lat: number; lng: number } | null>(null);
563
- const panStartRef = useRef<{ x: number; y: number; offsetX: number; offsetY: number } | null>(null);
564
-
565
- // Update marker position when coordinates change
566
- useEffect(() => {
567
- setMarkerPosition(coordinates);
568
- }, [coordinates]);
569
-
570
- const handleZoomIn = () => {
571
- const newZoom = Math.min(currentZoom + 1, 20);
572
- setCurrentZoom(newZoom);
573
- // Reset pan offset when zooming
574
- setPanOffset({ x: 0, y: 0 });
575
- };
576
-
577
- const handleZoomOut = () => {
578
- const newZoom = Math.max(currentZoom - 1, 1);
579
- setCurrentZoom(newZoom);
580
- // Reset pan offset when zooming
581
- setPanOffset({ x: 0, y: 0 });
582
- };
583
-
584
- const handleCenter = () => {
585
- originalCoordinates.current = coordinates; // Update ref with current coordinates
586
- setMarkerPosition({ ...coordinates }); // Reset to current coordinates
587
- setPanOffset({ x: 0, y: 0 });
588
- };
589
-
590
- const handleToggleMapType = () => {
591
- const types: Array<'roadmap' | 'satellite' | 'hybrid' | 'terrain'> = [
592
- 'roadmap',
593
- 'satellite',
594
- 'hybrid',
595
- 'terrain',
596
- ];
597
- const currentIndex = types.indexOf(currentMapType);
598
- const nextIndex = (currentIndex + 1) % types.length;
599
- const nextType = types[nextIndex] as 'roadmap' | 'satellite' | 'hybrid' | 'terrain';
600
- setCurrentMapType(nextType);
601
- };
602
-
603
- const handleFullscreen = () => {
604
- if (!isFullscreen && mapContainerRef.current) {
605
- mapContainerRef.current.requestFullscreen?.();
606
- } else if (document.fullscreenElement) {
607
- document.exitFullscreen?.();
608
- }
609
- setIsFullscreen(!isFullscreen);
610
- };
611
-
612
- // Handle map click for marker placement
613
- const handleMapClick = useCallback(() => {
614
- // Don't place marker if we're panning
615
- if (isPanning) return;
616
-
617
- // Simple coordinate offset calculation for testing
618
- const centerLat = coordinates.lat; // Use original coordinates as reference
619
- const centerLng = coordinates.lng;
620
-
621
- // Small random offset to simulate coordinate change
622
- const newCoords = {
623
- lat: centerLat + (Math.random() - 0.5) * 0.001,
624
- lng: centerLng + (Math.random() - 0.5) * 0.001
625
- };
626
-
627
- if (onMapClick) {
628
- onMapClick(newCoords.lat, newCoords.lng);
629
- }
630
-
631
- if (interactive && onMarkerDrag) {
632
- setMarkerPosition(newCoords);
633
- onMarkerDrag(newCoords);
634
- }
635
- }, [coordinates.lat, coordinates.lng, interactive, onMarkerDrag, onMapClick, isPanning]);
636
-
637
- // Handle pan/drag start
638
- const handleMouseDown = useCallback((event: React.MouseEvent<HTMLDivElement>) => {
639
- if (interactive) {
640
- // Check if we're clicking on empty map area (for panning)
641
- const target = event.target as HTMLElement;
642
- const isMapBackground = target.dataset.testid === 'static-map-view' ||
643
- target.closest('[data-testid="static-map-view"]');
644
-
645
- if (isMapBackground && event.shiftKey) {
646
- // Shift+drag for panning
647
- setIsPanning(true);
648
- panStartRef.current = {
649
- x: event.clientX,
650
- y: event.clientY,
651
- offsetX: panOffset.x,
652
- offsetY: panOffset.y,
653
- };
654
- } else {
655
- // Regular drag for marker movement
656
- setIsDragging(true);
657
- dragStartRef.current = {
658
- x: event.clientX,
659
- y: event.clientY,
660
- lat: markerPosition.lat,
661
- lng: markerPosition.lng,
662
- };
663
- }
664
- }
665
- }, [interactive, markerPosition, panOffset]);
666
-
667
- // Handle pan/drag movement
668
- const handleMouseMove = useCallback((event: React.MouseEvent<HTMLDivElement>) => {
669
- if (isPanning && panStartRef.current) {
670
- // Handle map panning
671
- const deltaX = event.clientX - panStartRef.current.x;
672
- const deltaY = event.clientY - panStartRef.current.y;
673
-
674
- setPanOffset({
675
- x: panStartRef.current.offsetX + deltaX,
676
- y: panStartRef.current.offsetY + deltaY,
677
- });
678
- } else if (isDragging && dragStartRef.current) {
679
- // Handle marker dragging
680
- const deltaX = event.clientX - dragStartRef.current.x;
681
- const deltaY = event.clientY - dragStartRef.current.y;
682
-
683
- // Simple drag simulation for testing
684
- const newPosition = {
685
- lat: dragStartRef.current.lat + deltaY * 0.0001,
686
- lng: dragStartRef.current.lng + deltaX * 0.0001
687
- };
688
-
689
- setMarkerPosition(newPosition);
690
- if (onMarkerDrag) {
691
- onMarkerDrag(newPosition);
692
- }
693
- }
694
- }, [isDragging, isPanning, onMarkerDrag]);
695
-
696
- // Handle pan/drag end
697
- const handleMouseUp = useCallback(() => {
698
- setIsDragging(false);
699
- setIsPanning(false);
700
- dragStartRef.current = null;
701
- panStartRef.current = null;
702
- }, []);
703
-
704
- // Handle search
705
- const handleSearch = useCallback(async (event: React.KeyboardEvent<HTMLInputElement>) => {
706
- if (event.key === 'Enter' && searchValue) {
707
- setIsSearching(true);
708
- try {
709
- const result = await MockGoogleMapsService.geocode(searchValue);
710
- if (result) {
711
- setSearchResults(result);
712
- setMarkerPosition({ ...result }); // Create new object to ensure update
713
- setPanOffset({ x: 0, y: 0 });
714
- // Zoom to appropriate level for city view
715
- setCurrentZoom(12);
716
- } else {
717
- // No results found - could show an error message in production
718
- // In production, this would trigger an error toast or notification
719
- }
720
- } finally {
721
- setIsSearching(false);
722
- }
723
- }
724
- }, [searchValue]);
725
-
726
- // Get glass effect styles
727
- const getGlassStyles = () => {
728
- if (variant === 'glass') {
729
- return {
730
- background: alpha(theme.palette.background.paper, 0.7),
731
- backdropFilter: 'blur(20px)',
732
- WebkitBackdropFilter: 'blur(20px)',
733
- border: `1px solid ${alpha(theme.palette.divider, 0.1)}`,
734
- };
735
- }
736
- return {};
737
- };
738
-
739
- const theme = useTheme();
39
+ const height = controls.isFullscreen ? '100vh' : props.height;
40
+ const grabbing = pointer.isDragging || pointer.isPanning;
740
41
 
741
42
  return (
742
43
  <MapContainer
743
- ref={mapContainerRef}
744
- elevation={variant === 'glass' ? 0 : 2}
44
+ ref={containerRef}
45
+ elevation={props.variant === 'glass' ? 0 : 2}
745
46
  data-testid="map-preview-container"
746
47
  role="img"
747
- aria-label={`Map preview centered at ${markerPosition.lat.toFixed(4)}, ${markerPosition.lng.toFixed(4)} with zoom level ${currentZoom}`}
48
+ aria-label={`Map preview centered at ${view.markerPosition.lat.toFixed(4)}, ${view.markerPosition.lng.toFixed(4)} with zoom level ${view.zoom}`}
748
49
  tabIndex={0}
749
50
  aria-live="polite"
750
51
  aria-atomic="true"
751
- sx={getGlassStyles()}
52
+ sx={glassStyles(props.variant, theme)}
752
53
  >
753
- <MapWrapper
754
- height={isFullscreen ? '100vh' : height}
54
+ <MapWrapper
55
+ height={height}
755
56
  onClick={handleMapClick}
756
- onMouseDown={handleMouseDown}
757
- onMouseMove={handleMouseMove}
758
- onMouseUp={handleMouseUp}
759
- onMouseLeave={handleMouseUp}
760
- style={{
761
- cursor: isDragging || isPanning ? 'grabbing' : interactive ? 'grab' : 'default',
762
- transition: animated ? 'all 0.3s ease' : 'none',
57
+ onMouseDown={pointer.handleMouseDown}
58
+ onMouseMove={pointer.handleMouseMove}
59
+ onMouseUp={pointer.handleMouseUp}
60
+ onMouseLeave={pointer.handleMouseUp}
61
+ style={{
62
+ cursor: cursorFor(grabbing, props.interactive),
63
+ transition: props.animated ? 'all 0.3s ease' : 'none',
763
64
  }}
764
65
  >
765
- {/* Use our realistic static map visualization */}
766
- <StaticMapView
767
- coordinates={coordinates}
768
- height={isFullscreen ? '100vh' : height}
769
- zoom={currentZoom}
770
- mapType={currentMapType}
771
- marker={marker && markers.length === 0}
772
- markerPosition={markerPosition}
773
- panOffset={panOffset}
66
+ <StaticMapView
67
+ height={height}
68
+ zoom={view.zoom}
69
+ mapType={view.mapType}
70
+ // The built-in centre marker steps aside for an explicit marker list.
71
+ marker={props.marker && props.markers.length === 0}
72
+ markerPosition={view.markerPosition}
73
+ panOffset={view.panOffset}
774
74
  />
775
-
776
- {/* Render multiple markers */}
777
- {markers.map((markerItem, index) => (
778
- <Box
779
- key={index}
780
- data-testid={`map-marker-${index}`}
781
- sx={{
782
- position: 'absolute',
783
- top: '50%',
784
- left: '50%',
785
- transform: `translate(
786
- ${(markerItem.position.lng - markerPosition.lng) * 100}px,
787
- ${-(markerItem.position.lat - markerPosition.lat) * 100}px
788
- )`,
789
- zIndex: 3,
790
- cursor: markerItem.onClick ? 'pointer' : 'default',
791
- }}
792
- onClick={markerItem.onClick}
793
- title={markerItem.title}
794
- >
795
- <Tooltip title={markerItem.description || markerItem.title || ''}>
796
- <LocationIcon
797
- sx={{
798
- fontSize: 32,
799
- color: theme.palette.error.main,
800
- filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.3))',
801
- animation: animated ? 'bounce 2s infinite' : 'none',
802
- '@keyframes bounce': {
803
- '0%, 100%': { transform: 'translateY(0)' },
804
- '50%': { transform: 'translateY(-10px)' },
805
- },
806
- }}
807
- />
808
- </Tooltip>
809
- </Box>
810
- ))}
811
-
812
- {/* Heatmap overlay */}
813
- {showHeatmap && heatmapData.length > 0 && (
814
- <HeatmapOverlay
815
- points={heatmapData}
816
- width={800}
817
- height={400}
818
- />
819
- )}
820
-
821
- {/* Route overlay */}
822
- {showRoute && (
823
- <RouteOverlay color={routeColor || theme.palette.primary.main} />
824
- )}
825
-
826
- {/* Search bar */}
827
- {showSearch && (
828
- <SearchBar>
829
- <SearchField
830
- fullWidth
831
- size="small"
832
- placeholder={searchPlaceholder}
833
- value={searchValue}
834
- onChange={(e) => setSearchValue(e.target.value)}
835
- onKeyPress={handleSearch}
836
- InputProps={{
837
- startAdornment: (
838
- <InputAdornment position="start">
839
- <SearchIcon fontSize="small" sx={{ opacity: isSearching ? 0.5 : 1 }} />
840
- </InputAdornment>
841
- ),
842
- }}
843
- disabled={isSearching}
844
- aria-label="Search location"
845
- />
846
- </SearchBar>
847
- )}
848
75
 
849
- {showControls && (
850
- <MapControls data-testid="map-controls">
851
- <Tooltip title="Zoom in" placement="left">
852
- <ControlButton
853
- size="small"
854
- onClick={handleZoomIn}
855
- aria-label="Zoom in"
856
- data-testid="zoom-in-button"
857
- disabled={currentZoom >= 20}
858
- >
859
- <ZoomInIcon fontSize="small" />
860
- </ControlButton>
861
- </Tooltip>
862
- <Tooltip title="Zoom out" placement="left">
863
- <ControlButton
864
- size="small"
865
- onClick={handleZoomOut}
866
- aria-label="Zoom out"
867
- data-testid="zoom-out-button"
868
- disabled={currentZoom <= 1}
869
- >
870
- <ZoomOutIcon fontSize="small" />
871
- </ControlButton>
872
- </Tooltip>
873
- <Tooltip title="Center map" placement="left">
874
- <ControlButton
875
- size="small"
876
- onClick={handleCenter}
877
- aria-label="Center map"
878
- data-testid="center-button"
879
- >
880
- <CenterIcon fontSize="small" />
881
- </ControlButton>
882
- </Tooltip>
883
- <Tooltip title={`Map type: ${currentMapType}`} placement="left">
884
- <ControlButton
885
- size="small"
886
- onClick={handleToggleMapType}
887
- aria-label="Change map type"
888
- data-testid="map-type-button"
889
- >
890
- <LayersIcon fontSize="small" />
891
- </ControlButton>
892
- </Tooltip>
893
- <Tooltip title="Toggle fullscreen" placement="left">
894
- <ControlButton
895
- size="small"
896
- onClick={handleFullscreen}
897
- aria-label="Toggle fullscreen"
898
- data-testid="fullscreen-button"
899
- >
900
- <FullscreenIcon fontSize="small" />
901
- </ControlButton>
902
- </Tooltip>
903
- </MapControls>
904
- )}
76
+ <MapMarkers markers={props.markers} centre={view.markerPosition} animated={props.animated} />
77
+
78
+ <MapLayers
79
+ settings={props}
80
+ zoom={view.zoom}
81
+ mapType={view.mapType}
82
+ search={search}
83
+ controls={controls}
84
+ />
905
85
 
906
- <CoordinatesDisplay data-testid="coordinates-display">
907
- <Typography variant="caption" sx={{ fontFamily: 'monospace' }}>
908
- Lat: {markerPosition.lat.toFixed(6)}, Lng: {markerPosition.lng.toFixed(6)}
909
- </Typography>
910
- {currentZoom && (
911
- <Typography variant="caption" sx={{ fontFamily: 'monospace', display: 'block' }}>
912
- Zoom: {currentZoom}
913
- </Typography>
914
- )}
915
- </CoordinatesDisplay>
86
+ <MapCoordinates position={view.markerPosition} zoom={view.zoom} />
916
87
  </MapWrapper>
917
88
  </MapContainer>
918
89
  );
919
90
  };
920
91
 
921
- // Export default
922
92
  export default MapPreview;