@lugg/maps 1.0.0-beta.4 → 1.0.0-beta.6

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 (104) hide show
  1. package/android/src/main/java/com/luggmaps/LuggCalloutView.kt +4 -2
  2. package/android/src/main/java/com/luggmaps/LuggCalloutViewManager.kt +4 -3
  3. package/android/src/main/java/com/luggmaps/LuggMapView.kt +40 -0
  4. package/android/src/main/java/com/luggmaps/LuggMapViewManager.kt +31 -0
  5. package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +23 -0
  6. package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +13 -0
  7. package/android/src/main/java/com/luggmaps/core/GoogleMapProvider.kt +166 -21
  8. package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +5 -0
  9. package/android/src/main/java/com/luggmaps/extensions/ViewExtensions.kt +11 -0
  10. package/ios/LuggCalloutView.h +1 -1
  11. package/ios/LuggCalloutView.mm +21 -11
  12. package/ios/LuggMapView.mm +41 -2
  13. package/ios/LuggMarkerView.h +3 -0
  14. package/ios/LuggMarkerView.mm +23 -0
  15. package/ios/core/AppleMapProvider.mm +236 -16
  16. package/ios/core/GoogleMapProvider.mm +91 -18
  17. package/ios/core/MapProviderDelegate.h +8 -1
  18. package/lib/module/MapProvider.web.js +4 -1
  19. package/lib/module/MapProvider.web.js.map +1 -1
  20. package/lib/module/MapView.js +12 -1
  21. package/lib/module/MapView.js.map +1 -1
  22. package/lib/module/MapView.web.js +21 -18
  23. package/lib/module/MapView.web.js.map +1 -1
  24. package/lib/module/components/Circle.web.js +3 -3
  25. package/lib/module/components/Circle.web.js.map +1 -1
  26. package/lib/module/components/GeoJson.js +3 -3
  27. package/lib/module/components/GeoJson.js.map +1 -1
  28. package/lib/module/components/GroundOverlay.web.js +3 -3
  29. package/lib/module/components/GroundOverlay.web.js.map +1 -1
  30. package/lib/module/components/Marker.js +17 -3
  31. package/lib/module/components/Marker.js.map +1 -1
  32. package/lib/module/components/Marker.web.js +23 -10
  33. package/lib/module/components/Marker.web.js.map +1 -1
  34. package/lib/module/components/Polygon.web.js +3 -3
  35. package/lib/module/components/Polygon.web.js.map +1 -1
  36. package/lib/module/components/Polyline.web.js +6 -12
  37. package/lib/module/components/Polyline.web.js.map +1 -1
  38. package/lib/module/components/TileOverlay.web.js +3 -3
  39. package/lib/module/components/TileOverlay.web.js.map +1 -1
  40. package/lib/module/components/index.js.map +1 -1
  41. package/lib/module/fabric/LuggCalloutViewNativeComponent.ts +1 -1
  42. package/lib/module/fabric/LuggMapViewNativeComponent.ts +9 -1
  43. package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +14 -2
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/typescript/src/MapProvider.web.d.ts +3 -2
  46. package/lib/typescript/src/MapProvider.web.d.ts.map +1 -1
  47. package/lib/typescript/src/MapView.d.ts +1 -1
  48. package/lib/typescript/src/MapView.d.ts.map +1 -1
  49. package/lib/typescript/src/MapView.types.d.ts +36 -1
  50. package/lib/typescript/src/MapView.types.d.ts.map +1 -1
  51. package/lib/typescript/src/MapView.web.d.ts +1 -1
  52. package/lib/typescript/src/MapView.web.d.ts.map +1 -1
  53. package/lib/typescript/src/components/Circle.web.d.ts +1 -1
  54. package/lib/typescript/src/components/Circle.web.d.ts.map +1 -1
  55. package/lib/typescript/src/components/GeoJson.d.ts +2 -1
  56. package/lib/typescript/src/components/GeoJson.d.ts.map +1 -1
  57. package/lib/typescript/src/components/GroundOverlay.web.d.ts +1 -1
  58. package/lib/typescript/src/components/GroundOverlay.web.d.ts.map +1 -1
  59. package/lib/typescript/src/components/Marker.d.ts +6 -3
  60. package/lib/typescript/src/components/Marker.d.ts.map +1 -1
  61. package/lib/typescript/src/components/Marker.types.d.ts +14 -5
  62. package/lib/typescript/src/components/Marker.types.d.ts.map +1 -1
  63. package/lib/typescript/src/components/Marker.web.d.ts +3 -2
  64. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -1
  65. package/lib/typescript/src/components/Polygon.web.d.ts +1 -1
  66. package/lib/typescript/src/components/Polygon.web.d.ts.map +1 -1
  67. package/lib/typescript/src/components/Polyline.web.d.ts +1 -1
  68. package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -1
  69. package/lib/typescript/src/components/TileOverlay.web.d.ts +1 -1
  70. package/lib/typescript/src/components/TileOverlay.web.d.ts.map +1 -1
  71. package/lib/typescript/src/components/index.d.ts +1 -1
  72. package/lib/typescript/src/components/index.d.ts.map +1 -1
  73. package/lib/typescript/src/fabric/LuggCalloutViewNativeComponent.d.ts +1 -1
  74. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts +6 -1
  75. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -1
  76. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +8 -1
  77. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
  78. package/lib/typescript/src/index.d.ts +3 -3
  79. package/lib/typescript/src/index.d.ts.map +1 -1
  80. package/lib/typescript/src/index.web.d.ts +1 -1
  81. package/lib/typescript/src/index.web.d.ts.map +1 -1
  82. package/lib/typescript/src/types.d.ts +0 -4
  83. package/lib/typescript/src/types.d.ts.map +1 -1
  84. package/package.json +1 -1
  85. package/src/MapProvider.web.tsx +5 -3
  86. package/src/MapView.tsx +12 -1
  87. package/src/MapView.types.ts +118 -1
  88. package/src/MapView.web.tsx +378 -345
  89. package/src/components/Circle.web.tsx +81 -79
  90. package/src/components/GeoJson.tsx +3 -3
  91. package/src/components/GroundOverlay.web.tsx +65 -69
  92. package/src/components/Marker.tsx +28 -5
  93. package/src/components/Marker.types.ts +15 -5
  94. package/src/components/Marker.web.tsx +196 -150
  95. package/src/components/Polygon.web.tsx +93 -89
  96. package/src/components/Polyline.web.tsx +235 -235
  97. package/src/components/TileOverlay.web.tsx +83 -81
  98. package/src/components/index.ts +1 -0
  99. package/src/fabric/LuggCalloutViewNativeComponent.ts +1 -1
  100. package/src/fabric/LuggMapViewNativeComponent.ts +9 -1
  101. package/src/fabric/LuggMarkerViewNativeComponent.ts +14 -2
  102. package/src/index.ts +6 -1
  103. package/src/index.web.ts +3 -0
  104. package/src/types.ts +0 -5
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  forwardRef,
3
+ memo,
3
4
  useCallback,
