@maydon_tech/react-native-nitro-maps 0.1.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 (283) hide show
  1. package/LICENSE +20 -0
  2. package/NitroMap.podspec +42 -0
  3. package/README.md +172 -0
  4. package/android/CMakeLists.txt +27 -0
  5. package/android/build.gradle +141 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +3 -0
  8. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  9. package/android/src/main/java/com/margelo/nitro/nitromap/ClusterIconGenerator.kt +108 -0
  10. package/android/src/main/java/com/margelo/nitro/nitromap/ColorUtils.kt +63 -0
  11. package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMap.kt +408 -0
  12. package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMapConfig.kt +68 -0
  13. package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconCache.kt +176 -0
  14. package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconFactory.kt +252 -0
  15. package/android/src/main/java/com/margelo/nitro/nitromap/NitroMapPackage.kt +33 -0
  16. package/android/src/main/java/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +252 -0
  17. package/android/src/main/java/com/margelo/nitro/nitromap/clustering/QuadTree.kt +195 -0
  18. package/android/src/main/java/com/margelo/nitro/nitromap/providers/GoogleMapProvider.kt +912 -0
  19. package/android/src/main/java/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +70 -0
  20. package/cpp/ClusterEngine.hpp +411 -0
  21. package/cpp/KDBush.hpp +238 -0
  22. package/cpp/QuadTree.hpp +246 -0
  23. package/ios/Clustering/ClusterEngineWrapper.h +58 -0
  24. package/ios/Clustering/ClusterEngineWrapper.mm +142 -0
  25. package/ios/Clustering/ClusterIconRenderer.swift +80 -0
  26. package/ios/Clustering/NitroClusterEngine.swift +117 -0
  27. package/ios/Clustering/NitroClusterIconGenerator.swift +35 -0
  28. package/ios/MarkerRenderer/MarkerIconFactory.swift +322 -0
  29. package/ios/MarkerRenderer/PriceMarkerRenderer.swift +140 -0
  30. package/ios/NitroMap.swift +332 -0
  31. package/ios/NitroMapConfig/HybridNitroMapConfig.swift +33 -0
  32. package/ios/Providers/GoogleMapDelegate.swift +310 -0
  33. package/ios/Providers/GoogleMapProvider+Camera.swift +164 -0
  34. package/ios/Providers/GoogleMapProvider.swift +924 -0
  35. package/ios/Providers/MapProviderProtocol.swift +78 -0
  36. package/ios/Shared/ClusterConfig+Factory.swift +58 -0
  37. package/ios/Shared/ClusteringManager.swift +211 -0
  38. package/ios/Shared/MapStyleProvider.swift +135 -0
  39. package/ios/Shared/MarkerSelectionHandler.swift +116 -0
  40. package/ios/Utils/ColorValueExtension.swift +54 -0
  41. package/lib/module/components/ImageMarker.js +146 -0
  42. package/lib/module/components/ImageMarker.js.map +1 -0
  43. package/lib/module/components/NitroMap.js +320 -0
  44. package/lib/module/components/NitroMap.js.map +1 -0
  45. package/lib/module/components/PriceMarker.js +165 -0
  46. package/lib/module/components/PriceMarker.js.map +1 -0
  47. package/lib/module/context/NitroMapContext.js +15 -0
  48. package/lib/module/context/NitroMapContext.js.map +1 -0
  49. package/lib/module/hooks/useNitroMarker.js +104 -0
  50. package/lib/module/hooks/useNitroMarker.js.map +1 -0
  51. package/lib/module/index.js +21 -0
  52. package/lib/module/index.js.map +1 -0
  53. package/lib/module/modules/index.js +4 -0
  54. package/lib/module/modules/index.js.map +1 -0
  55. package/lib/module/modules/module.js +30 -0
  56. package/lib/module/modules/module.js.map +1 -0
  57. package/lib/module/package.json +1 -0
  58. package/lib/module/specs/NitroMap.nitro.js +4 -0
  59. package/lib/module/specs/NitroMap.nitro.js.map +1 -0
  60. package/lib/module/specs/NitroMapConfig.nitro.js +4 -0
  61. package/lib/module/specs/NitroMapConfig.nitro.js.map +1 -0
  62. package/lib/module/types/map.js +2 -0
  63. package/lib/module/types/map.js.map +1 -0
  64. package/lib/module/types/marker.js +4 -0
  65. package/lib/module/types/marker.js.map +1 -0
  66. package/lib/module/utils/colors.js +147 -0
  67. package/lib/module/utils/colors.js.map +1 -0
  68. package/lib/typescript/package.json +1 -0
  69. package/lib/typescript/src/components/ImageMarker.d.ts +70 -0
  70. package/lib/typescript/src/components/ImageMarker.d.ts.map +1 -0
  71. package/lib/typescript/src/components/NitroMap.d.ts +14 -0
  72. package/lib/typescript/src/components/NitroMap.d.ts.map +1 -0
  73. package/lib/typescript/src/components/PriceMarker.d.ts +88 -0
  74. package/lib/typescript/src/components/PriceMarker.d.ts.map +1 -0
  75. package/lib/typescript/src/context/NitroMapContext.d.ts +16 -0
  76. package/lib/typescript/src/context/NitroMapContext.d.ts.map +1 -0
  77. package/lib/typescript/src/hooks/useNitroMarker.d.ts +78 -0
  78. package/lib/typescript/src/hooks/useNitroMarker.d.ts.map +1 -0
  79. package/lib/typescript/src/index.d.ts +12 -0
  80. package/lib/typescript/src/index.d.ts.map +1 -0
  81. package/lib/typescript/src/modules/index.d.ts +2 -0
  82. package/lib/typescript/src/modules/index.d.ts.map +1 -0
  83. package/lib/typescript/src/modules/module.d.ts +22 -0
  84. package/lib/typescript/src/modules/module.d.ts.map +1 -0
  85. package/lib/typescript/src/specs/NitroMap.nitro.d.ts +227 -0
  86. package/lib/typescript/src/specs/NitroMap.nitro.d.ts.map +1 -0
  87. package/lib/typescript/src/specs/NitroMapConfig.nitro.d.ts +10 -0
  88. package/lib/typescript/src/specs/NitroMapConfig.nitro.d.ts.map +1 -0
  89. package/lib/typescript/src/types/map.d.ts +154 -0
  90. package/lib/typescript/src/types/map.d.ts.map +1 -0
  91. package/lib/typescript/src/types/marker.d.ts +248 -0
  92. package/lib/typescript/src/types/marker.d.ts.map +1 -0
  93. package/lib/typescript/src/utils/colors.d.ts +82 -0
  94. package/lib/typescript/src/utils/colors.d.ts.map +1 -0
  95. package/nitro.json +21 -0
  96. package/nitrogen/generated/android/c++/JCamera.hpp +74 -0
  97. package/nitrogen/generated/android/c++/JClusterAnimationStyle.hpp +68 -0
  98. package/nitrogen/generated/android/c++/JClusterConfig.hpp +121 -0
  99. package/nitrogen/generated/android/c++/JClusterPressEvent.hpp +86 -0
  100. package/nitrogen/generated/android/c++/JClusterStrategy.hpp +59 -0
  101. package/nitrogen/generated/android/c++/JColorValue.cpp +26 -0
  102. package/nitrogen/generated/android/c++/JColorValue.hpp +70 -0
  103. package/nitrogen/generated/android/c++/JCoordinate.hpp +61 -0
  104. package/nitrogen/generated/android/c++/JEdgePadding.hpp +69 -0
  105. package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  106. package/nitrogen/generated/android/c++/JFunc_void_ClusterPressEvent.hpp +81 -0
  107. package/nitrogen/generated/android/c++/JFunc_void_MapError.hpp +78 -0
  108. package/nitrogen/generated/android/c++/JFunc_void_MapPressEvent.hpp +81 -0
  109. package/nitrogen/generated/android/c++/JFunc_void_MarkerDragEvent.hpp +80 -0
  110. package/nitrogen/generated/android/c++/JFunc_void_MarkerPressEvent.hpp +80 -0
  111. package/nitrogen/generated/android/c++/JFunc_void_RegionChangeEvent.hpp +79 -0
  112. package/nitrogen/generated/android/c++/JHybridNitroMapConfigSpec.cpp +59 -0
  113. package/nitrogen/generated/android/c++/JHybridNitroMapConfigSpec.hpp +66 -0
  114. package/nitrogen/generated/android/c++/JHybridNitroMapSpec.cpp +593 -0
  115. package/nitrogen/generated/android/c++/JHybridNitroMapSpec.hpp +125 -0
  116. package/nitrogen/generated/android/c++/JImageMarkerConfig.hpp +86 -0
  117. package/nitrogen/generated/android/c++/JMapBoundaries.hpp +62 -0
  118. package/nitrogen/generated/android/c++/JMapError.hpp +61 -0
  119. package/nitrogen/generated/android/c++/JMapPressEvent.hpp +64 -0
  120. package/nitrogen/generated/android/c++/JMapProvider.hpp +62 -0
  121. package/nitrogen/generated/android/c++/JMapStyleElement.hpp +87 -0
  122. package/nitrogen/generated/android/c++/JMapStyler.hpp +78 -0
  123. package/nitrogen/generated/android/c++/JMapType.hpp +62 -0
  124. package/nitrogen/generated/android/c++/JMarkerAnimation.hpp +62 -0
  125. package/nitrogen/generated/android/c++/JMarkerColor.hpp +69 -0
  126. package/nitrogen/generated/android/c++/JMarkerConfig.hpp +77 -0
  127. package/nitrogen/generated/android/c++/JMarkerData.hpp +121 -0
  128. package/nitrogen/generated/android/c++/JMarkerDragEvent.hpp +63 -0
  129. package/nitrogen/generated/android/c++/JMarkerPressEvent.hpp +63 -0
  130. package/nitrogen/generated/android/c++/JMarkerStyle.hpp +62 -0
  131. package/nitrogen/generated/android/c++/JPoint.hpp +61 -0
  132. package/nitrogen/generated/android/c++/JPriceMarkerStyle.hpp +102 -0
  133. package/nitrogen/generated/android/c++/JRegion.hpp +69 -0
  134. package/nitrogen/generated/android/c++/JRegionChangeEvent.hpp +62 -0
  135. package/nitrogen/generated/android/c++/JVariant_String_MarkerColor.cpp +26 -0
  136. package/nitrogen/generated/android/c++/JVariant_String_MarkerColor.hpp +70 -0
  137. package/nitrogen/generated/android/c++/views/JHybridNitroMapStateUpdater.cpp +144 -0
  138. package/nitrogen/generated/android/c++/views/JHybridNitroMapStateUpdater.hpp +49 -0
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Camera.kt +50 -0
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterAnimationStyle.kt +24 -0
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterConfig.kt +80 -0
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterPressEvent.kt +44 -0
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterStrategy.kt +21 -0
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ColorValue.kt +59 -0
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Coordinate.kt +41 -0
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/EdgePadding.kt +47 -0
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void.kt +80 -0
  148. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_ClusterPressEvent.kt +80 -0
  149. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MapError.kt +80 -0
  150. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MapPressEvent.kt +80 -0
  151. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MarkerDragEvent.kt +80 -0
  152. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_MarkerPressEvent.kt +80 -0
  153. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_RegionChangeEvent.kt +80 -0
  154. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/HybridNitroMapConfigSpec.kt +61 -0
  155. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/HybridNitroMapSpec.kt +342 -0
  156. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ImageMarkerConfig.kt +56 -0
  157. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapBoundaries.kt +41 -0
  158. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapError.kt +41 -0
  159. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapPressEvent.kt +41 -0
  160. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapProvider.kt +22 -0
  161. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapStyleElement.kt +44 -0
  162. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapStyler.kt +53 -0
  163. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MapType.kt +22 -0
  164. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerAnimation.kt +22 -0
  165. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerColor.kt +47 -0
  166. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerConfig.kt +44 -0
  167. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerData.kt +71 -0
  168. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerDragEvent.kt +41 -0
  169. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerPressEvent.kt +41 -0
  170. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerStyle.kt +22 -0
  171. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Point.kt +41 -0
  172. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PriceMarkerStyle.kt +68 -0
  173. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Region.kt +47 -0
  174. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/RegionChangeEvent.kt +41 -0
  175. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Variant_String_MarkerColor.kt +59 -0
  176. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/nitromapOnLoad.kt +35 -0
  177. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/views/HybridNitroMapManager.kt +50 -0
  178. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/views/HybridNitroMapStateUpdater.kt +23 -0
  179. package/nitrogen/generated/android/nitromap+autolinking.cmake +87 -0
  180. package/nitrogen/generated/android/nitromap+autolinking.gradle +27 -0
  181. package/nitrogen/generated/android/nitromapOnLoad.cpp +70 -0
  182. package/nitrogen/generated/android/nitromapOnLoad.hpp +25 -0
  183. package/nitrogen/generated/ios/NitroMap+autolinking.rb +60 -0
  184. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.cpp +130 -0
  185. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.hpp +793 -0
  186. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Umbrella.hpp +132 -0
  187. package/nitrogen/generated/ios/NitroMapAutolinking.mm +41 -0
  188. package/nitrogen/generated/ios/NitroMapAutolinking.swift +40 -0
  189. package/nitrogen/generated/ios/c++/HybridNitroMapConfigSpecSwift.cpp +11 -0
  190. package/nitrogen/generated/ios/c++/HybridNitroMapConfigSpecSwift.hpp +84 -0
  191. package/nitrogen/generated/ios/c++/HybridNitroMapSpecSwift.cpp +11 -0
  192. package/nitrogen/generated/ios/c++/HybridNitroMapSpecSwift.hpp +410 -0
  193. package/nitrogen/generated/ios/c++/views/HybridNitroMapComponent.mm +206 -0
  194. package/nitrogen/generated/ios/swift/Camera.swift +80 -0
  195. package/nitrogen/generated/ios/swift/ClusterAnimationStyle.swift +52 -0
  196. package/nitrogen/generated/ios/swift/ClusterConfig.swift +268 -0
  197. package/nitrogen/generated/ios/swift/ClusterPressEvent.swift +70 -0
  198. package/nitrogen/generated/ios/swift/ClusterStrategy.swift +40 -0
  199. package/nitrogen/generated/ios/swift/ColorValue.swift +18 -0
  200. package/nitrogen/generated/ios/swift/Coordinate.swift +47 -0
  201. package/nitrogen/generated/ios/swift/EdgePadding.swift +69 -0
  202. package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
  203. package/nitrogen/generated/ios/swift/Func_void_Camera.swift +47 -0
  204. package/nitrogen/generated/ios/swift/Func_void_ClusterPressEvent.swift +47 -0
  205. package/nitrogen/generated/ios/swift/Func_void_MapBoundaries.swift +47 -0
  206. package/nitrogen/generated/ios/swift/Func_void_MapError.swift +47 -0
  207. package/nitrogen/generated/ios/swift/Func_void_MapPressEvent.swift +47 -0
  208. package/nitrogen/generated/ios/swift/Func_void_MarkerDragEvent.swift +47 -0
  209. package/nitrogen/generated/ios/swift/Func_void_MarkerPressEvent.swift +47 -0
  210. package/nitrogen/generated/ios/swift/Func_void_RegionChangeEvent.swift +47 -0
  211. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
  212. package/nitrogen/generated/ios/swift/HybridNitroMapConfigSpec.swift +57 -0
  213. package/nitrogen/generated/ios/swift/HybridNitroMapConfigSpec_cxx.swift +142 -0
  214. package/nitrogen/generated/ios/swift/HybridNitroMapSpec.swift +93 -0
  215. package/nitrogen/generated/ios/swift/HybridNitroMapSpec_cxx.swift +953 -0
  216. package/nitrogen/generated/ios/swift/ImageMarkerConfig.swift +166 -0
  217. package/nitrogen/generated/ios/swift/MapBoundaries.swift +47 -0
  218. package/nitrogen/generated/ios/swift/MapError.swift +47 -0
  219. package/nitrogen/generated/ios/swift/MapPressEvent.swift +47 -0
  220. package/nitrogen/generated/ios/swift/MapProvider.swift +44 -0
  221. package/nitrogen/generated/ios/swift/MapStyleElement.swift +108 -0
  222. package/nitrogen/generated/ios/swift/MapStyler.swift +177 -0
  223. package/nitrogen/generated/ios/swift/MapType.swift +44 -0
  224. package/nitrogen/generated/ios/swift/MarkerAnimation.swift +44 -0
  225. package/nitrogen/generated/ios/swift/MarkerColor.swift +69 -0
  226. package/nitrogen/generated/ios/swift/MarkerConfig.swift +82 -0
  227. package/nitrogen/generated/ios/swift/MarkerData.swift +195 -0
  228. package/nitrogen/generated/ios/swift/MarkerDragEvent.swift +47 -0
  229. package/nitrogen/generated/ios/swift/MarkerPressEvent.swift +47 -0
  230. package/nitrogen/generated/ios/swift/MarkerStyle.swift +44 -0
  231. package/nitrogen/generated/ios/swift/Point.swift +47 -0
  232. package/nitrogen/generated/ios/swift/PriceMarkerStyle.swift +374 -0
  233. package/nitrogen/generated/ios/swift/Region.swift +69 -0
  234. package/nitrogen/generated/ios/swift/RegionChangeEvent.swift +47 -0
  235. package/nitrogen/generated/ios/swift/Variant_String_MarkerColor.swift +18 -0
  236. package/nitrogen/generated/shared/c++/Camera.hpp +92 -0
  237. package/nitrogen/generated/shared/c++/ClusterAnimationStyle.hpp +88 -0
  238. package/nitrogen/generated/shared/c++/ClusterConfig.hpp +140 -0
  239. package/nitrogen/generated/shared/c++/ClusterPressEvent.hpp +86 -0
  240. package/nitrogen/generated/shared/c++/ClusterStrategy.hpp +76 -0
  241. package/nitrogen/generated/shared/c++/Coordinate.hpp +79 -0
  242. package/nitrogen/generated/shared/c++/EdgePadding.hpp +87 -0
  243. package/nitrogen/generated/shared/c++/HybridNitroMapConfigSpec.cpp +22 -0
  244. package/nitrogen/generated/shared/c++/HybridNitroMapConfigSpec.hpp +65 -0
  245. package/nitrogen/generated/shared/c++/HybridNitroMapSpec.cpp +82 -0
  246. package/nitrogen/generated/shared/c++/HybridNitroMapSpec.hpp +173 -0
  247. package/nitrogen/generated/shared/c++/ImageMarkerConfig.hpp +103 -0
  248. package/nitrogen/generated/shared/c++/MapBoundaries.hpp +80 -0
  249. package/nitrogen/generated/shared/c++/MapError.hpp +79 -0
  250. package/nitrogen/generated/shared/c++/MapPressEvent.hpp +83 -0
  251. package/nitrogen/generated/shared/c++/MapProvider.hpp +80 -0
  252. package/nitrogen/generated/shared/c++/MapStyleElement.hpp +87 -0
  253. package/nitrogen/generated/shared/c++/MapStyler.hpp +96 -0
  254. package/nitrogen/generated/shared/c++/MapType.hpp +80 -0
  255. package/nitrogen/generated/shared/c++/MarkerAnimation.hpp +80 -0
  256. package/nitrogen/generated/shared/c++/MarkerColor.hpp +87 -0
  257. package/nitrogen/generated/shared/c++/MarkerConfig.hpp +91 -0
  258. package/nitrogen/generated/shared/c++/MarkerData.hpp +131 -0
  259. package/nitrogen/generated/shared/c++/MarkerDragEvent.hpp +81 -0
  260. package/nitrogen/generated/shared/c++/MarkerPressEvent.hpp +81 -0
  261. package/nitrogen/generated/shared/c++/MarkerStyle.hpp +80 -0
  262. package/nitrogen/generated/shared/c++/Point.hpp +79 -0
  263. package/nitrogen/generated/shared/c++/PriceMarkerStyle.hpp +119 -0
  264. package/nitrogen/generated/shared/c++/Region.hpp +87 -0
  265. package/nitrogen/generated/shared/c++/RegionChangeEvent.hpp +80 -0
  266. package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.cpp +351 -0
  267. package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.hpp +141 -0
  268. package/nitrogen/generated/shared/json/NitroMapConfig.json +32 -0
  269. package/package.json +176 -0
  270. package/react-native.config.js +16 -0
  271. package/src/components/ImageMarker.tsx +254 -0
  272. package/src/components/NitroMap.tsx +433 -0
  273. package/src/components/PriceMarker.tsx +311 -0
  274. package/src/context/NitroMapContext.tsx +33 -0
  275. package/src/hooks/useNitroMarker.ts +198 -0
  276. package/src/index.tsx +62 -0
  277. package/src/modules/index.ts +6 -0
  278. package/src/modules/module.ts +45 -0
  279. package/src/specs/NitroMap.nitro.ts +292 -0
  280. package/src/specs/NitroMapConfig.nitro.ts +8 -0
  281. package/src/types/map.ts +166 -0
  282. package/src/types/marker.ts +267 -0
  283. package/src/utils/colors.ts +159 -0
