@lugg/maps 0.2.0-alpha.6 → 0.2.0-alpha.8

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 (49) hide show
  1. package/README.md +17 -4
  2. package/lib/module/MapProvider.js +13 -0
  3. package/lib/module/MapProvider.js.map +1 -0
  4. package/lib/module/MapProvider.types.js +4 -0
  5. package/lib/module/MapProvider.types.js.map +1 -0
  6. package/lib/module/MapProvider.web.js +14 -0
  7. package/lib/module/MapProvider.web.js.map +1 -0
  8. package/lib/module/MapView.web.js +264 -0
  9. package/lib/module/MapView.web.js.map +1 -0
  10. package/lib/module/components/Marker.web.js +34 -0
  11. package/lib/module/components/Marker.web.js.map +1 -0
  12. package/lib/module/components/Polyline.web.js +171 -0
  13. package/lib/module/components/Polyline.web.js.map +1 -0
  14. package/lib/module/components/index.js +2 -2
  15. package/lib/module/components/index.js.map +1 -1
  16. package/lib/module/components/index.web.js +5 -0
  17. package/lib/module/components/index.web.js.map +1 -0
  18. package/lib/module/index.js +3 -2
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/index.web.js +6 -0
  21. package/lib/module/index.web.js.map +1 -0
  22. package/lib/typescript/src/MapProvider.d.ts +8 -0
  23. package/lib/typescript/src/MapProvider.d.ts.map +1 -0
  24. package/lib/typescript/src/MapProvider.types.d.ts +16 -0
  25. package/lib/typescript/src/MapProvider.types.d.ts.map +1 -0
  26. package/lib/typescript/src/MapProvider.web.d.ts +3 -0
  27. package/lib/typescript/src/MapProvider.web.d.ts.map +1 -0
  28. package/lib/typescript/src/MapView.web.d.ts +12 -0
  29. package/lib/typescript/src/MapView.web.d.ts.map +1 -0
  30. package/lib/typescript/src/components/Marker.web.d.ts +6 -0
  31. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -0
  32. package/lib/typescript/src/components/Polyline.web.d.ts +6 -0
  33. package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -0
  34. package/lib/typescript/src/components/index.web.d.ts +5 -0
  35. package/lib/typescript/src/components/index.web.d.ts.map +1 -0
  36. package/lib/typescript/src/index.d.ts +3 -1
  37. package/lib/typescript/src/index.d.ts.map +1 -1
  38. package/lib/typescript/src/index.web.d.ts +7 -0
  39. package/lib/typescript/src/index.web.d.ts.map +1 -0
  40. package/package.json +13 -1
  41. package/src/MapProvider.tsx +10 -0
  42. package/src/MapProvider.types.ts +16 -0
  43. package/src/MapProvider.web.tsx +6 -0
  44. package/src/MapView.web.tsx +317 -0
  45. package/src/components/Marker.web.tsx +32 -0
  46. package/src/components/Polyline.web.tsx +206 -0
  47. package/src/components/index.web.ts +4 -0
  48. package/src/index.ts +8 -1
  49. package/src/index.web.ts +17 -0
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from 'react';
2
+ /**
3
+ * MapProvider props
4
+ */
5
+ export interface MapProviderProps {
6
+ /**
7
+ * Google Maps API key
8
+ * @platform web
9
+ */
10
+ apiKey?: string;
11
+ /**
12
+ * Map children
13
+ */
14
+ children: ReactNode;
15
+ }
16
+ //# sourceMappingURL=MapProvider.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapProvider.types.d.ts","sourceRoot":"","sources":["../../../src/MapProvider.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB"}
@@ -0,0 +1,3 @@
1
+ import type { MapProviderProps } from './MapProvider.types';
2
+ export declare function MapProvider({ apiKey, children }: MapProviderProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=MapProvider.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapProvider.web.d.ts","sourceRoot":"","sources":["../../../src/MapProvider.web.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,wBAAgB,WAAW,CAAC,EAAE,MAAW,EAAE,QAAQ,EAAE,EAAE,gBAAgB,2CAEtE"}
@@ -0,0 +1,12 @@
1
+ import { Component } from 'react';
2
+ import type { MapViewProps, MapViewRef, MoveCameraOptions, FitCoordinatesOptions } from './MapView.types';
3
+ import type { Coordinate } from './types';
4
+ export declare class MapView extends Component<MapViewProps> implements MapViewRef {
5
+ static defaultProps: Partial<MapViewProps>;
6
+ private mapInstance;
7
+ private handleMapReady;
8
+ moveCamera(coordinate: Coordinate, options: MoveCameraOptions): void;
9
+ fitCoordinates(coordinates: Coordinate[], options?: FitCoordinatesOptions): void;
10
+ render(): import("react/jsx-runtime").JSX.Element;
11
+ }
12
+ //# sourceMappingURL=MapView.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapView.web.d.ts","sourceRoot":"","sources":["../../../src/MapView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EAOV,MAAM,OAAO,CAAC;AAOf,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,qBAAqB,EAEtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAsJ1C,qBAAa,OAAQ,SAAQ,SAAS,CAAC,YAAY,CAAE,YAAW,UAAU;IACxE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,CAQxC;IAEF,OAAO,CAAC,WAAW,CAAgC;IAEnD,OAAO,CAAC,cAAc,CAEpB;IAEF,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB;IAgB7D,cAAc,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,EAAE,qBAAqB;IA0BzE,MAAM;CAoFP"}
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import type { MarkerProps } from './Marker';
3
+ export declare class Marker extends React.Component<MarkerProps> {
4
+ render(): import("react/jsx-runtime").JSX.Element;
5
+ }
6
+ //# sourceMappingURL=Marker.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Marker.web.d.ts","sourceRoot":"","sources":["../../../../src/components/Marker.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAQ5C,qBAAa,MAAO,SAAQ,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;IACtD,MAAM;CAoBP"}
@@ -0,0 +1,6 @@
1
+ import { Component } from 'react';
2
+ import type { PolylineProps } from './Polyline';
3
+ export declare class Polyline extends Component<PolylineProps> {
4
+ render(): import("react/jsx-runtime").JSX.Element;
5
+ }
6
+ //# sourceMappingURL=Polyline.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Polyline.web.d.ts","sourceRoot":"","sources":["../../../../src/components/Polyline.web.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAMV,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAgMhD,qBAAa,QAAS,SAAQ,SAAS,CAAC,aAAa,CAAC;IACpD,MAAM;CAGP"}
@@ -0,0 +1,5 @@
1
+ export { Marker } from './Marker.web';
2
+ export { Polyline } from './Polyline.web';
3
+ export type { MarkerProps } from './Marker';
4
+ export type { PolylineProps } from './Polyline';
5
+ //# sourceMappingURL=index.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../src/components/index.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -1,5 +1,7 @@
1
1
  export { MapView } from './MapView';
2
+ export { MapProvider } from './MapProvider';
3
+ export type { MapProviderProps } from './MapProvider.types';
2
4
  export * from './components';
3
5
  export type { MapViewProps, MapViewRef, MoveCameraOptions, FitCoordinatesOptions, CameraEventPayload, } from './MapView.types';
4
- export type { MapProvider, Coordinate, Point, EdgeInsets } from './types';
6
+ export type { MapProvider as MapProviderType, Coordinate, Point, EdgeInsets, } from './types';
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,YAAY,EACV,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,cAAc,cAAc,CAAC;AAC7B,YAAY,EACV,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,WAAW,IAAI,eAAe,EAC9B,UAAU,EACV,KAAK,EACL,UAAU,GACX,MAAM,SAAS,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { MapView } from './MapView.web';
2
+ export { MapProvider } from './MapProvider.web';
3
+ export type { MapProviderProps } from './MapProvider.types';
4
+ export * from './components/index.web';
5
+ export type { MapViewProps, MapViewRef, MoveCameraOptions, FitCoordinatesOptions, CameraEventPayload, } from './MapView.types';
6
+ export type { MapProvider as MapProviderType, Coordinate, Point, EdgeInsets, } from './types';
7
+ //# sourceMappingURL=index.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../src/index.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,cAAc,wBAAwB,CAAC;AACvC,YAAY,EACV,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,WAAW,IAAI,eAAe,EAC9B,UAAU,EACV,KAAK,EACL,UAAU,GACX,MAAM,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "@lugg/maps",
3
- "version": "0.2.0-alpha.6",
3
+ "version": "0.2.0-alpha.8",
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
  },
