@lugg/maps 0.2.0-alpha.0 → 0.2.0-alpha.10

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 (152) hide show
  1. package/README.md +17 -4
  2. package/android/src/main/java/com/luggmaps/{LuggMapsGoogleMapView.kt → LuggGoogleMapView.kt} +111 -36
  3. package/android/src/main/java/com/luggmaps/{LuggMapsGoogleMapViewManager.kt → LuggGoogleMapViewManager.kt} +66 -39
  4. package/android/src/main/java/com/luggmaps/{LuggMapsWrapperView.kt → LuggMapWrapperView.kt} +1 -1
  5. package/android/src/main/java/com/luggmaps/LuggMapWrapperViewManager.kt +25 -0
  6. package/android/src/main/java/com/luggmaps/{LuggMapsMarkerView.kt → LuggMarkerView.kt} +13 -7
  7. package/android/src/main/java/com/luggmaps/{LuggMapsMarkerViewManager.kt → LuggMarkerViewManager.kt} +23 -17
  8. package/android/src/main/java/com/luggmaps/{LuggMapsPackage.kt → LuggPackage.kt} +2 -2
  9. package/android/src/main/java/com/luggmaps/{LuggMapsPolylineView.kt → LuggPolylineView.kt} +11 -4
  10. package/android/src/main/java/com/luggmaps/{LuggMapsPolylineViewManager.kt → LuggPolylineViewManager.kt} +22 -16
  11. package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +89 -43
  12. package/android/src/main/java/com/luggmaps/events/CameraIdleEvent.kt +10 -2
  13. package/android/src/main/java/com/luggmaps/events/CameraMoveEvent.kt +6 -5
  14. package/android/src/main/java/com/luggmaps/events/ReadyEvent.kt +12 -0
  15. package/android/src/main/java/com/luggmaps/extensions/ViewExtensions.kt +14 -0
  16. package/ios/{LuggMapsAppleMapView.h → LuggAppleMapView.h} +2 -2
  17. package/ios/{LuggMapsAppleMapView.mm → LuggAppleMapView.mm} +140 -71
  18. package/ios/{LuggMapsGoogleMapView.h → LuggGoogleMapView.h} +1 -1
  19. package/ios/{LuggMapsGoogleMapView.mm → LuggGoogleMapView.mm} +82 -64
  20. package/ios/{LuggMapsWrapperView.h → LuggMapWrapperView.h} +1 -1
  21. package/ios/{LuggMapsWrapperView.mm → LuggMapWrapperView.mm} +7 -7
  22. package/ios/{LuggMapsMarkerView.h → LuggMarkerView.h} +8 -6
  23. package/ios/{LuggMapsMarkerView.mm → LuggMarkerView.mm} +21 -8
  24. package/ios/{LuggMapsPolylineView.h → LuggPolylineView.h} +6 -5
  25. package/ios/{LuggMapsPolylineView.mm → LuggPolylineView.mm} +14 -9
  26. package/ios/core/GMSPolylineAnimator.m +85 -36
  27. package/ios/core/MKPolylineAnimator.m +63 -32
  28. package/ios/events/CameraIdleEvent.h +6 -1
  29. package/ios/events/CameraMoveEvent.h +6 -3
  30. package/ios/events/ReadyEvent.h +20 -0
  31. package/lib/module/MapProvider.js +13 -0
  32. package/lib/module/MapProvider.js.map +1 -0
  33. package/lib/module/MapProvider.types.js +4 -0
  34. package/lib/module/MapProvider.types.js.map +1 -0
  35. package/lib/module/MapProvider.web.js +14 -0
  36. package/lib/module/MapProvider.web.js.map +1 -0
  37. package/lib/module/MapView.js +21 -7
  38. package/lib/module/MapView.js.map +1 -1
  39. package/lib/module/MapView.web.js +266 -0
  40. package/lib/module/MapView.web.js.map +1 -0
  41. package/lib/module/{Marker.js → components/Marker.js} +6 -3
  42. package/lib/module/components/Marker.js.map +1 -0
  43. package/lib/module/components/Marker.web.js +34 -0
  44. package/lib/module/components/Marker.web.js.map +1 -0
  45. package/lib/module/{Polyline.js → components/Polyline.js} +7 -4
  46. package/lib/module/components/Polyline.js.map +1 -0
  47. package/lib/module/components/Polyline.web.js +177 -0
  48. package/lib/module/components/Polyline.web.js.map +1 -0
  49. package/lib/module/components/index.js +5 -0
  50. package/lib/module/components/index.js.map +1 -0
  51. package/lib/module/components/index.web.js +5 -0
  52. package/lib/module/components/index.web.js.map +1 -0
  53. package/{src/fabric/LuggMapsAppleMapViewNativeComponent.ts → lib/module/fabric/LuggAppleMapViewNativeComponent.ts} +13 -3
  54. package/lib/module/fabric/{LuggMapsGoogleMapViewNativeComponent.ts → LuggGoogleMapViewNativeComponent.ts} +13 -3
  55. package/{src/fabric/LuggMapsWrapperViewNativeComponent.ts → lib/module/fabric/LuggMapWrapperViewNativeComponent.ts} +1 -1
  56. package/lib/module/fabric/{LuggMapsMarkerViewNativeComponent.ts → LuggMarkerViewNativeComponent.ts} +1 -1
  57. package/{src/fabric/LuggMapsPolylineViewNativeComponent.ts → lib/module/fabric/LuggPolylineViewNativeComponent.ts} +1 -1
  58. package/lib/module/index.js +3 -3
  59. package/lib/module/index.js.map +1 -1
  60. package/lib/module/index.web.js +6 -0
  61. package/lib/module/index.web.js.map +1 -0
  62. package/lib/typescript/plugin/src/withLuggMapsAndroid.d.ts +6 -0
  63. package/lib/typescript/plugin/src/withLuggMapsAndroid.d.ts.map +1 -0
  64. package/lib/typescript/plugin/src/withLuggMapsIOS.d.ts +6 -0
  65. package/lib/typescript/plugin/src/withLuggMapsIOS.d.ts.map +1 -0
  66. package/lib/typescript/src/MapProvider.d.ts +8 -0
  67. package/lib/typescript/src/MapProvider.d.ts.map +1 -0
  68. package/lib/typescript/src/MapProvider.types.d.ts +16 -0
  69. package/lib/typescript/src/MapProvider.types.d.ts.map +1 -0
  70. package/lib/typescript/src/MapProvider.web.d.ts +3 -0
  71. package/lib/typescript/src/MapProvider.web.d.ts.map +1 -0
  72. package/lib/typescript/src/MapView.d.ts.map +1 -1
  73. package/lib/typescript/src/MapView.types.d.ts +24 -14
  74. package/lib/typescript/src/MapView.types.d.ts.map +1 -1
  75. package/lib/typescript/src/MapView.web.d.ts +12 -0
  76. package/lib/typescript/src/MapView.web.d.ts.map +1 -0
  77. package/lib/typescript/src/{Marker.types.d.ts → components/Marker.d.ts} +10 -5
  78. package/lib/typescript/src/components/Marker.d.ts.map +1 -0
  79. package/lib/typescript/src/{Marker.d.ts → components/Marker.web.d.ts} +2 -2
  80. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -0
  81. package/lib/typescript/src/{Polyline.types.d.ts → components/Polyline.d.ts} +10 -5
  82. package/lib/typescript/src/components/Polyline.d.ts.map +1 -0
  83. package/lib/typescript/src/components/Polyline.web.d.ts +6 -0
  84. package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -0
  85. package/lib/typescript/src/components/index.d.ts +3 -0
  86. package/lib/typescript/src/components/index.d.ts.map +1 -0
  87. package/lib/typescript/src/components/index.web.d.ts +5 -0
  88. package/lib/typescript/src/components/index.web.d.ts.map +1 -0
  89. package/lib/typescript/src/fabric/{LuggMapsAppleMapViewNativeComponent.d.ts → LuggAppleMapViewNativeComponent.d.ts} +10 -3
  90. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts.map +1 -0
  91. package/lib/typescript/src/fabric/{LuggMapsGoogleMapViewNativeComponent.d.ts → LuggGoogleMapViewNativeComponent.d.ts} +10 -3
  92. package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts.map +1 -0
  93. package/lib/typescript/src/fabric/{LuggMapsWrapperViewNativeComponent.d.ts → LuggMapWrapperViewNativeComponent.d.ts} +1 -1
  94. package/lib/typescript/src/fabric/LuggMapWrapperViewNativeComponent.d.ts.map +1 -0
  95. package/lib/typescript/src/fabric/{LuggMapsMarkerViewNativeComponent.d.ts → LuggMarkerViewNativeComponent.d.ts} +1 -1
  96. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -0
  97. package/lib/typescript/src/fabric/{LuggMapsPolylineViewNativeComponent.d.ts → LuggPolylineViewNativeComponent.d.ts} +1 -1
  98. package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts.map +1 -0
  99. package/lib/typescript/src/index.d.ts +5 -6
  100. package/lib/typescript/src/index.d.ts.map +1 -1
  101. package/lib/typescript/src/index.web.d.ts +7 -0
  102. package/lib/typescript/src/index.web.d.ts.map +1 -0
  103. package/package.json +20 -7
  104. package/plugin/build/index.js +4 -4
  105. package/{lib/typescript/plugin/src/withMapsAndroid.d.ts → plugin/build/withLuggMapsAndroid.d.ts} +0 -1
  106. package/plugin/build/withLuggMapsAndroid.js +15 -0
  107. package/{lib/typescript/plugin/src/withMapsIOS.d.ts → plugin/build/withLuggMapsIOS.d.ts} +0 -1
  108. package/plugin/build/withLuggMapsIOS.js +27 -0
  109. package/plugin/build/withMapsAndroid.d.ts +1 -1
  110. package/plugin/build/withMapsIOS.d.ts +1 -1
  111. package/src/MapProvider.tsx +10 -0
  112. package/src/MapProvider.types.ts +16 -0
  113. package/src/MapProvider.web.tsx +6 -0
  114. package/src/MapView.tsx +27 -10
  115. package/src/MapView.types.ts +24 -15
  116. package/src/MapView.web.tsx +319 -0
  117. package/src/components/Marker.tsx +63 -0
  118. package/src/components/Marker.web.tsx +32 -0
  119. package/src/components/Polyline.tsx +57 -0
  120. package/src/components/Polyline.web.tsx +222 -0
  121. package/src/components/index.ts +2 -0
  122. package/src/components/index.web.ts +4 -0
  123. package/{lib/module/fabric/LuggMapsAppleMapViewNativeComponent.ts → src/fabric/LuggAppleMapViewNativeComponent.ts} +13 -3
  124. package/src/fabric/{LuggMapsGoogleMapViewNativeComponent.ts → LuggGoogleMapViewNativeComponent.ts} +13 -3
  125. package/{lib/module/fabric/LuggMapsWrapperViewNativeComponent.ts → src/fabric/LuggMapWrapperViewNativeComponent.ts} +1 -1
  126. package/src/fabric/{LuggMapsMarkerViewNativeComponent.ts → LuggMarkerViewNativeComponent.ts} +1 -1
  127. package/{lib/module/fabric/LuggMapsPolylineViewNativeComponent.ts → src/fabric/LuggPolylineViewNativeComponent.ts} +1 -1
  128. package/src/index.ts +11 -7
  129. package/src/index.web.ts +17 -0
  130. package/android/src/main/java/com/luggmaps/LuggMapsWrapperViewManager.kt +0 -25
  131. package/lib/module/Marker.js.map +0 -1
  132. package/lib/module/Marker.types.js +0 -4
  133. package/lib/module/Marker.types.js.map +0 -1
  134. package/lib/module/Polyline.js.map +0 -1
  135. package/lib/module/Polyline.types.js +0 -4
  136. package/lib/module/Polyline.types.js.map +0 -1
  137. package/lib/typescript/plugin/src/withMapsAndroid.d.ts.map +0 -1
  138. package/lib/typescript/plugin/src/withMapsIOS.d.ts.map +0 -1
  139. package/lib/typescript/src/Marker.d.ts.map +0 -1
  140. package/lib/typescript/src/Marker.types.d.ts.map +0 -1
  141. package/lib/typescript/src/Polyline.d.ts +0 -6
  142. package/lib/typescript/src/Polyline.d.ts.map +0 -1
  143. package/lib/typescript/src/Polyline.types.d.ts.map +0 -1
  144. package/lib/typescript/src/fabric/LuggMapsAppleMapViewNativeComponent.d.ts.map +0 -1
  145. package/lib/typescript/src/fabric/LuggMapsGoogleMapViewNativeComponent.d.ts.map +0 -1
  146. package/lib/typescript/src/fabric/LuggMapsMarkerViewNativeComponent.d.ts.map +0 -1
  147. package/lib/typescript/src/fabric/LuggMapsPolylineViewNativeComponent.d.ts.map +0 -1
  148. package/lib/typescript/src/fabric/LuggMapsWrapperViewNativeComponent.d.ts.map +0 -1
  149. package/src/Marker.tsx +0 -31
  150. package/src/Marker.types.ts +0 -32
  151. package/src/Polyline.tsx +0 -32
  152. package/src/Polyline.types.ts +0 -24