@@ -0,0 +1,332 @@
1
+ import Foundation
2
+ import NitroModules
3
+ import UIKit
4
+
5
+ /// HybridNitroMap - Google Maps powered map view.
6
+ ///
7
+ /// Threading contract:
8
+ /// - All UI/SDK operations are dispatched to main thread HERE.
9
+ /// - GoogleMapProvider assumes it is ALWAYS called from main thread.
10
+ /// - Props are stored locally; forwarded to provider via optional chaining
11
+ /// (no-op if provider isn't initialized yet). `afterUpdate()` ensures
12
+ /// provider is created and settings applied.
13
+ class HybridNitroMap: HybridNitroMapSpec {
14
+
15
+ // MARK: - Provider
16
+
17
+ private let containerView: UIView = {
18
+ let view = UIView()
19
+ view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
20
+ return view
21
+ }()
22
+
23
+ /// The provider is created lazily on first `afterUpdate()` or first
24
+ /// imperative method call. This avoids premature init before the view
25
+ /// has valid bounds.
26
+ private var _provider: GoogleMapProvider?
27
+
28
+ /// Returns the provider, initializing it if needed.
29
+ /// Must be called from the main thread.
30
+ private var mapProvider: GoogleMapProvider {
31
+ if _provider == nil {
32
+ initializeProvider()
33
+ }
34
+ return _provider!
35
+ }
36
+
37
+ private func initializeProvider() {
38
+ let provider = GoogleMapProvider()
39
+ provider.setup()
40
+
41
+ let providerView = provider.mapView
42
+ providerView.frame = containerView.bounds
43
+ providerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
44
+ containerView.addSubview(providerView)
45
+
46
+ _provider = provider
47
+ applyCurrentSettings(to: provider)
48
+ }
49
+
50
+ private func applyCurrentSettings(to provider: GoogleMapProvider) {
51
+ provider.initialRegion = initialRegion
52
+ provider.showsUserLocation = showsUserLocation
53
+ provider.zoomEnabled = zoomEnabled
54
+ provider.scrollEnabled = scrollEnabled
55
+ provider.rotateEnabled = rotateEnabled
56
+ provider.pitchEnabled = pitchEnabled
57
+ provider.mapType = mapType
58
+ provider.showsMyLocationButton = showsMyLocationButton
59
+ provider.clusterConfig = clusterConfig
60
+ provider.customMapStyle = customMapStyle
61
+ provider.darkMode = darkMode
62
+
63
+ provider.onPress = onPress
64
+ provider.onLongPress = onLongPress
65
+ provider.onMapReady = onMapReady
66
+ provider.onRegionChange = onRegionChange
67
+ provider.onRegionChangeComplete = onRegionChangeComplete
68
+ provider.onMarkerPress = onMarkerPress
69
+ provider.onMarkerDragStart = onMarkerDragStart
70
+ provider.onMarkerDrag = onMarkerDrag
71
+ provider.onMarkerDragEnd = onMarkerDragEnd
72
+ provider.onClusterPress = onClusterPress
73
+ provider.onError = onError
74
+ }
75
+
76
+ var view: UIView { return containerView }
77
+
78
+ // Provider prop from JS — currently only Google is supported
79
+ var provider: MapProvider? {
80
+ didSet {
81
+ // Only Google Maps is supported — ignored for now
82
+ }
83
+ }
84
+
85
+ // MARK: - Properties
86
+ // Stored locally. Forwarded to provider via optional chaining so
87
+ // setting a prop before the provider is ready is a no-op (the values
88
+ // are pushed in bulk via applyCurrentSettings when provider inits).
89
+
90
+ var initialRegion: Region? {
91
+ didSet { _provider?.initialRegion = initialRegion }
92
+ }
93
+
94
+ var showsUserLocation: Bool? {
95
+ didSet { _provider?.showsUserLocation = showsUserLocation }
96
+ }
97
+
98
+ var zoomEnabled: Bool? {
99
+ didSet { _provider?.zoomEnabled = zoomEnabled }
100
+ }
101
+
102
+ var scrollEnabled: Bool? {
103
+ didSet { _provider?.scrollEnabled = scrollEnabled }
104
+ }
105
+
106
+ var rotateEnabled: Bool? {
107
+ didSet { _provider?.rotateEnabled = rotateEnabled }
108
+ }
109
+
110
+ var pitchEnabled: Bool? {
111
+ didSet { _provider?.pitchEnabled = pitchEnabled }
112
+ }
113
+
114
+ var mapType: MapType? {
115
+ didSet { _provider?.mapType = mapType }
116
+ }
117
+
118
+ var showsMyLocationButton: Bool? {
119
+ didSet { _provider?.showsMyLocationButton = showsMyLocationButton }
120
+ }
121
+
122
+ var clusterConfig: ClusterConfig? {
123
+ didSet { _provider?.clusterConfig = clusterConfig }
124
+ }
125
+
126
+ var customMapStyle: [MapStyleElement]? {
127
+ didSet { _provider?.customMapStyle = customMapStyle }
128
+ }
129
+
130
+ var darkMode: Bool? {
131
+ didSet { _provider?.darkMode = darkMode }
132
+ }
133
+
134
+ // MARK: - Callbacks
135
+
136
+ var onPress: ((MapPressEvent) -> Void)? {
137
+ didSet { _provider?.onPress = onPress }
138
+ }
139
+
140
+ var onLongPress: ((MapPressEvent) -> Void)? {
141
+ didSet { _provider?.onLongPress = onLongPress }
142
+ }
143
+
144
+ var onMapReady: (() -> Void)? {
145
+ didSet { _provider?.onMapReady = onMapReady }
146
+ }
147
+
148
+ var onRegionChange: ((RegionChangeEvent) -> Void)? {
149
+ didSet { _provider?.onRegionChange = onRegionChange }
150
+ }
151
+
152
+ var onRegionChangeComplete: ((RegionChangeEvent) -> Void)? {
153
+ didSet { _provider?.onRegionChangeComplete = onRegionChangeComplete }
154
+ }
155
+
156
+ var onMarkerPress: ((_ event: MarkerPressEvent) -> Void)? {
157
+ didSet { _provider?.onMarkerPress = onMarkerPress }
158
+ }
159
+
160
+ var onMarkerDragStart: ((_ event: MarkerDragEvent) -> Void)? {
161
+ didSet { _provider?.onMarkerDragStart = onMarkerDragStart }
162
+ }
163
+
164
+ var onMarkerDrag: ((_ event: MarkerDragEvent) -> Void)? {
165
+ didSet { _provider?.onMarkerDrag = onMarkerDrag }
166
+ }
167
+
168
+ var onMarkerDragEnd: ((_ event: MarkerDragEvent) -> Void)? {
169
+ didSet { _provider?.onMarkerDragEnd = onMarkerDragEnd }
170
+ }
171
+
172
+ var onClusterPress: ((_ event: ClusterPressEvent) -> Void)? {
173
+ didSet { _provider?.onClusterPress = onClusterPress }
174
+ }
175
+
176
+ var onError: ((_ error: MapError) -> Void)? {
177
+ didSet { _provider?.onError = onError }
178
+ }
179
+
180
+ // MARK: - Initialization
181
+
182
+ override init() {
183
+ super.init()
184
+ }
185
+
186
+ // MARK: - Lifecycle
187
+
188
+ func beforeUpdate() {}
189
+
190
+ func afterUpdate() {
191
+ // Ensure provider is initialized on first render
192
+ DispatchQueue.main.async { [weak self] in
193
+ self?.mapProvider.updateSettings()
194
+ }
195
+ }
196
+
197
+ // MARK: - Camera Methods
198
+
199
+ func animateToRegion(region: Region, duration: Double?) throws {
200
+ DispatchQueue.main.async { [weak self] in
201
+ self?.mapProvider.animateToRegion(region, duration: duration)
202
+ }
203
+ }
204
+
205
+ func fitToCoordinates(
206
+ coordinates: [Coordinate],
207
+ edgePadding: EdgePadding?,
208
+ animated: Bool?
209
+ ) throws {
210
+ DispatchQueue.main.async { [weak self] in
211
+ self?.mapProvider.fitToCoordinates(
212
+ coordinates,
213
+ edgePadding: edgePadding,
214
+ animated: animated
215
+ )
216
+ }
217
+ }
218
+
219
+ func animateCamera(camera: Camera, duration: Double?) throws {
220
+ DispatchQueue.main.async { [weak self] in
221
+ self?.mapProvider.animateCamera(camera, duration: duration)
222
+ }
223
+ }
224
+
225
+ func setCamera(camera: Camera) throws {
226
+ DispatchQueue.main.async { [weak self] in
227
+ self?.mapProvider.setCamera(camera)
228
+ }
229
+ }
230
+
231
+ func getCamera() throws -> NitroModules.Promise<Camera> {
232
+ // Called from JS thread — provider access is safe because
233
+ // GMSMapView.camera is a stored property (thread-safe read)
234
+ return .resolved(withResult: mapProvider.getCamera())
235
+ }
236
+
237
+ func getMapBoundaries() throws -> NitroModules.Promise<MapBoundaries> {
238
+ // projection.visibleRegion() must be called on the main thread.
239
+ // Use DispatchQueue.main.sync when called from a background thread,
240
+ // or call directly if already on main.
241
+ let result: MapBoundaries?
242
+ if Thread.isMainThread {
243
+ result = mapProvider.getMapBoundaries()
244
+ } else {
245
+ result = DispatchQueue.main.sync {
246
+ return self.mapProvider.getMapBoundaries()
247
+ }
248
+ }
249
+ guard let boundaries = result else {
250
+ return .rejected(withError: RuntimeError.error(withMessage: "Map boundaries not available"))
251
+ }
252
+ return .resolved(withResult: boundaries)
253
+ }
254
+
255
+ // MARK: - Marker Methods
256
+
257
+ func addMarker(marker: MarkerData) throws {
258
+ DispatchQueue.main.async { [weak self] in
259
+ self?.mapProvider.addMarker(marker)
260
+ }
261
+ }
262
+
263
+ func addMarkers(markers: [MarkerData]) throws {
264
+ DispatchQueue.main.async { [weak self] in
265
+ self?.mapProvider.addMarkers(markers)
266
+ }
267
+ }
268
+
269
+ func updateMarker(marker: MarkerData) throws {
270
+ DispatchQueue.main.async { [weak self] in
271
+ self?.mapProvider.updateMarker(marker)
272
+ }
273
+ }
274
+
275
+ func removeMarker(id: String) throws {
276
+ DispatchQueue.main.async { [weak self] in
277
+ self?.mapProvider.removeMarker(id)
278
+ }
279
+ }
280
+
281
+ func clearMarkers() throws {
282
+ DispatchQueue.main.async { [weak self] in
283
+ self?.mapProvider.clearMarkers()
284
+ }
285
+ }
286
+
287
+ func selectMarker(id: String) {
288
+ DispatchQueue.main.async { [weak self] in
289
+ self?.mapProvider.selectMarker(id)
290
+ }
291
+ }
292
+
293
+ // MARK: - Clustering
294
+
295
+ func setClusteringEnabled(enabled: Bool) throws {
296
+ DispatchQueue.main.async { [weak self] in
297
+ self?.mapProvider.setClusteringEnabled(enabled)
298
+ }
299
+ }
300
+
301
+ func refreshClusters() throws {
302
+ DispatchQueue.main.async { [weak self] in
303
+ self?.mapProvider.refreshClusters()
304
+ }
305
+ }
306
+
307
+ // MARK: - Map Style
308
+
309
+ func setMapStyle(style: [MapStyleElement]?) throws {
310
+ DispatchQueue.main.async { [weak self] in
311
+ self?.mapProvider.setMapStyle(style)
312
+ }
313
+ }
314
+
315
+ func setIsDarkMode(enabled isDark: Bool) {
316
+ DispatchQueue.main.async { [weak self] in
317
+ self?.mapProvider.setDarkMode(isDark)
318
+ }
319
+ }
320
+
321
+ // MARK: - Clustering & Region
322
+
323
+ func performClustering() {
324
+ DispatchQueue.main.async { [weak self] in
325
+ self?.mapProvider.performClustering()
326
+ }
327
+ }
328
+
329
+ func getCurrentRegion() -> Region {
330
+ return mapProvider.getCurrentRegion()
331
+ }
332
+ }
@@ -0,0 +1,33 @@
1
+ import Foundation
2
+ import GoogleMaps
3
+ import NitroModules
4
+
5
+ class HybridNitroMapConfig: HybridNitroMapConfigSpec {
6
+
7
+ // Static flag to track initialization across all instances
8
+ private static var isInitialized = false
9
+
10
+ func NitroMapInitialize(apiKey: String, provider: MapProvider) {
11
+ // Use static flag to prevent duplicate initialization
12
+ guard !HybridNitroMapConfig.isInitialized else {
13
+ #if DEBUG
14
+ print("[NitroMap] Already initialized, skipping...")
15
+ #endif
16
+ return
17
+ }
18
+
19
+ // Set initialized BEFORE async dispatch to prevent race conditions
20
+ HybridNitroMapConfig.isInitialized = true
21
+
22
+ DispatchQueue.main.async {
23
+ GMSServices.provideAPIKey(apiKey)
24
+ #if DEBUG
25
+ print("[NitroMap] Google Maps initialized")
26
+ #endif
27
+ }
28
+ }
29
+
30
+ func IsNitroMapInitialized() -> Bool {
31
+ return HybridNitroMapConfig.isInitialized
32
+ }
33
+ }
@@ -0,0 +1,310 @@
1
+ import Foundation
2
+ import GoogleMaps
3
+ import GoogleMapsUtils
4
+
5
+ /// GMSMapViewDelegate implementation for GoogleMapProvider
6
+ class GoogleMapDelegate: NSObject, GMSMapViewDelegate {
7
+
8
+ weak var provider: GoogleMapProvider?
9
+ private var isGesture: Bool = false
10
+ private var lastGestureWasZoom: Bool = false
11
+ private var zoomAtWillMove: Float = 0
12
+ private var isMapReady: Bool = false
13
+ private var hasPerformedInitialClustering: Bool = false
14
+ private var fallbackClusteringTimer: Timer?
15
+
16
+ init(provider: GoogleMapProvider) {
17
+ self.provider = provider
18
+ super.init()
19
+
20
+ // Fallback timer for real devices where tile rendering callback may be delayed
21
+ // This ensures clustering happens even if mapViewDidFinishTileRendering is slow
22
+ fallbackClusteringTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { [weak self] _ in
23
+ self?.triggerInitialClusteringIfNeeded()
24
+ }
25
+ }
26
+
27
+ deinit {
28
+ fallbackClusteringTimer?.invalidate()
29
+ }
30
+
31
+ /// Triggers initial clustering if it hasn't happened yet and the view is ready
32
+ private func triggerInitialClusteringIfNeeded() {
33
+ guard !hasPerformedInitialClustering else { return }
34
+ guard let provider = provider else { return }
35
+
36
+ // Check if map view has valid dimensions
37
+ let mapView = provider.mapView
38
+ guard mapView.frame.size.width > 0 && mapView.frame.size.height > 0 else {
39
+ // Retry after a short delay if view isn't laid out yet
40
+ fallbackClusteringTimer?.invalidate()
41
+ fallbackClusteringTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false) { [weak self] _ in
42
+ self?.triggerInitialClusteringIfNeeded()
43
+ }
44
+ return
45
+ }
46
+
47
+ hasPerformedInitialClustering = true
48
+ if !isMapReady {
49
+ isMapReady = true
50
+ provider.onMapReady?()
51
+ }
52
+ provider.performClustering()
53
+ }
54
+
55
+ func mapViewDidFinishTileRendering(_ mapView: GMSMapView) {
56
+ fallbackClusteringTimer?.invalidate()
57
+ guard !isMapReady else { return }
58
+ isMapReady = true
59
+ hasPerformedInitialClustering = true
60
+ provider?.onMapReady?()
61
+ provider?.performClustering()
62
+ }
63
+
64
+ /// Called when map snapshot is ready - another reliable trigger point
65
+ func mapViewSnapshotReady(_ mapView: GMSMapView) {
66
+ triggerInitialClusteringIfNeeded()
67
+ }
68
+
69
+ // MARK: - Proximity Cluster Detection
70
+
71
+ /// Check if a coordinate is near any rendered cluster marker.
72
+ private func findNearbyCluster(
73
+ at coordinate: CLLocationCoordinate2D,
74
+ in mapView: GMSMapView
75
+ ) -> GMSMarker? {
76
+ guard let provider = provider else { return nil }
77
+
78
+ let tapPoint = mapView.projection.point(for: coordinate)
79
+ let proximityThreshold: CGFloat = 60.0
80
+
81
+ var closestMarker: GMSMarker?
82
+ var closestDistance: CGFloat = .greatestFiniteMagnitude
83
+
84
+ for clusterMarker in provider.renderedClusterMarkers {
85
+ let markerPoint = mapView.projection.point(for: clusterMarker.position)
86
+ let dx = tapPoint.x - markerPoint.x
87
+ let dy = tapPoint.y - markerPoint.y
88
+ let distance = sqrt(dx * dx + dy * dy)
89
+ if distance < proximityThreshold && distance < closestDistance {
90
+ closestDistance = distance
91
+ closestMarker = clusterMarker
92
+ }
93
+ }
94
+
95
+ return closestMarker
96
+ }
97
+
98
+ private func fireClusterPress(for marker: GMSMarker) {
99
+ guard let clusterData = marker.userData as? ClusterUserData else { return }
100
+ provider?.onClusterPress?(
101
+ ClusterPressEvent(
102
+ coordinate: Coordinate(
103
+ latitude: marker.position.latitude,
104
+ longitude: marker.position.longitude
105
+ ),
106
+ markerIds: clusterData.markerIds,
107
+ count: Double(clusterData.count)
108
+ )
109
+ )
110
+ }
111
+
112
+ // MARK: - Map Tap Handlers
113
+
114
+ func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
115
+ // Proximity-based cluster tap fallback
116
+ if let clusterMarker = findNearbyCluster(at: coordinate, in: mapView) {
117
+ fireClusterPress(for: clusterMarker)
118
+ return
119
+ }
120
+
121
+ let point = mapView.projection.point(for: coordinate)
122
+ let event = MapPressEvent(
123
+ coordinate: Coordinate(
124
+ latitude: coordinate.latitude,
125
+ longitude: coordinate.longitude
126
+ ),
127
+ position: Point(
128
+ x: Double(point.x),
129
+ y: Double(point.y)
130
+ )
131
+ )
132
+ provider?.onPress?(event)
133
+ }
134
+
135
+ /// POI labels (city names, landmarks) intercept taps before markers.
136
+ func mapView(_ mapView: GMSMapView, didTapPOIWithPlaceID placeID: String, name: String, location: CLLocationCoordinate2D) {
137
+ if let clusterMarker = findNearbyCluster(at: location, in: mapView) {
138
+ fireClusterPress(for: clusterMarker)
139
+ return
140
+ }
141
+
142
+ let point = mapView.projection.point(for: location)
143
+ let event = MapPressEvent(
144
+ coordinate: Coordinate(
145
+ latitude: location.latitude,
146
+ longitude: location.longitude
147
+ ),
148
+ position: Point(
149
+ x: Double(point.x),
150
+ y: Double(point.y)
151
+ )
152
+ )
153
+ provider?.onPress?(event)
154
+ }
155
+
156
+ func mapView(_ mapView: GMSMapView, didLongPressAt coordinate: CLLocationCoordinate2D) {
157
+ let point = mapView.projection.point(for: coordinate)
158
+ let event = MapPressEvent(
159
+ coordinate: Coordinate(
160
+ latitude: coordinate.latitude,
161
+ longitude: coordinate.longitude
162
+ ),
163
+ position: Point(
164
+ x: Double(point.x),
165
+ y: Double(point.y)
166
+ )
167
+ )
168
+ provider?.onLongPress?(event)
169
+ }
170
+
171
+ func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
172
+ isGesture = gesture
173
+ zoomAtWillMove = mapView.camera.zoom
174
+ #if DEBUG
175
+ NSLog("[GestureDebug] willMove gesture=%d zoom=%.4f", gesture, mapView.camera.zoom)
176
+ #endif
177
+ }
178
+
179
+ func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
180
+ guard let provider = provider else { return }
181
+
182
+ // Track if zoom changed during this gesture
183
+ if isGesture && abs(position.zoom - zoomAtWillMove) > 0.01 {
184
+ lastGestureWasZoom = true
185
+ }
186
+
187
+ let event = RegionChangeEvent(
188
+ region: provider.getCurrentRegion(),
189
+ isGesture: isGesture
190
+ )
191
+ provider.onRegionChange?(event)
192
+
193
+ // Live clustering during gestures (throttled)
194
+ if provider.clusterConfig?.realtimeClustering == true {
195
+ provider.performClusteringThrottled()
196
+ }
197
+ }
198
+
199
+ func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
200
+ guard let provider = provider else { return }
201
+
202
+ #if DEBUG
203
+ let gestureType = lastGestureWasZoom ? "ZOOM" : "PAN"
204
+ NSLog("[GestureDebug] idleAt zoom=%.4f gestureType=%@ cameraZoom=%.4f",
205
+ position.zoom, gestureType, mapView.camera.zoom)
206
+
207
+ // Schedule a check to compare zoom at idle vs zoom when clustering fires
208
+ let idleZoom = mapView.camera.zoom
209
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.11) {
210
+ let clusterZoom = mapView.camera.zoom
211
+ if abs(idleZoom - clusterZoom) > 0.001 {
212
+ NSLog("[GestureDebug] ⚠️ ZOOM DRIFT: idle=%.4f clustering=%.4f delta=%.4f",
213
+ idleZoom, clusterZoom, clusterZoom - idleZoom)
214
+ } else {
215
+ NSLog("[GestureDebug] ✅ Zoom stable: idle=%.4f clustering=%.4f",
216
+ idleZoom, clusterZoom)
217
+ }
218
+ }
219
+ #endif
220
+
221
+ let event = RegionChangeEvent(
222
+ region: provider.getCurrentRegion(),
223
+ isGesture: isGesture
224
+ )
225
+ provider.onRegionChangeComplete?(event)
226
+ isGesture = false
227
+ lastGestureWasZoom = false
228
+ provider.performClustering()
229
+ }
230
+
231
+ // MARK: - Marker Methods
232
+
233
+ func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
234
+ guard let provider = provider else { return false }
235
+
236
+ // Check if it's a C++ cluster
237
+ if let clusterData = marker.userData as? ClusterUserData {
238
+ provider.onClusterPress?(
239
+ ClusterPressEvent(
240
+ coordinate: Coordinate(
241
+ latitude: marker.position.latitude,
242
+ longitude: marker.position.longitude
243
+ ),
244
+ markerIds: clusterData.markerIds,
245
+ count: Double(clusterData.count)
246
+ )
247
+ )
248
+ return true
249
+ }
250
+ // Regular marker
251
+ if let markerId = marker.userData as? String {
252
+ provider.onMarkerPress?(
253
+ MarkerPressEvent(
254
+ id: markerId,
255
+ coordinate: Coordinate(
256
+ latitude: marker.position.latitude,
257
+ longitude: marker.position.longitude
258
+ )
259
+ )
260
+ )
261
+ return true
262
+ }
263
+
264
+ return false
265
+ }
266
+
267
+ func mapView(_ mapView: GMSMapView, didBeginDragging marker: GMSMarker) {
268
+ guard let provider = provider, let markerId = getMarkerId(from: marker) else { return }
269
+ provider.onMarkerDragStart?(
270
+ MarkerDragEvent(
271
+ id: markerId,
272
+ coordinate: Coordinate(
273
+ latitude: marker.position.latitude,
274
+ longitude: marker.position.longitude
275
+ )
276
+ )
277
+ )
278
+ }
279
+
280
+ func mapView(_ mapView: GMSMapView, didDrag marker: GMSMarker) {
281
+ guard let provider = provider, let markerId = getMarkerId(from: marker) else { return }
282
+ provider.onMarkerDrag?(
283
+ MarkerDragEvent(
284
+ id: markerId,
285
+ coordinate: Coordinate(
286
+ latitude: marker.position.latitude,
287
+ longitude: marker.position.longitude
288
+ )
289
+ )
290
+ )
291
+ }
292
+
293
+ func mapView(_ mapView: GMSMapView, didEndDragging marker: GMSMarker) {
294
+ guard let provider = provider, let markerId = getMarkerId(from: marker) else { return }
295
+ provider.onMarkerDragEnd?(
296
+ MarkerDragEvent(
297
+ id: markerId,
298
+ coordinate: Coordinate(
299
+ latitude: marker.position.latitude,
300
+ longitude: marker.position.longitude
301
+ )
302
+ )
303
+ )
304
+ }
305
+
306
+ private func getMarkerId(from marker: GMSMarker) -> String? {
307
+ // FIX #10: Removed dead NitroClusterItem check — only String IDs are used.
308
+ return marker.userData as? String
309
+ }
310
+ }