4
5
  useEffect,
5
6
  useId,
6
7
  useImperativeHandle,
8
+ useMemo,
7
9
  useRef,
8
10
  useState,
9
11
  type CSSProperties,
@@ -96,378 +98,409 @@ const UserLocationMarker = ({ enabled }: { enabled?: boolean }) => {
96
98
  );
97
99
  };
98
100
 
99
- export const MapView = forwardRef<MapViewRef, MapViewProps>(function MapView(
100
- props,
101
- ref
102
- ) {
103
- const {
104
- mapId = 'DEMO_MAP_ID',
105
- initialCoordinate,
106
- initialZoom = 10,
107
- minZoom,
108
- maxZoom,
109
- zoomEnabled = true,
110
- scrollEnabled = true,
111
- pitchEnabled = true,
112
- edgeInsets,
113
- userLocationEnabled,
114
- theme = 'system',
115
- onPress,
116
- onLongPress,
117
- onCameraMove,
118
- onCameraIdle,
119
- onReady,
120
- children,
121
- style,
122
- } = props;
123
-
124
- const id = useId();
125
- const map = useMap(id);
126
- const containerRef = useRef<View>(null);
127
- const readyFired = useRef(false);
128
- const [isDragging, setIsDragging] = useState(false);
129
- const wasGesture = useRef(false);
130
- const prevEdgeInsets = useRef(edgeInsets);
131
-
132
- const offsetCenter = useCallback(
133
- (coord: Coordinate, zoom: number, insets?: EdgeInsets, reverse = false) => {
134
- const p = insets ?? prevEdgeInsets.current;
135
- if (!p) {
136
- return { lat: coord.latitude, lng: coord.longitude };
137
- }
138
-
139
- const dir = reverse ? -1 : 1;
140
- const scale = 256 * Math.pow(2, zoom);
141
- const offsetX = (dir * ((p.right ?? 0) - (p.left ?? 0))) / 2;
142
- const offsetY = (dir * ((p.bottom ?? 0) - (p.top ?? 0))) / 2;
143
-
144
- const latRad = (coord.latitude * Math.PI) / 180;
145
- const x = ((coord.longitude + 180) / 360) * scale + offsetX;
146
- const y =
147
- ((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) /
148
- 2) *
149
- scale +
150
- offsetY;
151
-
152
- const lng = (x / scale) * 360 - 180;
153
- const lat =
154
- (Math.atan(Math.sinh(Math.PI * (1 - (2 * y) / scale))) * 180) / Math.PI;
155
-
156
- return { lat, lng };
157
- },
158
- []
159
- );
160
-
161
- const applyEdgeInsets = useCallback(
162
- (newEdgeInsets: EdgeInsets, duration?: number) => {
163
- if (!map) return;
164
-
165
- const prev = prevEdgeInsets.current;
166
- const center = map.getCenter();
167
- const zoom = map.getZoom() ?? initialZoom;
168
-
169
- if (center) {
170
- const logicalCenter = offsetCenter(
171
- { latitude: center.lat(), longitude: center.lng() },
172
- zoom,
173
- prev,
174
- true
175
- );
176
- const newCenter = offsetCenter(
177
- { latitude: logicalCenter.lat, longitude: logicalCenter.lng },
178
- zoom,
179
- newEdgeInsets,
180
- false
181
- );
182
-
183
- if (duration === 0) {
184
- map.moveCamera({ center: newCenter, zoom });
185
- } else {
186
- map.panTo(newCenter);
101
+ export const MapView = memo(
102
+ forwardRef<MapViewRef, MapViewProps>(function MapView(props, ref) {
103
+ const {
104
+ mapType = 'standard',
105
+ mapId = 'DEMO_MAP_ID',
106
+ initialCoordinate,
107
+ initialZoom = 10,
108
+ minZoom,
109
+ maxZoom,
110
+ zoomEnabled = true,
111
+ scrollEnabled = true,
112
+ pitchEnabled = true,
113
+ edgeInsets,
114
+ userLocationEnabled,
115
+ theme = 'system',
116
+ onPress,
117
+ onLongPress,
118
+ onCameraMove,
119
+ onCameraIdle,
120
+ onReady,
121
+ children,
122
+ style,
123
+ } = props;
124
+
125
+ const id = useId();
126
+ const map = useMap(id);
127
+ const containerRef = useRef<View>(null);
128
+ const readyFired = useRef(false);
129
+ const isDraggingRef = useRef(false);
130
+ const wasGesture = useRef(false);
131
+ const prevEdgeInsets = useRef(edgeInsets);
132
+
133
+ const offsetCenter = useCallback(
134
+ (
135
+ coord: Coordinate,
136
+ zoom: number,
137
+ insets?: EdgeInsets,
138
+ reverse = false
139
+ ) => {
140
+ const p = insets ?? prevEdgeInsets.current;
141
+ if (!p) {
142
+ return { lat: coord.latitude, lng: coord.longitude };
187
143
  }
188
- }
189
-
190
- prevEdgeInsets.current = newEdgeInsets;
191
- },
192
- [map, initialZoom, offsetCenter]
193
- );
194
144
 
195
- const panToCoordinate = useCallback(
196
- (coordinate: Coordinate) => {
197
- if (!map) return;
198
- const zoom = map.getZoom() || initialZoom;
199
- const center = offsetCenter(coordinate, zoom, undefined, false);
200
- map.panTo(center);
201
- },
202
- [map, initialZoom, offsetCenter]
203
- );
145
+ const dir = reverse ? -1 : 1;
146
+ const scale = 256 * Math.pow(2, zoom);
147
+ const offsetX = (dir * ((p.right ?? 0) - (p.left ?? 0))) / 2;
148
+ const offsetY = (dir * ((p.bottom ?? 0) - (p.top ?? 0))) / 2;
149
+
150
+ const latRad = (coord.latitude * Math.PI) / 180;
151
+ const x = ((coord.longitude + 180) / 360) * scale + offsetX;
152
+ const y =
153
+ ((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) /
154
+ 2) *
155
+ scale +
156
+ offsetY;
157
+
158
+ const lng = (x / scale) * 360 - 180;
159
+ const lat =
160
+ (Math.atan(Math.sinh(Math.PI * (1 - (2 * y) / scale))) * 180) /
161
+ Math.PI;
162
+
163
+ return { lat, lng };
164
+ },
165
+ []
166
+ );
204
167
 
205
- useImperativeHandle(
206
- ref,
207
- () => ({
208
- moveCamera(coordinate: Coordinate, options?: MoveCameraOptions) {
168
+ const applyEdgeInsets = useCallback(
169
+ (newEdgeInsets: EdgeInsets, duration?: number) => {
209
170
  if (!map) return;
210
171
 
211
- const { zoom = 0, duration = -1 } = options ?? {};
212
- const targetZoom = zoom || map.getZoom() || initialZoom;
213
- const center = offsetCenter(coordinate, targetZoom, undefined, false);
214
-
215
- if (duration === 0) {
216
- map.moveCamera({ center, zoom: targetZoom });
217
- } else {
218
- const currentZoom = map.getZoom();
219
- const zoomChanged = zoom !== 0 && zoom !== currentZoom;
220
-
221
- if (zoomChanged) {
222
- map.setZoom(zoom);
172
+ const prev = prevEdgeInsets.current;
173
+ const center = map.getCenter();
174
+ const zoom = map.getZoom() ?? initialZoom;
175
+
176
+ if (center) {
177
+ const logicalCenter = offsetCenter(
178
+ { latitude: center.lat(), longitude: center.lng() },
179
+ zoom,
180
+ prev,
181
+ true
182
+ );
183
+ const newCenter = offsetCenter(
184
+ { latitude: logicalCenter.lat, longitude: logicalCenter.lng },
185
+ zoom,
186
+ newEdgeInsets,
187
+ false
188
+ );
189
+
190
+ if (duration === 0) {
191
+ map.moveCamera({ center: newCenter, zoom });
192
+ } else {
193
+ map.panTo(newCenter);
223
194
  }
224
- map.panTo(center);
225
195
  }
196
+
197
+ prevEdgeInsets.current = newEdgeInsets;
226
198
  },
199
+ [map, initialZoom, offsetCenter]
200
+ );
227
201
 
228
- fitCoordinates(
229
- coordinates: Coordinate[],
230
- options?: FitCoordinatesOptions
231
- ) {
232
- const first = coordinates[0];
233
- if (!map || !first) return;
202
+ const panToCoordinate = useCallback(
203
+ (coordinate: Coordinate) => {
204
+ if (!map) return;
205
+ const zoom = map.getZoom() || initialZoom;
206
+ const center = offsetCenter(coordinate, zoom, undefined, false);
207
+ map.panTo(center);
208
+ },
209
+ [map, initialZoom, offsetCenter]
210
+ );
234
211
 
235
- const { padding: fitPadding, duration = -1 } = options ?? {};
212
+ useImperativeHandle(
213
+ ref,
214
+ () => ({
215
+ moveCamera(coordinate: Coordinate, options?: MoveCameraOptions) {
216
+ if (!map) return;
217
+
218
+ const { zoom = 0, duration = -1 } = options ?? {};
219
+ const targetZoom = zoom || map.getZoom() || initialZoom;
220
+ const center = offsetCenter(coordinate, targetZoom, undefined, false);
221
+
222
+ if (duration === 0) {
223
+ map.moveCamera({ center, zoom: targetZoom });
224
+ } else {
225
+ const currentZoom = map.getZoom();
226
+ const zoomChanged = zoom !== 0 && zoom !== currentZoom;
227
+
228
+ if (zoomChanged) {
229
+ map.setZoom(zoom);
230
+ }
231
+ map.panTo(center);
232
+ }
233
+ },
236
234
 
237
- if (coordinates.length === 1) {
238
- this.moveCamera(first, { zoom: initialZoom, duration });
239
- return;
240
- }
235
+ fitCoordinates(
236
+ coordinates: Coordinate[],
237
+ options?: FitCoordinatesOptions
238
+ ) {
239
+ const first = coordinates[0];
240
+ if (!map || !first) return;
241
241
 
242
- const bounds = new google.maps.LatLngBounds();
243
- coordinates.forEach((coord) => {
244
- bounds.extend({ lat: coord.latitude, lng: coord.longitude });
245
- });
242
+ const { padding: fitPadding, duration = -1 } = options ?? {};
246
243
 
247
- const ei = prevEdgeInsets.current;
248
- map.fitBounds(bounds, {
249
- top: (ei?.top ?? 0) + (fitPadding?.top ?? 0),
250
- left: (ei?.left ?? 0) + (fitPadding?.left ?? 0),
251
- bottom: (ei?.bottom ?? 0) + (fitPadding?.bottom ?? 0),
252
- right: (ei?.right ?? 0) + (fitPadding?.right ?? 0),
253
- });
254
- },
244
+ if (coordinates.length === 1) {
245
+ this.moveCamera(first, { zoom: initialZoom, duration });
246
+ return;
247
+ }
255
248
 
256
- setEdgeInsets(newEdgeInsets: EdgeInsets, options?: SetEdgeInsetsOptions) {
257
- applyEdgeInsets(newEdgeInsets, options?.duration);
258
- },
259
- }),
260
- [map, initialZoom, offsetCenter, applyEdgeInsets]
261
- );
249
+ const bounds = new google.maps.LatLngBounds();
250
+ coordinates.forEach((coord) => {
251
+ bounds.extend({ lat: coord.latitude, lng: coord.longitude });
252
+ });
253
+
254
+ const ei = prevEdgeInsets.current;
255
+ map.fitBounds(bounds, {
256
+ top: (ei?.top ?? 0) + (fitPadding?.top ?? 0),
257
+ left: (ei?.left ?? 0) + (fitPadding?.left ?? 0),
258
+ bottom: (ei?.bottom ?? 0) + (fitPadding?.bottom ?? 0),
259
+ right: (ei?.right ?? 0) + (fitPadding?.right ?? 0),
260
+ });
261
+ },
262
+
263
+ setEdgeInsets(
264
+ newEdgeInsets: EdgeInsets,
265
+ options?: SetEdgeInsetsOptions
266
+ ) {
267
+ applyEdgeInsets(newEdgeInsets, options?.duration);
268
+ },
269
+ }),
270
+ [map, initialZoom, offsetCenter, applyEdgeInsets]
271
+ );
262
272
 
263
- useEffect(() => {
264
- if (map && !readyFired.current) {
265
- readyFired.current = true;
266
- onReady?.();
267
- }
268
- }, [map, onReady]);
273
+ useEffect(() => {
274
+ if (map && !readyFired.current) {
275
+ readyFired.current = true;
276
+ onReady?.();
277
+ }
278
+ }, [map, onReady]);
269
279
 
270
- useEffect(() => {
271
- if (!map || !edgeInsets) return;
280
+ useEffect(() => {
281
+ if (!map || !edgeInsets) return;
272
282
 
273
- const prev = prevEdgeInsets.current;
274
- const changed =
275
- prev?.top !== edgeInsets.top ||
276
- prev?.left !== edgeInsets.left ||
277
- prev?.bottom !== edgeInsets.bottom ||
278
- prev?.right !== edgeInsets.right;
283
+ const prev = prevEdgeInsets.current;
284
+ const changed =
285
+ prev?.top !== edgeInsets.top ||
286
+ prev?.left !== edgeInsets.left ||
287
+ prev?.bottom !== edgeInsets.bottom ||
288
+ prev?.right !== edgeInsets.right;
289
+
290
+ if (changed) {
291
+ applyEdgeInsets(edgeInsets);
292
+ }
293
+ }, [map, edgeInsets, applyEdgeInsets]);
279
294
 
280
- if (changed) {
281
- applyEdgeInsets(edgeInsets);
282
- }
283
- }, [map, edgeInsets, applyEdgeInsets]);
284
-
285
- const longPressTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
286
- const longPressFired = useRef(false);
287
-
288
- const calloutListeners = useRef(new Set<() => void>()).current;
289
- const onCalloutClose = useCallback(
290
- (listener: () => void) => {
291
- calloutListeners.add(listener);
292
- return () => calloutListeners.delete(listener);
293
- },
294
- [calloutListeners]
295
- );
296
- const closeCallouts = useCallback(
297
- (except?: () => void) => {
298
- calloutListeners.forEach((l) => {
299
- if (l !== except) l();
300
- });
301
- },
302
- [calloutListeners]
303
- );
295
+ const longPressTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
296
+ const longPressFired = useRef(false);
304
297
 
305
- const getPoint = useCallback((domEvent?: Event) => {
306
- const el = containerRef.current as unknown as HTMLElement | null;
307
- if (!domEvent || !el) return { x: 0, y: 0 };
308
- const rect = el.getBoundingClientRect();
309
- const e = domEvent as MouseEvent | Touch;
310
- return { x: e.clientX - rect.left, y: e.clientY - rect.top };
311
- }, []);
312
-
313
- const handleClick = useCallback(
314
- (event: MapMouseEvent) => {
315
- if (longPressFired.current) {
316
- longPressFired.current = false;
317
- return;
318
- }
319
- closeCallouts();
320
- const latLng = event.detail.latLng;
321
- if (!onPress || !latLng) return;
322
- onPress(
323
- createSyntheticEvent({
324
- coordinate: { latitude: latLng.lat, longitude: latLng.lng },
325
- point: getPoint(event.domEvent),
326
- })
327
- );
328
- },
329
- [onPress, getPoint, closeCallouts]
330
- );
298
+ const calloutListeners = useRef(new Set<() => void>()).current;
299
+ const onCalloutClose = useCallback(
300
+ (listener: () => void) => {
301
+ calloutListeners.add(listener);
302
+ return () => calloutListeners.delete(listener);
303
+ },
304
+ [calloutListeners]
305
+ );
306
+ const closeCallouts = useCallback(
307
+ (except?: () => void) => {
308
+ calloutListeners.forEach((l) => {
309
+ if (l !== except) l();
310
+ });
311
+ },
312
+ [calloutListeners]
313
+ );
331
314
 
332
- const handleMouseDown = useCallback(
333
- (event: google.maps.MapMouseEvent) => {
334
- if (!onLongPress) return;
335
- const point = getPoint(event.domEvent);
336
- longPressFired.current = false;
337
- longPressTimer.current = setTimeout(() => {
338
- longPressFired.current = true;
339
- const latLng = event.latLng;
340
- if (!latLng) return;
341
- onLongPress(
315
+ const getPoint = useCallback((domEvent?: Event) => {
316
+ const el = containerRef.current as unknown as HTMLElement | null;
317
+ if (!domEvent || !el) return { x: 0, y: 0 };
318
+ const rect = el.getBoundingClientRect();
319
+ const e = domEvent as MouseEvent | Touch;
320
+ return { x: e.clientX - rect.left, y: e.clientY - rect.top };
321
+ }, []);
322
+
323
+ const handleClick = useCallback(
324
+ (event: MapMouseEvent) => {
325
+ if (longPressFired.current) {
326
+ longPressFired.current = false;
327
+ return;
328
+ }
329
+ closeCallouts();
330
+ const latLng = event.detail.latLng;
331
+ if (!onPress || !latLng) return;
332
+ onPress(
342
333
  createSyntheticEvent({
343
- coordinate: { latitude: latLng.lat(), longitude: latLng.lng() },
344
- point,
334
+ coordinate: { latitude: latLng.lat, longitude: latLng.lng },
335
+ point: getPoint(event.domEvent),
345
336
  })
346
337
  );
347
- }, 500);
348
- },
349
- [onLongPress, getPoint]
350
- );
338
+ },
339
+ [onPress, getPoint, closeCallouts]
340
+ );
351
341
 
352
- const handleMouseUp = useCallback(() => {
353
- if (longPressTimer.current) {
354
- clearTimeout(longPressTimer.current);
355
- longPressTimer.current = null;
356
- }
357
- }, []);
342
+ const handleMouseDown = useCallback(
343
+ (event: google.maps.MapMouseEvent) => {
344
+ if (!onLongPress) return;
345
+ const point = getPoint(event.domEvent);
346
+ longPressFired.current = false;
347
+ longPressTimer.current = setTimeout(() => {
348
+ longPressFired.current = true;
349
+ const latLng = event.latLng;
350
+ if (!latLng) return;
351
+ onLongPress(
352
+ createSyntheticEvent({
353
+ coordinate: { latitude: latLng.lat(), longitude: latLng.lng() },
354
+ point,
355
+ })
356
+ );
357
+ }, 500);
358
+ },
359
+ [onLongPress, getPoint]
360
+ );
358
361
 
359
- useEffect(() => {
360
- if (!map || !onLongPress) return;
361
- const listeners = [
362
- map.addListener('mousedown', handleMouseDown),
363
- map.addListener('mouseup', handleMouseUp),
364
- ];
365
- return () => {
366
- listeners.forEach((l) => google.maps.event.removeListener(l));
362
+ const handleMouseUp = useCallback(() => {
363
+ if (longPressTimer.current) {
364
+ clearTimeout(longPressTimer.current);
365
+ longPressTimer.current = null;
366
+ }
367
+ }, []);
368
+
369
+ useEffect(() => {
370
+ if (!map || !onLongPress) return;
371
+ const listeners = [
372
+ map.addListener('mousedown', handleMouseDown),
373
+ map.addListener('mouseup', handleMouseUp),
374
+ ];
375
+ return () => {
376
+ listeners.forEach((l) => google.maps.event.removeListener(l));
377
+ handleMouseUp();
378
+ };
379
+ }, [map, onLongPress, handleMouseDown, handleMouseUp]);
380
+
381
+ const handleDragStart = useCallback(() => {
367
382
  handleMouseUp();
368
- };
369
- }, [map, onLongPress, handleMouseDown, handleMouseUp]);
370
-
371
- const handleDragStart = () => {
372
- handleMouseUp();
373
- setIsDragging(true);
374
- wasGesture.current = true;
375
- };
376
-
377
- const handleDragEnd = () => {
378
- setIsDragging(false);
379
- };
380
-
381
- const handleCameraChanged = (event: MapCameraChangedEvent) => {
382
- const logicalCenter = offsetCenter(
383
- { latitude: event.detail.center.lat, longitude: event.detail.center.lng },
384
- event.detail.zoom,
385
- undefined,
386
- true
387
- );
388
- const payload: CameraEventPayload = {
389
- coordinate: {
390
- latitude: logicalCenter.lat,
391
- longitude: logicalCenter.lng,
383
+ isDraggingRef.current = true;
384
+ wasGesture.current = true;
385
+ }, [handleMouseUp]);
386
+
387
+ const handleDragEnd = useCallback(() => {
388
+ isDraggingRef.current = false;
389
+ }, []);
390
+
391
+ const handleCameraChanged = useCallback(
392
+ (event: MapCameraChangedEvent) => {
393
+ const logicalCenter = offsetCenter(
394
+ {
395
+ latitude: event.detail.center.lat,
396
+ longitude: event.detail.center.lng,
397
+ },
398
+ event.detail.zoom,
399
+ undefined,
400
+ true
401
+ );
402
+ const payload: CameraEventPayload = {
403
+ coordinate: {
404
+ latitude: logicalCenter.lat,
405
+ longitude: logicalCenter.lng,
406
+ },
407
+ zoom: event.detail.zoom,
408
+ gesture: isDraggingRef.current,
409
+ };
410
+ onCameraMove?.(createSyntheticEvent(payload));
392
411
  },
393
- zoom: event.detail.zoom,
394
- gesture: isDragging,
395
- };
396
- onCameraMove?.(createSyntheticEvent(payload));
397
- };
398
-
399
- const handleIdle = (event: MapEvent) => {
400
- const center = event.map.getCenter();
401
- const zoom = event.map.getZoom() ?? 0;
402
- const logicalCenter = offsetCenter(
403
- { latitude: center?.lat() ?? 0, longitude: center?.lng() ?? 0 },
404
- zoom,
405
- undefined,
406
- true
412
+ [offsetCenter, onCameraMove]
407
413
  );
408
- const payload: CameraEventPayload = {
409
- coordinate: {
410
- latitude: logicalCenter.lat,
411
- longitude: logicalCenter.lng,
414
+
415
+ const handleIdle = useCallback(
416
+ (event: MapEvent) => {
417
+ const center = event.map.getCenter();
418
+ const zoom = event.map.getZoom() ?? 0;
419
+ const logicalCenter = offsetCenter(
420
+ { latitude: center?.lat() ?? 0, longitude: center?.lng() ?? 0 },
421
+ zoom,
422
+ undefined,
423
+ true
424
+ );
425
+ const payload: CameraEventPayload = {
426
+ coordinate: {
427
+ latitude: logicalCenter.lat,
428
+ longitude: logicalCenter.lng,
429
+ },
430
+ zoom,
431
+ gesture: wasGesture.current,
432
+ };
433
+ onCameraIdle?.(createSyntheticEvent(payload));
434
+ wasGesture.current = false;
412
435
  },
413
- zoom,
414
- gesture: wasGesture.current,
415
- };
416
- onCameraIdle?.(createSyntheticEvent(payload));
417
- wasGesture.current = false;
418
- };
419
-
420
- const gestureHandling =
421
- scrollEnabled === false && zoomEnabled === false
422
- ? 'none'
423
- : scrollEnabled === false
424
- ? 'cooperative'
425
- : 'auto';
426
-
427
- const colorScheme =
428
- theme === 'dark'
429
- ? ColorScheme.DARK
430
- : theme === 'light'
431
- ? ColorScheme.LIGHT
432
- : ColorScheme.FOLLOW_SYSTEM;
433
-
434
- const defaultCenter = initialCoordinate
435
- ? { lat: initialCoordinate.latitude, lng: initialCoordinate.longitude }
436
- : undefined;
436
+ [offsetCenter, onCameraIdle]
437
+ );
437
438
 
438
- return (
439
- <MapContext.Provider
440
- value={{
441
- map,
442
- isDragging,
443
- moveCamera: panToCoordinate,
444
- onCalloutClose,
445
- closeCallouts,
446
- }}
447
- >
448
- <View ref={containerRef} style={style}>
449
- <Map
450
- id={id}
451
- mapId={mapId}
452
- defaultCenter={defaultCenter}
453
- defaultZoom={initialZoom}
454
- minZoom={minZoom}
455
- maxZoom={maxZoom}
456
- gestureHandling={gestureHandling}
457
- colorScheme={colorScheme}
458
- disableDefaultUI
459
- isFractionalZoomEnabled
460
- tilt={pitchEnabled === false ? 0 : undefined}
461
- onClick={handleClick}
462
- onDragstart={handleDragStart}
463
- onDragend={handleDragEnd}
464
- onCameraChanged={handleCameraChanged}
465
- onIdle={handleIdle}
466
- >
467
- <UserLocationMarker enabled={userLocationEnabled} />
468
- {children}
469
- </Map>
470
- </View>
471
- </MapContext.Provider>
472
- );
473
- });
439
+ const mapTypeId =
440
+ mapType === 'satellite'
441
+ ? 'satellite'
442
+ : mapType === 'terrain'
443
+ ? 'terrain'
444
+ : mapType === 'hybrid'
445
+ ? 'hybrid'
446
+ : 'roadmap';
447
+
448
+ const gestureHandling =
449
+ scrollEnabled === false && zoomEnabled === false
450
+ ? 'none'
451
+ : scrollEnabled === false
452
+ ? 'cooperative'
453
+ : 'auto';
454
+
455
+ const colorScheme =
456
+ theme === 'dark'
457
+ ? ColorScheme.DARK
458
+ : theme === 'light'
459
+ ? ColorScheme.LIGHT
460
+ : ColorScheme.FOLLOW_SYSTEM;
461
+
462
+ const defaultCenter = initialCoordinate
463
+ ? { lat: initialCoordinate.latitude, lng: initialCoordinate.longitude }
464
+ : undefined;
465
+
466
+ return (
467
+ <MapContext.Provider
468
+ value={useMemo(
469
+ () => ({
470
+ map,
471
+ isDraggingRef,
472
+ moveCamera: panToCoordinate,
473
+ onCalloutClose,
474
+ closeCallouts,
475
+ }),
476
+ [map, panToCoordinate, onCalloutClose, closeCallouts]
477
+ )}
478
+ >
479
+ <View ref={containerRef} style={style}>
480
+ <Map
481
+ id={id}
482
+ mapId={mapId}
483
+ defaultCenter={defaultCenter}
484
+ defaultZoom={initialZoom}
485
+ minZoom={minZoom}
486
+ maxZoom={maxZoom}
487
+ mapTypeId={mapTypeId}
488
+ gestureHandling={gestureHandling}
489
+ colorScheme={colorScheme}
490
+ disableDefaultUI
491
+ isFractionalZoomEnabled
492
+ tilt={pitchEnabled === false ? 0 : undefined}
493
+ onClick={handleClick}
494
+ onDragstart={handleDragStart}
495
+ onDragend={handleDragEnd}
496
+ onCameraChanged={handleCameraChanged}
497
+ onIdle={handleIdle}
498
+ >
499
+ <UserLocationMarker enabled={userLocationEnabled} />
500
+ {children}
501
+ </Map>
502
+ </View>
503
+ </MapContext.Provider>
504
+ );
505
+ })
506
+ );