package/package.json CHANGED
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "name": "@lugg/maps",
3
- "version": "0.2.0-alpha.0",
3
+ "version": "0.2.0-alpha.10",
4
4
  "description": "Universal maps for React Native.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
7
7
  "exports": {
8
8
  ".": {
9
9
  "source": "./src/index.ts",
10
+ "react-native": "./lib/module/index.js",
11
+ "web": {
12
+ "types": "./lib/typescript/src/index.web.d.ts",
13
+ "default": "./lib/module/index.web.js"
14
+ },
10
15
  "types": "./lib/typescript/src/index.d.ts",
11
16
  "default": "./lib/module/index.js"
12
17
  },
13
- "./package.json": "./package.json"
18
+ "./package.json": "./package.json",
19
+ "./app.plugin.js": "./app.plugin.js"
14
20
  },
15
21
  "files": [
16
22
  "src",
@@ -74,6 +80,7 @@
74
80
  "@release-it/conventional-changelog": "^10.0.1",
75
81
  "@types/jest": "^29.5.14",
76
82
  "@types/react": "^19.2.0",
83
+ "@vis.gl/react-google-maps": "^1.7.1",
77
84
  "commitlint": "^19.8.1",
78
85
  "del-cli": "^6.0.0",
79
86
  "eslint": "^9.35.0",
@@ -90,9 +97,15 @@
90
97
  "typescript": "^5.9.2"
91
98
  },
