@maydon_tech/react-native-nitro-maps 0.1.4 → 0.2.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 (222) hide show
  1. package/LICENSE +1 -1
  2. package/NitroMap.podspec +1 -1
  3. package/README.md +82 -9
  4. package/android/CMakeLists.txt +4 -1
  5. package/android/build.gradle +6 -2
  6. package/android/gradle.properties +4 -4
  7. package/android/src/main/cpp/ClusterEngineJNI.cpp +198 -0
  8. package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMap.kt +397 -0
  9. package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMapConfig.kt +53 -0
  10. package/android/src/main/{java → kotlin}/com/margelo/nitro/nitromap/NitroMapPackage.kt +4 -4
  11. package/android/src/main/kotlin/com/margelo/nitro/nitromap/NitroMapView.kt +73 -0
  12. package/android/src/main/kotlin/com/margelo/nitro/nitromap/UserLocationManager.kt +295 -0
  13. package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/ClusterIconRenderer.kt +111 -0
  14. package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/ClusteringManager.kt +104 -0
  15. package/android/src/main/kotlin/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +166 -0
  16. package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/MarkerIconFactory.kt +303 -0
  17. package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/MarkerSelectionHandler.kt +72 -0
  18. package/android/src/main/kotlin/com/margelo/nitro/nitromap/markers/PriceMarkerRenderer.kt +159 -0
  19. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/MapProviderFactory.kt +24 -0
  20. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +128 -0
  21. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapDelegate.kt +317 -0
  22. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Clustering.kt +524 -0
  23. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Markers.kt +358 -0
  24. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+Overlays.kt +272 -0
  25. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider+UserLocation.kt +296 -0
  26. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/GoogleMapProvider.kt +815 -0
  27. package/android/src/main/kotlin/com/margelo/nitro/nitromap/providers/google/MarkerTagData.kt +19 -0
  28. package/ios/Location/NitroLocationManager.swift +116 -0
  29. package/ios/MarkerRenderer/MarkerIconFactory.swift +1 -3
  30. package/ios/MarkerRenderer/PriceMarkerRenderer.swift +10 -6
  31. package/ios/NitroMap.swift +279 -13
  32. package/ios/NitroMapConfig/NitroMapConfig.swift +45 -0
  33. package/ios/Providers/{GoogleMapDelegate.swift → Google/GoogleMapDelegate.swift} +48 -23
  34. package/ios/Providers/Google/GoogleMapProvider+Camera.swift +180 -0
  35. package/ios/Providers/Google/GoogleMapProvider+Clustering.swift +541 -0
  36. package/ios/Providers/Google/GoogleMapProvider+Markers.swift +270 -0
  37. package/ios/Providers/Google/GoogleMapProvider+Overlays.swift +245 -0
  38. package/ios/Providers/Google/GoogleMapProvider+UserLocation.swift +180 -0
  39. package/ios/Providers/Google/GoogleMapProvider.swift +342 -0
  40. package/ios/Providers/MapProviderFactory.swift +17 -0
  41. package/ios/Providers/MapProviderProtocol.swift +48 -1
  42. package/ios/Shared/ClusterConfig+Factory.swift +2 -2
  43. package/ios/Shared/MapStyleProvider.swift +6 -4
  44. package/ios/Shared/MarkerSelectionHandler.swift +4 -1
  45. package/ios/Utils/ColorValueExtension.swift +46 -67
  46. package/lib/module/components/ImageMarker.js +39 -29
  47. package/lib/module/components/ImageMarker.js.map +1 -1
  48. package/lib/module/components/Marker.js +118 -0
  49. package/lib/module/components/Marker.js.map +1 -0
  50. package/lib/module/components/NitroCircle.js +92 -0
  51. package/lib/module/components/NitroCircle.js.map +1 -0
  52. package/lib/module/components/NitroMap.js +216 -76
  53. package/lib/module/components/NitroMap.js.map +1 -1
  54. package/lib/module/components/NitroPolygon.js +137 -0
  55. package/lib/module/components/NitroPolygon.js.map +1 -0
  56. package/lib/module/components/NitroPolyline.js +115 -0
  57. package/lib/module/components/NitroPolyline.js.map +1 -0
  58. package/lib/module/components/PriceMarker.js +16 -29
  59. package/lib/module/components/PriceMarker.js.map +1 -1
  60. package/lib/module/context/NitroMapContext.js.map +1 -1
  61. package/lib/module/hooks/useNitroCircle.js +18 -0
  62. package/lib/module/hooks/useNitroCircle.js.map +1 -0
  63. package/lib/module/hooks/useNitroMarker.js +26 -9
  64. package/lib/module/hooks/useNitroMarker.js.map +1 -1
  65. package/lib/module/hooks/useNitroOverlay.js +59 -0
  66. package/lib/module/hooks/useNitroOverlay.js.map +1 -0
  67. package/lib/module/hooks/useNitroPolygon.js +18 -0
  68. package/lib/module/hooks/useNitroPolygon.js.map +1 -0
  69. package/lib/module/hooks/useNitroPolyline.js +18 -0
  70. package/lib/module/hooks/useNitroPolyline.js.map +1 -0
  71. package/lib/module/index.js +5 -0
  72. package/lib/module/index.js.map +1 -1
  73. package/lib/module/types/overlay.js +4 -0
  74. package/lib/module/types/overlay.js.map +1 -0
  75. package/lib/module/types/theme.js +4 -0
  76. package/lib/module/types/theme.js.map +1 -0
  77. package/lib/module/utils/colors.js +41 -13
  78. package/lib/module/utils/colors.js.map +1 -1
  79. package/lib/module/utils/validation.js +45 -0
  80. package/lib/module/utils/validation.js.map +1 -0
  81. package/lib/typescript/src/components/ImageMarker.d.ts.map +1 -1
  82. package/lib/typescript/src/components/Marker.d.ts +34 -0
  83. package/lib/typescript/src/components/Marker.d.ts.map +1 -0
  84. package/lib/typescript/src/components/NitroCircle.d.ts +70 -0
  85. package/lib/typescript/src/components/NitroCircle.d.ts.map +1 -0
  86. package/lib/typescript/src/components/NitroMap.d.ts +60 -3
  87. package/lib/typescript/src/components/NitroMap.d.ts.map +1 -1
  88. package/lib/typescript/src/components/NitroPolygon.d.ts +86 -0
  89. package/lib/typescript/src/components/NitroPolygon.d.ts.map +1 -0
  90. package/lib/typescript/src/components/NitroPolyline.d.ts +84 -0
  91. package/lib/typescript/src/components/NitroPolyline.d.ts.map +1 -0
  92. package/lib/typescript/src/components/PriceMarker.d.ts +0 -5
  93. package/lib/typescript/src/components/PriceMarker.d.ts.map +1 -1
  94. package/lib/typescript/src/context/NitroMapContext.d.ts +2 -0
  95. package/lib/typescript/src/context/NitroMapContext.d.ts.map +1 -1
  96. package/lib/typescript/src/hooks/useNitroCircle.d.ts +7 -0
  97. package/lib/typescript/src/hooks/useNitroCircle.d.ts.map +1 -0
  98. package/lib/typescript/src/hooks/useNitroMarker.d.ts +20 -0
  99. package/lib/typescript/src/hooks/useNitroMarker.d.ts.map +1 -1
  100. package/lib/typescript/src/hooks/useNitroOverlay.d.ts +26 -0
  101. package/lib/typescript/src/hooks/useNitroOverlay.d.ts.map +1 -0
  102. package/lib/typescript/src/hooks/useNitroPolygon.d.ts +7 -0
  103. package/lib/typescript/src/hooks/useNitroPolygon.d.ts.map +1 -0
  104. package/lib/typescript/src/hooks/useNitroPolyline.d.ts +7 -0
  105. package/lib/typescript/src/hooks/useNitroPolyline.d.ts.map +1 -0
  106. package/lib/typescript/src/index.d.ts +15 -2
  107. package/lib/typescript/src/index.d.ts.map +1 -1
  108. package/lib/typescript/src/specs/NitroMap.nitro.d.ts +248 -6
  109. package/lib/typescript/src/specs/NitroMap.nitro.d.ts.map +1 -1
  110. package/lib/typescript/src/types/map.d.ts +34 -4
  111. package/lib/typescript/src/types/map.d.ts.map +1 -1
  112. package/lib/typescript/src/types/marker.d.ts +24 -36
  113. package/lib/typescript/src/types/marker.d.ts.map +1 -1
  114. package/lib/typescript/src/types/overlay.d.ts +84 -0
  115. package/lib/typescript/src/types/overlay.d.ts.map +1 -0
  116. package/lib/typescript/src/types/theme.d.ts +93 -0
  117. package/lib/typescript/src/types/theme.d.ts.map +1 -0
  118. package/lib/typescript/src/utils/colors.d.ts +6 -8
  119. package/lib/typescript/src/utils/colors.d.ts.map +1 -1
  120. package/lib/typescript/src/utils/validation.d.ts +12 -0
  121. package/lib/typescript/src/utils/validation.d.ts.map +1 -0
  122. package/nitrogen/generated/android/c++/JCircleData.hpp +94 -0
  123. package/nitrogen/generated/android/c++/JClusterConfig.hpp +5 -7
  124. package/nitrogen/generated/android/c++/JCoordinateRing.hpp +77 -0
  125. package/nitrogen/generated/android/c++/JFunc_void_UserLocationChangeEvent.hpp +79 -0
  126. package/nitrogen/generated/android/c++/JFunc_void_UserTrackingMode.hpp +77 -0
  127. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
  128. package/nitrogen/generated/android/c++/JHybridNitroMapSpec.cpp +332 -21
  129. package/nitrogen/generated/android/c++/JHybridNitroMapSpec.hpp +53 -2
  130. package/nitrogen/generated/android/c++/JMarkerAnimation.hpp +3 -6
  131. package/nitrogen/generated/android/c++/JMarkerData.hpp +15 -3
  132. package/nitrogen/generated/android/c++/JPolygonData.hpp +133 -0
  133. package/nitrogen/generated/android/c++/JPolylineData.hpp +113 -0
  134. package/nitrogen/generated/android/c++/JUserLocationChangeEvent.hpp +70 -0
  135. package/nitrogen/generated/android/c++/JUserTrackingMode.hpp +62 -0
  136. package/nitrogen/generated/android/c++/views/JHybridNitroMapStateUpdater.cpp +72 -4
  137. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/CircleData.kt +62 -0
  138. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/ClusterConfig.kt +4 -4
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/CoordinateRing.kt +38 -0
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_UserLocationChangeEvent.kt +80 -0
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_UserTrackingMode.kt +80 -0
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/Func_void_std__string.kt +80 -0
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/HybridNitroMapSpec.kt +228 -2
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerAnimation.kt +1 -2
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/MarkerData.kt +12 -3
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PolygonData.kt +62 -0
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/PolylineData.kt +62 -0
  148. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/UserLocationChangeEvent.kt +47 -0
  149. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitromap/{ClusterAnimationStyle.kt → UserTrackingMode.kt} +6 -8
  150. package/nitrogen/generated/android/nitromapOnLoad.cpp +6 -0
  151. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.cpp +24 -0
  152. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Bridge.hpp +178 -17
  153. package/nitrogen/generated/ios/NitroMap-Swift-Cxx-Umbrella.hpp +18 -3
  154. package/nitrogen/generated/ios/c++/HybridNitroMapSpecSwift.hpp +252 -16
  155. package/nitrogen/generated/ios/c++/views/HybridNitroMapComponent.mm +90 -5
  156. package/nitrogen/generated/ios/swift/CircleData.swift +143 -0
  157. package/nitrogen/generated/ios/swift/ClusterConfig.swift +22 -15
  158. package/nitrogen/generated/ios/swift/CoordinateRing.swift +48 -0
  159. package/nitrogen/generated/ios/swift/Func_void_UserLocationChangeEvent.swift +47 -0
  160. package/nitrogen/generated/ios/swift/Func_void_UserTrackingMode.swift +47 -0
  161. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +47 -0
  162. package/nitrogen/generated/ios/swift/HybridNitroMapSpec.swift +35 -1
  163. package/nitrogen/generated/ios/swift/HybridNitroMapSpec_cxx.swift +582 -8
  164. package/nitrogen/generated/ios/swift/MarkerAnimation.swift +4 -8
  165. package/nitrogen/generated/ios/swift/MarkerData.swift +54 -2
  166. package/nitrogen/generated/ios/swift/PolygonData.swift +167 -0
  167. package/nitrogen/generated/ios/swift/PolylineData.swift +155 -0
  168. package/nitrogen/generated/ios/swift/UserLocationChangeEvent.swift +69 -0
  169. package/nitrogen/generated/ios/swift/UserTrackingMode.swift +44 -0
  170. package/nitrogen/generated/shared/c++/CircleData.hpp +113 -0
  171. package/nitrogen/generated/shared/c++/ClusterConfig.hpp +5 -8
  172. package/nitrogen/generated/shared/c++/CoordinateRing.hpp +77 -0
  173. package/nitrogen/generated/shared/c++/HybridNitroMapSpec.cpp +53 -2
  174. package/nitrogen/generated/shared/c++/HybridNitroMapSpec.hpp +75 -6
  175. package/nitrogen/generated/shared/c++/MarkerAnimation.hpp +4 -8
  176. package/nitrogen/generated/shared/c++/MarkerData.hpp +14 -2
  177. package/nitrogen/generated/shared/c++/PolygonData.hpp +117 -0
  178. package/nitrogen/generated/shared/c++/PolylineData.hpp +114 -0
  179. package/nitrogen/generated/shared/c++/UserLocationChangeEvent.hpp +88 -0
  180. package/nitrogen/generated/shared/c++/UserTrackingMode.hpp +80 -0
  181. package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.cpp +216 -12
  182. package/nitrogen/generated/shared/c++/views/HybridNitroMapComponent.hpp +23 -1
  183. package/nitrogen/generated/shared/json/NitroMapConfig.json +18 -1
  184. package/package.json +36 -5
  185. package/src/components/ImageMarker.tsx +58 -42
  186. package/src/components/Marker.tsx +161 -0
  187. package/src/components/NitroCircle.tsx +183 -0
  188. package/src/components/NitroMap.tsx +328 -78
  189. package/src/components/NitroPolygon.tsx +229 -0
  190. package/src/components/NitroPolyline.tsx +208 -0
  191. package/src/components/PriceMarker.tsx +23 -48
  192. package/src/context/NitroMapContext.tsx +4 -0
  193. package/src/hooks/useNitroCircle.ts +25 -0
  194. package/src/hooks/useNitroMarker.ts +49 -10
  195. package/src/hooks/useNitroOverlay.ts +68 -0
  196. package/src/hooks/useNitroPolygon.ts +25 -0
  197. package/src/hooks/useNitroPolyline.ts +25 -0
  198. package/src/index.tsx +28 -2
  199. package/src/specs/NitroMap.nitro.ts +294 -5
  200. package/src/types/map.ts +36 -4
  201. package/src/types/marker.ts +24 -44
  202. package/src/types/overlay.ts +87 -0
  203. package/src/types/theme.ts +101 -0
  204. package/src/utils/colors.ts +48 -16
  205. package/src/utils/validation.ts +69 -0
  206. package/android/src/main/java/com/margelo/nitro/nitromap/ClusterIconGenerator.kt +0 -108
  207. package/android/src/main/java/com/margelo/nitro/nitromap/ColorUtils.kt +0 -63
  208. package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMap.kt +0 -408
  209. package/android/src/main/java/com/margelo/nitro/nitromap/HybridNitroMapConfig.kt +0 -68
  210. package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconCache.kt +0 -176
  211. package/android/src/main/java/com/margelo/nitro/nitromap/MarkerIconFactory.kt +0 -252
  212. package/android/src/main/java/com/margelo/nitro/nitromap/clustering/NitroClusterEngine.kt +0 -252
  213. package/android/src/main/java/com/margelo/nitro/nitromap/clustering/QuadTree.kt +0 -195
  214. package/android/src/main/java/com/margelo/nitro/nitromap/providers/GoogleMapProvider.kt +0 -912
  215. package/android/src/main/java/com/margelo/nitro/nitromap/providers/MapProviderInterface.kt +0 -70
  216. package/cpp/QuadTree.hpp +0 -246
  217. package/ios/NitroMapConfig/HybridNitroMapConfig.swift +0 -33
  218. package/ios/Providers/GoogleMapProvider+Camera.swift +0 -164
  219. package/ios/Providers/GoogleMapProvider.swift +0 -924
  220. package/nitrogen/generated/android/c++/JClusterAnimationStyle.hpp +0 -68
  221. package/nitrogen/generated/ios/swift/ClusterAnimationStyle.swift +0 -52
  222. package/nitrogen/generated/shared/c++/ClusterAnimationStyle.hpp +0 -88