@@ -75,6 +80,7 @@
75
80
  "@release-it/conventional-changelog": "^10.0.1",
76
81
  "@types/jest": "^29.5.14",
77
82
  "@types/react": "^19.2.0",
83
+ "@vis.gl/react-google-maps": "^1.7.1",
78
84
  "commitlint": "^19.8.1",
79
85
  "del-cli": "^6.0.0",
80
86
  "eslint": "^9.35.0",
@@ -91,9 +97,15 @@
91
97
  "typescript": "^5.9.2"
92
98
  },
93
99
  "peerDependencies": {
100
+ "@vis.gl/react-google-maps": ">=1.0.0",
94
101
  "react": "*",
95
102
  "react-native": "*"
96
103
  },
104
+ "peerDependenciesMeta": {
105
+ "@vis.gl/react-google-maps": {
106
+ "optional": true
107
+ }
108
+ },
97
109
  "dependencies": {
98
110
  "@expo/config-plugins": "^9.0.0"
99
111
  },
@@ -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
+ }
@@ -0,0 +1,317 @@
1
+ import {
2
+ Children,
3
+ Component,
4
+ isValidElement,
5
+ useEffect,
6
+ useRef,
7
+ type CSSProperties,
8
+ type ReactElement,
9
+ type ReactNode,
10
+ } from 'react';
11
+ import type { NativeSyntheticEvent, ViewStyle } from 'react-native';
12
+ import { View } from 'react-native';
13
+ import { Map, useMap } from '@vis.gl/react-google-maps';
14
+ import { Marker } from './components/Marker.web';
15
+ import { Polyline } from './components/Polyline.web';
16
+
17
+ import type {
18
+ MapViewProps,
19
+ MapViewRef,
20
+ MoveCameraOptions,
21
+ FitCoordinatesOptions,
22
+ CameraEventPayload,
23
+ } from './MapView.types';
24
+ import type { Coordinate } from './types';
25
+
26
+ // Map-specific component types that render inside the Google Map
27
+ const MAP_COMPONENT_TYPES = new Set([Marker, Polyline]);
28
+
29
+ const isMapComponent = (child: ReactElement): boolean =>
30
+ MAP_COMPONENT_TYPES.has(child.type as typeof Marker | typeof Polyline);
31
+
32
+ const createSyntheticEvent = <T,>(nativeEvent: T): NativeSyntheticEvent<T> =>
33
+ ({
34
+ nativeEvent,
35
+ currentTarget: null,
36
+ target: null,
37
+ bubbles: false,
38
+ cancelable: false,
39
+ defaultPrevented: false,
40
+ eventPhase: 0,
41
+ isTrusted: true,
42
+ preventDefault: () => {},
43
+ stopPropagation: () => {},
44
+ isDefaultPrevented: () => false,
45
+ isPropagationStopped: () => false,
46
+ persist: () => {},
47
+ timeStamp: Date.now(),
48
+ type: '',
49
+ } as unknown as NativeSyntheticEvent<T>);
50
+
51
+ interface MapControllerProps {
52
+ onMapReady: (map: google.maps.Map) => void;
53
+ onCameraMove?: (event: NativeSyntheticEvent<CameraEventPayload>) => void;
54
+ onCameraIdle?: (event: NativeSyntheticEvent<CameraEventPayload>) => void;
55
+ onReady?: () => void;
56
+ userLocationEnabled?: boolean;
57
+ }
58
+
59
+ function MapController({
60
+ onMapReady,
61
+ onCameraMove,
62
+ onCameraIdle,
63
+ onReady,
64
+ userLocationEnabled,
65
+ }: MapControllerProps) {
66
+ const map = useMap();
67
+ const readyFired = useRef(false);
68
+ const userLocationMarker =
69
+ useRef<google.maps.marker.AdvancedMarkerElement | null>(null);
70
+
71
+ useEffect(() => {
72
+ if (!map) return;
73
+ onMapReady(map);
74
+
75
+ if (!readyFired.current) {
76
+ readyFired.current = true;
77
+ onReady?.();
78
+ }
79
+ }, [map, onMapReady, onReady]);
80
+
81
+ useEffect(() => {
82
+ if (!map || !userLocationEnabled) {
83
+ if (userLocationMarker.current) {
84
+ userLocationMarker.current.map = null;
85
+ userLocationMarker.current = null;
86
+ }
87
+ return;
88
+ }
89
+
90
+ let watchId: number | null = null;
91
+
92
+ const updateLocation = (position: GeolocationPosition) => {
93
+ const { latitude, longitude } = position.coords;
94
+ const pos = { lat: latitude, lng: longitude };
95
+
96
+ if (!userLocationMarker.current) {
97
+ const dot = document.createElement('div');
98
+ dot.style.width = '16px';
99
+ dot.style.height = '16px';
100
+ dot.style.backgroundColor = '#4285F4';
101
+ dot.style.border = '2px solid white';
102
+ dot.style.borderRadius = '50%';
103
+ dot.style.boxShadow = '0 1px 4px rgba(0,0,0,0.3)';
104
+
105
+ userLocationMarker.current =
106
+ new google.maps.marker.AdvancedMarkerElement({
107
+ map,
108
+ position: pos,
109
+ content: dot,
110
+ });
111
+ } else {
112
+ userLocationMarker.current.position = pos;
113
+ }
114
+ };
115
+
116
+ navigator.geolocation.getCurrentPosition(updateLocation, () => {});
117
+ watchId = navigator.geolocation.watchPosition(updateLocation, () => {});
118
+
119
+ return () => {
120
+ if (watchId !== null) {
121
+ navigator.geolocation.clearWatch(watchId);
122
+ }
123
+ if (userLocationMarker.current) {
124
+ userLocationMarker.current.map = null;
125
+ userLocationMarker.current = null;
126
+ }
127
+ };
128
+ }, [map, userLocationEnabled]);
129
+
130
+ useEffect(() => {
131
+ if (!map) return;
132
+
133
+ const createPayload = (gesture: boolean): CameraEventPayload => {
134
+ const center = map.getCenter();
135
+ return {
136
+ coordinate: {
137
+ latitude: center?.lat() ?? 0,
138
+ longitude: center?.lng() ?? 0,
139
+ },
140
+ zoom: map.getZoom() ?? 0,
141
+ gesture,
142
+ };
143
+ };
144
+
145
+ let isDragging = false;
146
+
147
+ const dragStartListener = map.addListener('dragstart', () => {
148
+ isDragging = true;
149
+ });
150
+
151
+ const dragEndListener = map.addListener('dragend', () => {
152
+ isDragging = false;
153
+ });
154
+
155
+ const centerListener = map.addListener('center_changed', () => {
156
+ onCameraMove?.(createSyntheticEvent(createPayload(isDragging)));
157
+ });
158
+
159
+ const idleListener = map.addListener('idle', () => {
160
+ onCameraIdle?.(createSyntheticEvent(createPayload(false)));
161
+ });
162
+
163
+ return () => {
164
+ google.maps.event.removeListener(dragStartListener);
165
+ google.maps.event.removeListener(dragEndListener);
166
+ google.maps.event.removeListener(centerListener);
167
+ google.maps.event.removeListener(idleListener);
168
+ };
169
+ }, [map, onCameraMove, onCameraIdle]);
170
+
171
+ return null;
172
+ }
173
+
174
+ export class MapView extends Component<MapViewProps> implements MapViewRef {
175
+ static defaultProps: Partial<MapViewProps> = {
176
+ provider: 'google',
177
+ mapId: 'DEMO_MAP_ID',
178
+ initialZoom: 10,
179
+ zoomEnabled: true,
180
+ scrollEnabled: true,
181
+ rotateEnabled: true,
182
+ pitchEnabled: true,
183
+ };
184
+
185
+ private mapInstance: google.maps.Map | null = null;
186
+
187
+ private handleMapReady = (map: google.maps.Map) => {
188
+ this.mapInstance = map;
189
+ };
190
+
191
+ moveCamera(coordinate: Coordinate, options: MoveCameraOptions) {
192
+ const map = this.mapInstance;
193
+ if (!map) return;
194
+
195
+ const { zoom, duration = -1 } = options;
196
+ const center = { lat: coordinate.latitude, lng: coordinate.longitude };
197
+
198
+ if (duration > 0) {
199
+ map.panTo(center);
200
+ map.setZoom(zoom);
201
+ } else {
202
+ map.setCenter(center);
203
+ map.setZoom(zoom);
204
+ }
205
+ }
206
+
207
+ fitCoordinates(coordinates: Coordinate[], options?: FitCoordinatesOptions) {
208
+ const map = this.mapInstance;
209
+ const first = coordinates[0];
210
+ if (!map || !first) return;
211
+
212
+ const { padding, duration = -1 } = options ?? {};
213
+
214
+ if (coordinates.length === 1) {
215
+ const zoom = this.props.initialZoom ?? 10;
216
+ this.moveCamera(first, { zoom, duration });
217
+ return;
218
+ }
219
+
220
+ const bounds = new google.maps.LatLngBounds();
221
+ coordinates.forEach((coord) => {
222
+ bounds.extend({ lat: coord.latitude, lng: coord.longitude });
223
+ });
224
+
225
+ map.fitBounds(bounds, {
226
+ top: padding?.top ?? 0,
227
+ left: padding?.left ?? 0,
228
+ bottom: padding?.bottom ?? 0,
229
+ right: padding?.right ?? 0,
230
+ });
231
+ }
232
+
233
+ render() {
234
+ const {
235
+ mapId,
236
+ initialCoordinate,
237
+ initialZoom,
238
+ minZoom,
239
+ maxZoom,
240
+ zoomEnabled,
241
+ scrollEnabled,
242
+ pitchEnabled,
243
+ padding,
244
+ userLocationEnabled,
245
+ onCameraMove,
246
+ onCameraIdle,
247
+ onReady,
248
+ children,
249
+ style,
250
+ } = this.props;
251
+
252
+ const gestureHandling =
253
+ scrollEnabled === false && zoomEnabled === false
254
+ ? 'none'
255
+ : scrollEnabled === false
256
+ ? 'none'
257
+ : 'auto';
258
+
259
+ const defaultCenter = initialCoordinate
260
+ ? { lat: initialCoordinate.latitude, lng: initialCoordinate.longitude }
261
+ : undefined;
262
+
263
+ // Separate map children (Marker, Polyline) from overlay children (regular Views)
264
+ const mapChildren: ReactNode[] = [];
265
+ const overlayChildren: ReactNode[] = [];
266
+
267
+ Children.forEach(children, (child) => {
268
+ if (!isValidElement(child)) return;
269
+ if (isMapComponent(child)) {
270
+ mapChildren.push(child);
271
+ } else {
272
+ overlayChildren.push(child);
273
+ }
274
+ });
275
+
276
+ const mapContainerStyle: ViewStyle = {
277
+ position: 'absolute',
278
+ top: padding?.top ?? 0,
279
+ left: padding?.left ?? 0,
280
+ right: padding?.right ?? 0,
281
+ bottom: padding?.bottom ?? 0,
282
+ };
283
+
284
+ const mapStyle: CSSProperties = {
285
+ width: '100%',
286
+ height: '100%',
287
+ };
288
+
289
+ return (
290
+ <View style={style}>
291
+ <View style={mapContainerStyle}>
292
+ <Map
293
+ mapId={mapId}
294
+ defaultCenter={defaultCenter}
295
+ defaultZoom={initialZoom}
296
+ minZoom={minZoom}
297
+ maxZoom={maxZoom}
298
+ gestureHandling={gestureHandling}
299
+ disableDefaultUI
300
+ tilt={pitchEnabled === false ? 0 : undefined}
301
+ style={mapStyle}
302
+ >
303
+ <MapController
304
+ onMapReady={this.handleMapReady}
305
+ onCameraMove={onCameraMove}
306
+ onCameraIdle={onCameraIdle}
307
+ onReady={onReady}
308
+ userLocationEnabled={userLocationEnabled}
309
+ />
310
+ {mapChildren}
311
+ </Map>
312
+ </View>
313
+ {overlayChildren}
314
+ </View>
315
+ );
316
+ }
317
+ }
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { AdvancedMarker } from '@vis.gl/react-google-maps';
3
+ import type { MarkerProps } from './Marker';
4
+
5
+ /**
6
+ * Converts point to % anchor for web.
7
+ * e.g. `0.5` to `-50%`
8
+ */
9
+ const toWebAnchor = (value: number) => `-${value * 100}%`;
10
+
11
+ export class Marker extends React.Component<MarkerProps> {
12
+ render() {
13
+ const { coordinate, title, anchor, zIndex, children } = this.props;
14
+
15
+ const position = {
16
+ lat: coordinate.latitude,
17
+ lng: coordinate.longitude,
18
+ };
19
+
20
+ return (
21
+ <AdvancedMarker
22
+ position={position}
23
+ title={title}
24
+ zIndex={zIndex}
25
+ anchorLeft={anchor ? toWebAnchor(anchor.x) : undefined}
26
+ anchorTop={anchor ? toWebAnchor(anchor.y) : undefined}
27
+ >
28
+ {children}
29
+ </AdvancedMarker>
30
+ );
31
+ }
32
+ }