92
99
  "peerDependencies": {
100
+ "@vis.gl/react-google-maps": ">=1.0.0",
93
101
  "react": "*",
94
102
  "react-native": "*"
95
103
  },
104
+ "peerDependenciesMeta": {
105
+ "@vis.gl/react-google-maps": {
106
+ "optional": true
107
+ }
108
+ },
96
109
  "dependencies": {
97
110
  "@expo/config-plugins": "^9.0.0"
98
111
  },
@@ -129,11 +142,11 @@
129
142
  },
130
143
  "ios": {
131
144
  "componentProvider": {
132
- "LuggMapsGoogleMapView": "LuggMapsGoogleMapView",
133
- "LuggMapsAppleMapView": "LuggMapsAppleMapView",
134
- "LuggMapsMarkerView": "LuggMapsMarkerView",
135
- "LuggMapsWrapperView": "LuggMapsWrapperView",
136
- "LuggMapsPolylineView": "LuggMapsPolylineView"
145
+ "LuggGoogleMapView": "LuggGoogleMapView",
146
+ "LuggAppleMapView": "LuggAppleMapView",
147
+ "LuggMarkerView": "LuggMarkerView",
148
+ "LuggMapWrapperView": "LuggMapWrapperView",
149
+ "LuggPolylineView": "LuggPolylineView"
137
150
  }
138
151
  }