@@ -0,0 +1,101 @@
1
+ import type { MapStyle } from './map';
2
+
3
+ // ============ Provider-Specific Theme Types ============
4
+
5
+ /**
6
+ * Google Maps theme — JSON-based styling.
7
+ * Array of style elements targeting map features with visual modifiers.
8
+ *
9
+ * @see https://mapstyle.withgoogle.com/
10
+ * @see https://developers.google.com/maps/documentation/javascript/style-reference
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const darkTheme: GoogleMapTheme = [
15
+ * { featureType: 'water', stylers: [{ color: '#0e171d' }] },
16
+ * { featureType: 'road', stylers: [{ visibility: 'simplified' }] },
17
+ * ];
18
+ * ```
19
+ */
20
+ export type GoogleMapTheme = MapStyle;
21
+
22
+ /**
23
+ * Apple Maps theme — configuration-based styling.
24
+ *
25
+ * Maps to `MKMapConfiguration` on iOS. Unlike Google's element-level JSON
26
+ * styling, Apple Maps uses high-level configuration categories.
27
+ *
28
+ * **Not yet implemented** — will be available when the Apple Maps provider
29
+ * is added (Phase 3).
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const appleTheme: AppleMapTheme = {
34
+ * colorScheme: 'dark',
35
+ * emphasisStyle: 'muted',
36
+ * showsTraffic: true,
37
+ * pointOfInterestFilter: {
38
+ * includes: ['restaurant', 'cafe', 'hotel'],
39
+ * },
40
+ * };
41
+ * ```
42
+ */
43
+ export type AppleMapTheme = {
44
+ /** Color scheme for the map. @default 'light' */
45
+ colorScheme?: 'light' | 'dark';
46
+ /** Emphasis style — 'muted' reduces visual clutter. @default 'default' */
47
+ emphasisStyle?: 'default' | 'muted';
48
+ /** Show real-time traffic overlay. @default false */
49
+ showsTraffic?: boolean;
50
+ /** Filter which points of interest are visible. */
51
+ pointOfInterestFilter?: {
52
+ /** Only show these POI categories. Mutually exclusive with `excludes`. */
53
+ includes?: string[];
54
+ /** Hide these POI categories. Mutually exclusive with `includes`. */
55
+ excludes?: string[];
56
+ };
57
+ };
58
+
59
+ /**
60
+ * Yandex Maps theme — style URI or night mode toggle.
61
+ *
62
+ * **Not yet implemented** — will be available when the Yandex Maps provider
63
+ * is added (Phase 4).
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const yandexTheme: YandexMapTheme = {
68
+ * nightModeEnabled: true,
69
+ * };
70
+ * ```
71
+ */
72
+ export type YandexMapTheme = {
73
+ /** Custom style URI (e.g., from Yandex Style Editor). */
74
+ styleUri?: string;
75
+ /** Enable built-in night/dark mode. @default false */
76
+ nightModeEnabled?: boolean;
77
+ };
78
+
79
+ // ============ Provider → Theme Mapping ============
80
+
81
+ /**
82
+ * Maps each provider to its theme type.
83
+ * Used by the generic `NitroMapProps<P>` to enforce type-safe themes.
84
+ *
85
+ * When you write `<NitroMap provider="google" theme={...} />`,
86
+ * TypeScript narrows `theme` to `GoogleMapTheme`.
87
+ *
88
+ * When you write `<NitroMap provider="apple" theme={...} />`,
89
+ * TypeScript narrows `theme` to `AppleMapTheme`.
90
+ */
91
+ export type ThemeForProvider = {
92
+ google: GoogleMapTheme;
93
+ apple: AppleMapTheme;
94
+ yandex: YandexMapTheme;
95
+ };
96
+
97
+ /**
98
+ * Union of all possible theme types.
99
+ * Use `ThemeForProvider[P]` for type-safe narrowing instead.
100
+ */
101
+ export type MapTheme = GoogleMapTheme | AppleMapTheme | YandexMapTheme;
@@ -53,21 +53,6 @@ export const parseColor = (
53
53
  return undefined;
54
54
  };