139
152
  },
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const config_plugins_1 = require("@expo/config-plugins");
4
- const withMapsAndroid_1 = require("./withMapsAndroid");
5
- const withMapsIOS_1 = require("./withMapsIOS");
4
+ const withLuggMapsAndroid_1 = require("./withLuggMapsAndroid");
5
+ const withLuggMapsIOS_1 = require("./withLuggMapsIOS");
6
6
  const pkg = require('../../package.json');
7
7
  const withMaps = (config, props = {}) => {
8
8
  const { iosGoogleMapsApiKey, androidGoogleMapsApiKey } = props ?? {};
9
- config = (0, withMapsIOS_1.withLuggMapsIOS)(config, { apiKey: iosGoogleMapsApiKey });
10
- config = (0, withMapsAndroid_1.withLuggMapsAndroid)(config, { apiKey: androidGoogleMapsApiKey });
9
+ config = (0, withLuggMapsIOS_1.withLuggMapsIOS)(config, { apiKey: iosGoogleMapsApiKey });
10
+ config = (0, withLuggMapsAndroid_1.withLuggMapsAndroid)(config, { apiKey: androidGoogleMapsApiKey });
11
11
  return config;
12
12
  };
13
13
  exports.default = (0, config_plugins_1.createRunOncePlugin)(withMaps, pkg.name, pkg.version);
@@ -3,4 +3,3 @@ export interface MapsAndroidPluginProps {
3
3
  apiKey?: string;
4
4
  }
5
5
  export declare const withLuggMapsAndroid: ConfigPlugin<MapsAndroidPluginProps>;
6
- //# sourceMappingURL=withMapsAndroid.d.ts.map
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withLuggMapsAndroid = void 0;
4
+ const config_plugins_1 = require("@expo/config-plugins");
5
+ const withLuggMapsAndroid = (config, { apiKey }) => {
6
+ if (!apiKey) {
7
+ return config;
8
+ }
9
+ return (0, config_plugins_1.withAndroidManifest)(config, (c) => {
10
+ const mainApplication = config_plugins_1.AndroidConfig.Manifest.getMainApplicationOrThrow(c.modResults);
11
+ config_plugins_1.AndroidConfig.Manifest.addMetaDataItemToMainApplication(mainApplication, 'com.google.android.geo.API_KEY', apiKey);
12
+ return c;
13
+ });
14
+ };
15
+ exports.withLuggMapsAndroid = withLuggMapsAndroid;
@@ -3,4 +3,3 @@ export interface MapsIOSPluginProps {
3
3
  apiKey?: string;
4
4
  }
5
5
  export declare const withLuggMapsIOS: ConfigPlugin<MapsIOSPluginProps>;