55
55
 
56
- /**
57
- * Parse a ColorValue with a fallback default color
58
- * @param color - Color value (hex string or MarkerColor)
59
- * @param fallback - Fallback MarkerColor if parsing fails
60
- * @returns MarkerColor object
61
- * @internal
62
- */
63
- export const parseColorWithFallback = (
64
- color: ColorValue | undefined,
65
- fallback: MarkerColor
66
- ): MarkerColor => {
67
- const parsed = parseColor(color);
68
- return parsed ?? fallback;
69
- };
70
-
71
56
  /**
72
57
  * Create a MarkerColor from RGB values
73
58
  * @param r - Red component (0-255)
@@ -106,7 +91,20 @@ export const rgb = (
106
91
  * ```
107
92
  */
108
93
  export const hex = (hexStr: string, alpha: number = 255): MarkerColor => {
109
- // Try 6-char hex first (#RRGGBB or RRGGBB)
94
+ // Try 8-char hex first (#RRGGBBAA or RRGGBBAA)
95
+ const result8 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(
96
+ hexStr
97
+ );
98
+ if (result8) {
99
+ return {
100
+ r: parseInt(result8[1]!, 16),
101
+ g: parseInt(result8[2]!, 16),
102
+ b: parseInt(result8[3]!, 16),
103
+ a: parseInt(result8[4]!, 16),
104
+ };
105
+ }
106
+
107
+ // Try 6-char hex (#RRGGBB or RRGGBB)
110
108
  const result6 = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexStr);
111
109
  if (result6) {
112
110
  return {
@@ -117,6 +115,17 @@ export const hex = (hexStr: string, alpha: number = 255): MarkerColor => {
117
115
  };
118
116
  }
119
117
 
118
+ // Try 4-char hex (#RGBA or RGBA)
119
+ const result4 = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])$/i.exec(hexStr);
120
+ if (result4) {
121
+ return {
122
+ r: parseInt(result4[1]! + result4[1]!, 16),
123
+ g: parseInt(result4[2]! + result4[2]!, 16),
124
+ b: parseInt(result4[3]! + result4[3]!, 16),
125
+ a: parseInt(result4[4]! + result4[4]!, 16),
126
+ };
127
+ }
128
+
120
129
  // Try 3-char hex (#RGB or RGB)
121
130
  const result3 = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec(hexStr);
122
131
  if (result3) {
@@ -129,6 +138,11 @@ export const hex = (hexStr: string, alpha: number = 255): MarkerColor => {
129
138
  }
130
139
 
131
140
  // Fallback to black
141
+ if (__DEV__) {
142
+ console.warn(
143
+ `hex(): invalid hex color string "${hexStr}". Falling back to black.`
144
+ );
145
+ }
132
146
  return { r: 0, g: 0, b: 0, a: alpha };
133
147
  };