6
- //# sourceMappingURL=withMapsIOS.d.ts.map
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withLuggMapsIOS = void 0;
4
+ const config_plugins_1 = require("@expo/config-plugins");
5
+ const withLuggMapsIOS = (config, { apiKey }) => {
6
+ if (!apiKey) {
7
+ return config;
8
+ }
9
+ config = (0, config_plugins_1.withInfoPlist)(config, (c) => {
10
+ c.modResults.GMSApiKey = apiKey;
11
+ return c;
12
+ });
13
+ config = (0, config_plugins_1.withAppDelegate)(config, (c) => {
14
+ const contents = c.modResults.contents;
15
+ // Add import for GoogleMaps
16
+ if (!contents.includes('import GoogleMaps')) {
17
+ c.modResults.contents = contents.replace(/(import (?:UIKit|Expo))/, '$1\nimport GoogleMaps');
18
+ }
19
+ // Add GMSServices.provideAPIKey call
20
+ if (!c.modResults.contents.includes('GMSServices.provideAPIKey')) {
21
+ c.modResults.contents = c.modResults.contents.replace(/(func application\([^)]+\)[^{]*\{)/, `$1\n GMSServices.provideAPIKey("${apiKey}")\n`);
22
+ }
23
+ return c;
24
+ });
25
+ return config;
26
+ };
27
+ exports.withLuggMapsIOS = withLuggMapsIOS;
@@ -1,5 +1,5 @@
1
1
  import { type ConfigPlugin } from '@expo/config-plugins';
2
2
  export interface MapsAndroidPluginProps {
3
- apiKey?: string;
3
+ apiKey?: string;
4
4
  }
5
5
  export declare const withLuggMapsAndroid: ConfigPlugin<MapsAndroidPluginProps>;
@@ -1,5 +1,5 @@
1
1
  import { type ConfigPlugin } from '@expo/config-plugins';
2
2
  export interface MapsIOSPluginProps {
3
- apiKey?: string;
3
+ apiKey?: string;
4
4
  }
5
5
  export declare const withLuggMapsIOS: ConfigPlugin<MapsIOSPluginProps>;
@@ -0,0 +1,10 @@
1
+ import type { MapProviderProps } from './MapProvider.types';
2
+
3
+ /**
4
+ * Provider component for map configuration.
5
+ * On web, wraps children with Google Maps APIProvider.
6
+ * On native, passes children through.
7
+ */
8
+ export function MapProvider({ children }: MapProviderProps) {
9
+ return children;
10
+ }
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ /**
4
+ * MapProvider props
5
+ */
6
+ export interface MapProviderProps {
7
+ /**
8
+ * Google Maps API key
9
+ * @platform web
10
+ */
11
+ apiKey?: string;
12
+ /**
13
+ * Map children
14
+ */
15
+ children: ReactNode;
16
+ }
@@ -0,0 +1,6 @@
1
+ import { APIProvider } from '@vis.gl/react-google-maps';
2
+ import type { MapProviderProps } from './MapProvider.types';
3
+
4
+ export function MapProvider({ apiKey = '', children }: MapProviderProps) {
5
+ return <APIProvider apiKey={apiKey}>{children}</APIProvider>;
6
+ }
package/src/MapView.tsx CHANGED
@@ -1,12 +1,12 @@
1
1
  import React from 'react';
2
2
  import { Platform, StyleSheet } from 'react-native';
3
- import LuggMapsGoogleMapViewNativeComponent, {
3
+ import LuggGoogleMapViewNativeComponent, {
4
4
  Commands as GoogleMapCommands,
5
- } from './fabric/LuggMapsGoogleMapViewNativeComponent';
6
- import LuggMapsAppleMapViewNativeComponent, {
5
+ } from './fabric/LuggGoogleMapViewNativeComponent';
6
+ import LuggAppleMapViewNativeComponent, {
7
7
  Commands as AppleMapCommands,
8
- } from './fabric/LuggMapsAppleMapViewNativeComponent';
9
- import LuggMapsWrapperViewNativeComponent from './fabric/LuggMapsWrapperViewNativeComponent';
8
+ } from './fabric/LuggAppleMapViewNativeComponent';
9
+ import LuggMapWrapperViewNativeComponent from './fabric/LuggMapWrapperViewNativeComponent';
10
10
  import type {
11
11
  MapViewProps,
12
12
  MapViewRef,
@@ -55,7 +55,8 @@ export class MapView
55
55
  const first = coordinates[0];
56
56
  if (!ref || !first) return;
57
57
 
58
- const { padding = 0, duration = -1 } = options ?? {};
58
+ const { padding, duration = -1 } = options ?? {};
59
+ const { top = 0, left = 0, bottom = 0, right = 0 } = padding ?? {};
59
60
 
60
61
  if (coordinates.length === 1) {
61
62
  const zoom = this.props.initialZoom ?? 10;
@@ -63,7 +64,15 @@ export class MapView
63
64
  return;
64
65
  }
65
66
 
66
- this.nativeCommands.fitCoordinates(ref, coordinates, padding, duration);
67
+ this.nativeCommands.fitCoordinates(
68
+ ref,
69
+ coordinates,
70
+ top,
71
+ left,
72
+ bottom,
73
+ right,
74
+ duration
75
+ );
67
76
  }
68
77
 
69
78
  render() {
@@ -72,21 +81,25 @@ export class MapView
72
81
  mapId,
73
82
  initialCoordinate,
74
83
  initialZoom,
84
+ minZoom,
85
+ maxZoom,
75
86
  zoomEnabled,
76
87
  scrollEnabled,
77
88
  rotateEnabled,
78
89
  pitchEnabled,
79
90
  padding,
91
+ userLocationEnabled,
80
92
  onCameraMove,
81
93
  onCameraIdle,
94
+ onReady,
82
95
  children,
83
96
  ...rest
84
97
  } = this.props;
85
98
 
86
99
  const NativeMapView =
87
100
  Platform.OS === 'ios' && provider === 'apple'
88
- ? LuggMapsAppleMapViewNativeComponent
89
- : LuggMapsGoogleMapViewNativeComponent;
101
+ ? LuggAppleMapViewNativeComponent
102
+ : LuggGoogleMapViewNativeComponent;
90
103
 
91
104
  return (
92
105
  <NativeMapView
@@ -95,15 +108,19 @@ export class MapView
95
108
  mapId={mapId}
96
109
  initialCoordinate={initialCoordinate}
97
110
  initialZoom={initialZoom}
111
+ minZoom={minZoom}
112
+ maxZoom={maxZoom}
98
113
  zoomEnabled={zoomEnabled}
99
114
  scrollEnabled={scrollEnabled}
100
115
  rotateEnabled={rotateEnabled}
101
116
  pitchEnabled={pitchEnabled}
102
117
  padding={padding}
118
+ userLocationEnabled={userLocationEnabled}
103
119
  onCameraMove={onCameraMove}
104
120
  onCameraIdle={onCameraIdle}
121
+ onReady={onReady}
105
122
  >
106
- <LuggMapsWrapperViewNativeComponent style={StyleSheet.absoluteFill} />
123
+ <LuggMapWrapperViewNativeComponent style={StyleSheet.absoluteFill} />
107
124
  {children}
108
125
  </NativeMapView>
109
126
  );
@@ -13,11 +13,10 @@ export interface MoveCameraOptions {
13
13
 
14
14
  /**
15
15
  * Options for fitting coordinates in view
16
- * @default padding 0
17
16
  * @default duration -1
18
17
  */
19
18
  export interface FitCoordinatesOptions {
20
- padding?: number;
19
+ padding?: EdgeInsets;
21
20
  duration?: number;
22
21
  }
23
22
 
@@ -33,20 +32,12 @@ export interface MapViewRef {
33
32
  }
34
33
 
35
34
  /**
36
- * Camera move event data
37
- */
38
- export interface CameraMoveEvent {
39
- coordinate: Coordinate;
40
- zoom: number;
41
- dragging: boolean;
42
- }
43
-
44
- /**
45
- * Camera idle event data
35
+ * Camera event payload
46
36
  */
47
- export interface CameraIdleEvent {
37
+ export interface CameraEventPayload {
48
38
  coordinate: Coordinate;
49
39
  zoom: number;
40
+ gesture: boolean;
50
41
  }
51
42
 
52
43
  /**
@@ -71,6 +62,14 @@ export interface MapViewProps extends ViewProps {
71
62
  * @default 10
72
63
  */
73
64
  initialZoom?: number;
65
+ /**
66
+ * Minimum zoom level
67
+ */
68
+ minZoom?: number;
69
+ /**
70
+ * Maximum zoom level
71
+ */
72
+ maxZoom?: number;
74
73
  /**
75
74
  * Enable zoom gestures
76
75
  * @default true
@@ -95,14 +94,24 @@ export interface MapViewProps extends ViewProps {
95
94
  * Map content padding
96
95
  */
97
96
  padding?: EdgeInsets;
97
+ /**
98
+ * Show current user location on the map.
99
+ * Requires location permission to be granted, otherwise silently ignored.
100
+ * @default false
101
+ */
102
+ userLocationEnabled?: boolean;
98
103
  /**
99
104
  * Called when camera moves
100
105
  */
101
- onCameraMove?: (event: NativeSyntheticEvent<CameraMoveEvent>) => void;
106
+ onCameraMove?: (event: NativeSyntheticEvent<CameraEventPayload>) => void;
102
107
  /**
103
108
  * Called when camera stops moving
104
109
  */
105
- onCameraIdle?: (event: NativeSyntheticEvent<CameraIdleEvent>) => void;
110
+ onCameraIdle?: (event: NativeSyntheticEvent<CameraEventPayload>) => void;
111
+ /**
112
+ * Called when map is loaded and ready
113
+ */
114
+ onReady?: () => void;
106
115
  /**
107
116
  * Map children (markers, polylines, etc.)
108
117
  */
@@ -0,0 +1,319 @@
1
+ import {
2
+ Children,
3
+ Component,
4
+ isValidElement,
5
+ useEffect,
6
+ useRef,
7
+ useState,
8
+ type CSSProperties,
9
+ type ReactElement,
10
+ type ReactNode,
11
+ } from 'react';
12
+ import type { NativeSyntheticEvent, ViewStyle } from 'react-native';
13
+ import { View } from 'react-native';
14
+ import { Map, useMap } from '@vis.gl/react-google-maps';
15
+ import { Marker } from './components/Marker.web';
16
+ import { Polyline } from './components/Polyline.web';
17
+
18
+ import type {
19
+ MapViewProps,
20
+ MapViewRef,
21
+ MoveCameraOptions,
22
+ FitCoordinatesOptions,
23
+ CameraEventPayload,
24
+ } from './MapView.types';
25
+ import type { Coordinate } from './types';
26
+
27
+ // Map-specific component types that render inside the Google Map
28
+ const MAP_COMPONENT_TYPES = new Set([Marker, Polyline]);
29
+
30
+ const isMapComponent = (child: ReactElement): boolean =>
31
+ MAP_COMPONENT_TYPES.has(child.type as typeof Marker | typeof Polyline);
32
+
33
+ const createSyntheticEvent = <T,>(nativeEvent: T): NativeSyntheticEvent<T> =>
34
+ ({
35
+ nativeEvent,
36
+ currentTarget: null,
37
+ target: null,
38
+ bubbles: false,
39
+ cancelable: false,
40
+ defaultPrevented: false,
41
+ eventPhase: 0,
42
+ isTrusted: true,
43
+ preventDefault: () => {},
44
+ stopPropagation: () => {},
45
+ isDefaultPrevented: () => false,
46
+ isPropagationStopped: () => false,
47
+ persist: () => {},
48
+ timeStamp: Date.now(),
49
+ type: '',
50
+ } as unknown as NativeSyntheticEvent<T>);
51
+
52
+ interface MapControllerProps {
53
+ onMapReady: (map: google.maps.Map) => void;
54
+ onCameraMove?: (event: NativeSyntheticEvent<CameraEventPayload>) => void;
55
+ onCameraIdle?: (event: NativeSyntheticEvent<CameraEventPayload>) => void;
56
+ onReady?: () => void;
57
+ }
58
+
59
+ interface UserLocationMarkerProps {
60
+ enabled?: boolean;
61
+ }
62
+
63
+ const userLocationDotStyle: CSSProperties = {
64
+ width: 16,
65
+ height: 16,
66
+ backgroundColor: '#4285F4',
67
+ border: '2px solid white',
68
+ borderRadius: '50%',
69
+ boxShadow: '0 1px 4px rgba(0,0,0,0.3)',
70
+ };
71
+
72
+ function UserLocationMarker({ enabled }: UserLocationMarkerProps) {
73
+ const [coordinate, setCoordinate] = useState<Coordinate | null>(null);
74
+
75
+ useEffect(() => {
76
+ if (!enabled) {
77
+ setCoordinate(null);
78
+ return;
79
+ }
80
+
81
+ let watchId: number | null = null;
82
+
83
+ const updateLocation = (position: GeolocationPosition) => {
84
+ setCoordinate({
85
+ latitude: position.coords.latitude,
86
+ longitude: position.coords.longitude,
87
+ });
88
+ };
89
+
90
+ navigator.geolocation.getCurrentPosition(updateLocation, () => {});
91
+ watchId = navigator.geolocation.watchPosition(updateLocation, () => {});
92
+
93
+ return () => {
94
+ if (watchId !== null) {
95
+ navigator.geolocation.clearWatch(watchId);
96
+ }
97
+ };
98
+ }, [enabled]);
99
+
100
+ if (!coordinate) return null;
101
+
102
+ return (
103
+ <Marker coordinate={coordinate} anchor={{ x: 0.5, y: 0.5 }}>
104
+ <div style={userLocationDotStyle} />
105
+ </Marker>
106
+ );
107
+ }
108
+
109
+ function MapController({
110
+ onMapReady,
111
+ onCameraMove,
112
+ onCameraIdle,
113
+ onReady,
114
+ }: MapControllerProps) {
115
+ const map = useMap();
116
+ const readyFired = useRef(false);
117
+
118
+ useEffect(() => {
119
+ if (!map) return;
120
+ onMapReady(map);
121
+
122
+ if (!readyFired.current) {
123
+ readyFired.current = true;
124
+ onReady?.();
125
+ }
126
+ }, [map, onMapReady, onReady]);
127
+
128
+ useEffect(() => {
129
+ if (!map) return;
130
+
131
+ const createPayload = (gesture: boolean): CameraEventPayload => {
132
+ const center = map.getCenter();
133
+ return {
134
+ coordinate: {
135
+ latitude: center?.lat() ?? 0,
136
+ longitude: center?.lng() ?? 0,
137
+ },
138
+ zoom: map.getZoom() ?? 0,
139
+ gesture,
140
+ };
141
+ };
142
+
143
+ let isDragging = false;
144
+
145
+ const dragStartListener = map.addListener('dragstart', () => {
146
+ isDragging = true;
147
+ });
148
+
149
+ const dragEndListener = map.addListener('dragend', () => {
150
+ isDragging = false;
151
+ });
152
+
153
+ const centerListener = map.addListener('center_changed', () => {
154
+ onCameraMove?.(createSyntheticEvent(createPayload(isDragging)));
155
+ });
156
+
157
+ const idleListener = map.addListener('idle', () => {
158
+ onCameraIdle?.(createSyntheticEvent(createPayload(false)));
159
+ });
160
+
161
+ return () => {
162
+ google.maps.event.removeListener(dragStartListener);
163
+ google.maps.event.removeListener(dragEndListener);
164
+ google.maps.event.removeListener(centerListener);
165
+ google.maps.event.removeListener(idleListener);
166
+ };
167
+ }, [map, onCameraMove, onCameraIdle]);
168
+
169
+ return null;
170
+ }
171
+
172
+ export class MapView extends Component<MapViewProps> implements MapViewRef {
173
+ static defaultProps: Partial<MapViewProps> = {
174
+ provider: 'google',
175
+ mapId: 'DEMO_MAP_ID',
176
+ initialZoom: 10,
177
+ zoomEnabled: true,
178
+ scrollEnabled: true,
179
+ rotateEnabled: true,
180
+ pitchEnabled: true,
181
+ };
182
+
183
+ private mapInstance: google.maps.Map | null = null;
184
+
185
+ private handleMapReady = (map: google.maps.Map) => {
186
+ this.mapInstance = map;
187
+ };
188
+
189
+ moveCamera(coordinate: Coordinate, options: MoveCameraOptions) {
190
+ const map = this.mapInstance;
191
+ if (!map) return;
192
+
193
+ const { zoom, duration = -1 } = options;
194
+ const center = { lat: coordinate.latitude, lng: coordinate.longitude };
195
+
196
+ if (duration === 0) {
197
+ map.moveCamera({ center, zoom });
198
+ } else {
199
+ const currentZoom = map.getZoom();
200
+ const zoomChanged = zoom !== undefined && zoom !== currentZoom;
201
+
202
+ if (zoomChanged) {
203
+ map.setZoom(zoom);
204
+ }
205
+ map.panTo(center);
206
+ }
207
+ }
208
+
209
+ fitCoordinates(coordinates: Coordinate[], options?: FitCoordinatesOptions) {
210
+ const map = this.mapInstance;
211
+ const first = coordinates[0];
212
+ if (!map || !first) return;
213
+
214
+ const { padding, duration = -1 } = options ?? {};
215
+
216
+ if (coordinates.length === 1) {
217
+ const zoom = this.props.initialZoom ?? 10;
218
+ this.moveCamera(first, { zoom, duration });
219
+ return;
220
+ }
221
+
222
+ const bounds = new google.maps.LatLngBounds();
223
+ coordinates.forEach((coord) => {
224
+ bounds.extend({ lat: coord.latitude, lng: coord.longitude });
225
+ });
226
+
227
+ map.fitBounds(bounds, {
228
+ top: padding?.top ?? 0,
229
+ left: padding?.left ?? 0,
230
+ bottom: padding?.bottom ?? 0,
231
+ right: padding?.right ?? 0,
232
+ });
233
+ }
234
+
235
+ render() {
236
+ const {
237
+ mapId,
238
+ initialCoordinate,
239
+ initialZoom,
240
+ minZoom,
241
+ maxZoom,
242
+ zoomEnabled,
243
+ scrollEnabled,
244
+ pitchEnabled,
245
+ padding,
246
+ userLocationEnabled,
247
+ onCameraMove,
248
+ onCameraIdle,
249
+ onReady,
250
+ children,
251
+ style,
252
+ } = this.props;
253
+
254
+ const gestureHandling =
255
+ scrollEnabled === false && zoomEnabled === false
256
+ ? 'none'
257
+ : scrollEnabled === false
258
+ ? 'none'
259
+ : 'auto';
260
+
261
+ const defaultCenter = initialCoordinate
262
+ ? { lat: initialCoordinate.latitude, lng: initialCoordinate.longitude }
263
+ : undefined;
264
+
265
+ // Separate map children (Marker, Polyline) from overlay children (regular Views)
266
+ const mapChildren: ReactNode[] = [];
267
+ const overlayChildren: ReactNode[] = [];
268
+
269
+ Children.forEach(children, (child) => {
270
+ if (!isValidElement(child)) return;
271
+ if (isMapComponent(child)) {
272
+ mapChildren.push(child);
273
+ } else {
274
+ overlayChildren.push(child);
275
+ }
276
+ });
277
+
278
+ const mapContainerStyle: ViewStyle = {
279
+ position: 'absolute',
280
+ top: padding?.top ?? 0,
281
+ left: padding?.left ?? 0,
282
+ right: padding?.right ?? 0,
283
+ bottom: padding?.bottom ?? 0,
284
+ };
285
+
286
+ const mapStyle: CSSProperties = {
287
+ width: '100%',
288
+ height: '100%',
289
+ };
290
+
291
+ return (
292
+ <View style={style}>
293
+ <View style={mapContainerStyle}>
294
+ <Map
295
+ mapId={mapId}
296
+ defaultCenter={defaultCenter}
297
+ defaultZoom={initialZoom}
298
+ minZoom={minZoom}
299
+ maxZoom={maxZoom}
300
+ gestureHandling={gestureHandling}
301
+ disableDefaultUI
302
+ tilt={pitchEnabled === false ? 0 : undefined}
303
+ style={mapStyle}
304
+ >
305
+ <MapController
306
+ onMapReady={this.handleMapReady}
307
+ onCameraMove={onCameraMove}
308
+ onCameraIdle={onCameraIdle}
309
+ onReady={onReady}
310
+ />
311
+ <UserLocationMarker enabled={userLocationEnabled} />
312
+ {mapChildren}
313
+ </Map>
314
+ </View>
315
+ {overlayChildren}
316
+ </View>
317
+ );
318
+ }
319
+ }