134
148
 
@@ -157,3 +171,21 @@ export const Colors = {
157
171
  /** Light gray (240, 240, 240) */
158
172
  lightGray: rgb(240, 240, 240),
159
173
  };
174
+
175
+ /**
176
+ * Compare two ColorValue values for equality.
177
+ * Handles both hex strings and MarkerColor objects.
178
+ * @internal Used by component memo comparators to avoid duplication.
179
+ */
180
+ export const areColorsEqual = (
181
+ a: ColorValue | undefined,
182
+ b: ColorValue | undefined
183
+ ): boolean => {
184
+ if (a === b) return true;
185
+ if (!a || !b) return false;
186
+ if (typeof a !== typeof b) return false;
187
+ if (typeof a === 'string' && typeof b === 'string') return a === b;
188
+ const ca = a as MarkerColor;
189
+ const cb = b as MarkerColor;
190
+ return ca.r === cb.r && ca.g === cb.g && ca.b === cb.b && ca.a === cb.a;
191
+ };
@@ -0,0 +1,69 @@
1
+ // src/utils/validation.ts
2
+
3
+ import type { Coordinate } from '../types/map';
4
+
5
+ /**
6
+ * Validate a coordinate in __DEV__ mode.
7
+ * Warns on NaN, Infinity, or out-of-range values.
8
+ */
9
+ export function validateCoordinate(
10
+ coordinate: Coordinate,
11
+ context: string
12
+ ): void {
13
+ if (!__DEV__) return;
14
+
15
+ const { latitude, longitude } = coordinate;
16
+
17
+ if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) {
18
+ console.warn(
19
+ `[NitroMap] Invalid coordinate in ${context}: ` +
20
+ `latitude=${latitude}, longitude=${longitude}. ` +
21
+ 'Coordinates must be finite numbers.'
22
+ );
23
+ return;
24
+ }
25
+
26
+ if (latitude < -90 || latitude > 90) {
27
+ console.warn(
28
+ `[NitroMap] Out-of-range latitude in ${context}: ${latitude}. ` +
29
+ 'Latitude must be between -90 and 90.'
30
+ );
31
+ }
32
+
33
+ if (longitude < -180 || longitude > 180) {
34
+ console.warn(
35
+ `[NitroMap] Out-of-range longitude in ${context}: ${longitude}. ` +
36
+ 'Longitude must be between -180 and 180.'
37
+ );
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Validate an array of coordinates in __DEV__ mode.
43
+ * Only reports the first invalid coordinate to avoid console spam.
44
+ */
45
+ export function validateCoordinates(
46
+ coordinates: Coordinate[],
47
+ context: string
48
+ ): void {
49
+ if (!__DEV__) return;
50
+
51
+ for (let i = 0; i < coordinates.length; i++) {
52
+ const coord = coordinates[i]!;
53
+ const { latitude, longitude } = coord;
54
+ if (
55
+ !Number.isFinite(latitude) ||
56
+ !Number.isFinite(longitude) ||
57
+ latitude < -90 ||
58
+ latitude > 90 ||
59
+ longitude < -180 ||
60
+ longitude > 180
61
+ ) {
62
+ console.warn(
63
+ `[NitroMap] Invalid coordinate at index ${i} in ${context}: ` +
64
+ `latitude=${latitude}, longitude=${longitude}.`
65
+ );
66
+ return; // report first invalid only
67
+ }
68
+ }
69
+ }
@@ -1,108 +0,0 @@
1
- package com.margelo.nitro.nitromap
2
-
3
- import android.content.Context
4
- import android.graphics.*
5
- import com.google.android.gms.maps.model.BitmapDescriptor
6
- import com.google.android.gms.maps.model.BitmapDescriptorFactory
7
- import kotlin.math.roundToInt
8
- import androidx.core.graphics.toColorInt
9
-
10
- /**
11
- * Generator for cluster marker icons
12
- */
13
- class ClusterIconGenerator(private val context: Context) {
14
-
15
- private var backgroundColor = "#007AFF".toColorInt() // iOS blue
16
- private var textColor = Color.WHITE
17
- private var borderColor = Color.WHITE
18
- private var borderWidth = 2f
19
-
20
- private val iconCache = mutableMapOf<Int, BitmapDescriptor>()
21
-
22
- fun updateConfig(config: ClusterConfig?) {
23
- config?.let {
24
- backgroundColor = ColorUtils.fromColorValue(it.backgroundColor)
25
- textColor = ColorUtils.fromColorValue(it.textColor)
26
- borderColor = ColorUtils.fromColorValue(it.borderColor)
27
- borderWidth = it.borderWidth.toFloat()
28
- // Clear cache when config changes
29
- iconCache.clear()
30
- }
31
- }
32
-
33
- fun getClusterIcon(count: Int): BitmapDescriptor {
34
- // Check cache first
35
- iconCache[count]?.let { return it }
36
-
37
- val density = context.resources.displayMetrics.density
38
-
39
- // Size based on count
40
- val baseSize = when {
41
- count < 10 -> 40
42
- count < 100 -> 48
43
- count < 1000 -> 56
44
- else -> 64
45
- }
46
- val size = (baseSize * density).roundToInt()
47
-
48
- val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
49
- val canvas = Canvas(bitmap)
50
-
51
- // Draw background circle
52
- val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
53
- color = backgroundColor
54
- style = Paint.Style.FILL
55
- }
56
- canvas.drawCircle(size / 2f, size / 2f, size / 2f - borderWidth * density, bgPaint)
57
-
58
- // Draw border
59
- if (borderWidth > 0) {
60
- val borderPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
61
- color = borderColor
62
- style = Paint.Style.STROKE
63
- strokeWidth = borderWidth * density
64
- }
65
- canvas.drawCircle(
66
- size / 2f,
67
- size / 2f,
68
- size / 2f - borderWidth * density / 2,
69
- borderPaint
70
- )
71
- }
72
-
73
- // Draw count text
74
- val text = formatCount(count)
75
- val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
76
- color = textColor
77
- textSize = when {
78
- count < 10 -> 16 * density
79
- count < 100 -> 14 * density
80
- count < 1000 -> 12 * density
81
- else -> 10 * density
82
- }
83
- typeface = Typeface.DEFAULT_BOLD
84
- textAlign = Paint.Align.CENTER
85
- }
86
-
87
- val textBounds = Rect()
88
- textPaint.getTextBounds(text, 0, text.length, textBounds)
89
- val textY = size / 2f + textBounds.height() / 2f
90
- canvas.drawText(text, size / 2f, textY, textPaint)
91
-
92
- val descriptor = BitmapDescriptorFactory.fromBitmap(bitmap)
93
- iconCache[count] = descriptor
94
- return descriptor
95
- }
96
-
97
- private fun formatCount(count: Int): String {
98
- return when {
99
- count >= 1000000 -> "${count / 1000000}M"
100
- count >= 1000 -> "${count / 1000}K"
101
- else -> count.toString()
102
- }
103
- }
104
-
105
- fun clearCache() {
106
- iconCache.clear()
107
- }
108
- }
@@ -1,63 +0,0 @@
1
- package com.margelo.nitro.nitromap
2
-
3
- import android.graphics.Color
4
- import androidx.core.graphics.toColorInt
5
-
6
- /**
7
- * Utility functions for converting color types to Android color integers
8
- */
9
- object ColorUtils {
10
-
11
- /**
12
- * Convert MarkerColor (RGBA) to Android color int
13
- */
14
- fun fromMarkerColor(color: MarkerColor): Int {
15
- // Handle alpha: if <= 1.0, treat as 0-1 range and scale to 0-255
16
- val alpha = if (color.a <= 1.0) (color.a * 255).toInt() else color.a.toInt()
17
- return Color.argb(
18
- alpha.coerceIn(0, 255),
19
- color.r.toInt().coerceIn(0, 255),
20
- color.g.toInt().coerceIn(0, 255),
21
- color.b.toInt().coerceIn(0, 255)
22
- )
23
- }
24
-
25
- /**
26
- * Convert ColorValue (String | MarkerColor variant) to Android color int
27
- */
28
- fun fromColorValue(colorValue: ColorValue): Int {
29
- return colorValue.match(
30
- first = { hexString -> parseHexColor(hexString) },
31
- second = { markerColor -> fromMarkerColor(markerColor) }
32
- )
33
- }
34
-
35
- /**
36
- * Convert Variant_String_MarkerColor to Android color int
37
- */
38
- fun fromVariant(variant: Variant_String_MarkerColor): Int {
39
- return variant.match(
40
- first = { hexString -> parseHexColor(hexString) },
41
- second = { markerColor -> fromMarkerColor(markerColor) }
42
- )
43
- }
44
-
45
- /**
46
- * Parse hex color string to Android color int
47
- * Supports formats: #RGB, #RRGGBB, #AARRGGBB, and color names
48
- */
49
- private fun parseHexColor(hexString: String): Int {
50
- return try {
51
- hexString.toColorInt()
52
- } catch (e: Exception) {
53
- Color.BLACK // Default fallback
54
- }
55
- }
56
-
57
- /**
58
- * Create a default ColorValue from a MarkerColor
59
- */
60
- fun defaultColorValue(r: Double, g: Double, b: Double, a: Double = 255.0): ColorValue {
61
- return ColorValue.create(MarkerColor(r, g, b, a))
62
- }
63
- }