@revivejs/react-google-maps 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1797 @@
1
+ // src/GoogleMapsProvider.tsx
2
+ import { useEffect, useMemo, useState } from "react";
3
+
4
+ // src/internal.tsx
5
+ import { createContext, useContext } from "react";
6
+ var GoogleMapsApiContext = createContext({
7
+ status: "idle",
8
+ error: null,
9
+ google: null,
10
+ options: null
11
+ });
12
+ var GoogleMapContext = createContext(null);
13
+ var MarkerClustererContext = createContext(null);
14
+ function useGoogleMapsApiContext() {
15
+ return useContext(GoogleMapsApiContext);
16
+ }
17
+
18
+ // src/loadGoogleMapsApi.ts
19
+ var DEFAULT_LIBRARIES = ["marker", "places", "geometry", "visualization"];
20
+ var loaderPromise = null;
21
+ var loadedOptionsKey = null;
22
+ function getDefaultGoogleMapsLibraries() {
23
+ return [...DEFAULT_LIBRARIES];
24
+ }
25
+ function loadGoogleMapsApi(options) {
26
+ if (typeof window === "undefined" || typeof document === "undefined") {
27
+ return Promise.reject(new Error("@revivejs/react-google-maps can only load the Google Maps API in a browser environment."));
28
+ }
29
+ if (!options.apiKey) {
30
+ return Promise.reject(new Error("A Google Maps API key is required to load the Google Maps JavaScript API."));
31
+ }
32
+ if (window.google?.maps) {
33
+ return Promise.resolve(window.google);
34
+ }
35
+ const normalizedOptions = normalizeLoaderOptions(options);
36
+ const nextKey = JSON.stringify(normalizedOptions);
37
+ if (loaderPromise) {
38
+ if (loadedOptionsKey && loadedOptionsKey !== nextKey) {
39
+ console.warn(
40
+ "@revivejs/react-google-maps only loads the Google Maps JavaScript API once per page. Ignoring subsequent loader options and reusing the first loaded configuration."
41
+ );
42
+ }
43
+ return loaderPromise;
44
+ }
45
+ loadedOptionsKey = nextKey;
46
+ loaderPromise = new Promise((resolve, reject) => {
47
+ const callbackName = "__revivejsReactGoogleMapsInit";
48
+ const existingScript = document.querySelector('script[data-revivejs-google-maps-loader="true"]');
49
+ if (existingScript) {
50
+ existingScript.addEventListener("load", () => {
51
+ if (window.google?.maps) {
52
+ resolve(window.google);
53
+ } else {
54
+ reject(new Error("Google Maps script loaded but the google.maps namespace is still unavailable."));
55
+ }
56
+ });
57
+ existingScript.addEventListener("error", () => reject(new Error("The Google Maps JavaScript API script failed to load.")));
58
+ return;
59
+ }
60
+ const params = new URLSearchParams();
61
+ params.set("key", normalizedOptions.apiKey);
62
+ params.set("v", normalizedOptions.version);
63
+ params.set("loading", "async");
64
+ params.set("callback", callbackName);
65
+ if (normalizedOptions.language) {
66
+ params.set("language", normalizedOptions.language);
67
+ }
68
+ if (normalizedOptions.region) {
69
+ params.set("region", normalizedOptions.region);
70
+ }
71
+ if (normalizedOptions.libraries.length) {
72
+ params.set("libraries", normalizedOptions.libraries.join(","));
73
+ }
74
+ if (normalizedOptions.mapIds.length) {
75
+ params.set("map_ids", normalizedOptions.mapIds.join(","));
76
+ }
77
+ if (normalizedOptions.authReferrerPolicy) {
78
+ params.set("auth_referrer_policy", normalizedOptions.authReferrerPolicy);
79
+ }
80
+ if (normalizedOptions.channel) {
81
+ params.set("channel", normalizedOptions.channel);
82
+ }
83
+ if (normalizedOptions.solutionChannel) {
84
+ params.set("solution_channel", normalizedOptions.solutionChannel);
85
+ }
86
+ const script = document.createElement("script");
87
+ script.async = true;
88
+ script.defer = true;
89
+ script.dataset.revivejsGoogleMapsLoader = "true";
90
+ script.src = `https://maps.googleapis.com/maps/api/js?${params.toString()}`;
91
+ if (normalizedOptions.nonce) {
92
+ script.nonce = normalizedOptions.nonce;
93
+ }
94
+ window[callbackName] = () => {
95
+ delete window[callbackName];
96
+ if (window.google?.maps) {
97
+ resolve(window.google);
98
+ } else {
99
+ reject(new Error("Google Maps callback fired but the google.maps namespace is unavailable."));
100
+ }
101
+ };
102
+ script.onerror = () => {
103
+ loaderPromise = null;
104
+ loadedOptionsKey = null;
105
+ delete window[callbackName];
106
+ reject(new Error("The Google Maps JavaScript API script failed to load."));
107
+ };
108
+ document.head.appendChild(script);
109
+ });
110
+ return loaderPromise;
111
+ }
112
+ function normalizeLoaderOptions(options) {
113
+ return {
114
+ ...options,
115
+ version: options.version || "weekly",
116
+ libraries: Array.from(/* @__PURE__ */ new Set([...options.libraries || [], ...DEFAULT_LIBRARIES])).sort(),
117
+ mapIds: Array.from(new Set(options.mapIds || [])).sort()
118
+ };
119
+ }
120
+
121
+ // src/GoogleMapsProvider.tsx
122
+ import { jsx } from "react/jsx-runtime";
123
+ function GoogleMapsProvider({ children, ...options }) {
124
+ const [status, setStatus] = useState("idle");
125
+ const [error, setError] = useState(null);
126
+ const [googleApi, setGoogleApi] = useState(
127
+ () => typeof window !== "undefined" && window.google?.maps ? window.google : null
128
+ );
129
+ const serializedOptions = JSON.stringify({
130
+ ...options,
131
+ libraries: options.libraries || [],
132
+ mapIds: options.mapIds || []
133
+ });
134
+ useEffect(() => {
135
+ let cancelled = false;
136
+ if (!options.apiKey) {
137
+ setStatus("idle");
138
+ setError(null);
139
+ setGoogleApi(null);
140
+ return;
141
+ }
142
+ setStatus((current) => current === "ready" ? current : "loading");
143
+ setError(null);
144
+ loadGoogleMapsApi(options).then((googleNamespace) => {
145
+ if (cancelled) {
146
+ return;
147
+ }
148
+ setGoogleApi(googleNamespace);
149
+ setStatus("ready");
150
+ }).catch((nextError) => {
151
+ if (cancelled) {
152
+ return;
153
+ }
154
+ setError(nextError instanceof Error ? nextError : new Error(String(nextError)));
155
+ setStatus("error");
156
+ });
157
+ return () => {
158
+ cancelled = true;
159
+ };
160
+ }, [serializedOptions]);
161
+ const value = useMemo(
162
+ () => ({
163
+ status,
164
+ error,
165
+ google: googleApi,
166
+ options
167
+ }),
168
+ [status, error, googleApi, serializedOptions]
169
+ );
170
+ return /* @__PURE__ */ jsx(GoogleMapsApiContext.Provider, { value, children });
171
+ }
172
+
173
+ // src/clusterRenderer.ts
174
+ function createClusterRenderer(options = {}) {
175
+ return {
176
+ render(cluster, stats, map) {
177
+ const count = cluster.count;
178
+ const position = cluster.position;
179
+ const contextBase = {
180
+ cluster,
181
+ stats,
182
+ map,
183
+ count,
184
+ position,
185
+ color: "",
186
+ isAdvancedMarkerAvailable: false
187
+ };
188
+ const color = typeof options.color === "function" ? options.color(contextBase) : options.color || getDefaultClusterColor(count, stats);
189
+ const isAdvancedMarkerAvailable = options.useAdvancedMarker !== false && !!google.maps.marker?.AdvancedMarkerElement && !!map.get("mapId");
190
+ const context = {
191
+ ...contextBase,
192
+ color,
193
+ isAdvancedMarkerAvailable
194
+ };
195
+ const title = typeof options.title === "function" ? options.title(context) : options.title || `Cluster with ${count} markers`;
196
+ const zIndex = (options.zIndexBase || 1e3) + count;
197
+ if (isAdvancedMarkerAvailable) {
198
+ return new google.maps.marker.AdvancedMarkerElement({
199
+ position,
200
+ title,
201
+ zIndex,
202
+ content: buildAdvancedClusterContent(context, options)
203
+ });
204
+ }
205
+ return new google.maps.Marker({
206
+ position,
207
+ title,
208
+ zIndex,
209
+ label: {
210
+ text: String(count),
211
+ color: options.fallbackTextColor || "#ffffff",
212
+ fontSize: "12px",
213
+ fontWeight: "700"
214
+ },
215
+ icon: {
216
+ url: buildFallbackClusterSvg(
217
+ color,
218
+ options.fallbackBorderColor || "rgba(255,255,255,0.92)"
219
+ ),
220
+ scaledSize: new google.maps.Size(46, 46)
221
+ }
222
+ });
223
+ }
224
+ };
225
+ }
226
+ function buildAdvancedClusterContent(context, options) {
227
+ const customContent = options.render?.(context);
228
+ if (customContent instanceof HTMLElement) {
229
+ return customContent;
230
+ }
231
+ const element = document.createElement("div");
232
+ element.className = options.className || "revivejs-cluster-badge";
233
+ element.style.display = "grid";
234
+ element.style.gap = "2px";
235
+ element.style.minWidth = "52px";
236
+ element.style.padding = "10px 12px";
237
+ element.style.borderRadius = "999px";
238
+ element.style.background = context.color;
239
+ element.style.color = "#ffffff";
240
+ element.style.boxShadow = "0 12px 24px rgba(16, 32, 51, 0.18)";
241
+ element.style.border = "2px solid rgba(255,255,255,0.88)";
242
+ element.style.textAlign = "center";
243
+ element.style.fontFamily = "Avenir Next, Segoe UI, sans-serif";
244
+ const countNode = document.createElement("strong");
245
+ countNode.textContent = String(context.count);
246
+ countNode.style.fontSize = "14px";
247
+ countNode.style.lineHeight = "1";
248
+ const labelNode = document.createElement("span");
249
+ labelNode.textContent = typeof customContent === "string" ? customContent : "markers";
250
+ labelNode.style.fontSize = "10px";
251
+ labelNode.style.opacity = "0.92";
252
+ labelNode.style.lineHeight = "1";
253
+ element.append(countNode, labelNode);
254
+ return element;
255
+ }
256
+ function getDefaultClusterColor(count, stats) {
257
+ return count > Math.max(10, stats.clusters.markers.mean) ? "#d94b2b" : "#0d5c9e";
258
+ }
259
+ function buildFallbackClusterSvg(fill, stroke) {
260
+ const svg = `
261
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
262
+ <circle cx="32" cy="32" r="28" fill="${fill}" stroke="${stroke}" stroke-width="4" />
263
+ </svg>
264
+ `;
265
+ return `data:image/svg+xml;base64,${window.btoa(svg)}`;
266
+ }
267
+
268
+ // src/GoogleMap.tsx
269
+ import {
270
+ forwardRef,
271
+ useEffect as useEffect2,
272
+ useImperativeHandle,
273
+ useMemo as useMemo2,
274
+ useRef as useRef2,
275
+ useState as useState2
276
+ } from "react";
277
+
278
+ // src/hooks.ts
279
+ import { useContext as useContext2, useRef } from "react";
280
+ function useGoogleMapsApi() {
281
+ const context = useGoogleMapsApiContext();
282
+ return {
283
+ ...context,
284
+ isLoaded: context.status === "ready" && !!context.google
285
+ };
286
+ }
287
+ function useGoogleMap() {
288
+ return useContext2(GoogleMapContext);
289
+ }
290
+ function useMapGeocoder() {
291
+ const { google: google2, isLoaded } = useGoogleMapsApi();
292
+ const geocoderRef = useRef(null);
293
+ if (isLoaded && google2 && !geocoderRef.current) {
294
+ geocoderRef.current = new google2.maps.Geocoder();
295
+ }
296
+ return geocoderRef.current;
297
+ }
298
+ function useDirectionsService() {
299
+ const { google: google2, isLoaded } = useGoogleMapsApi();
300
+ const directionsServiceRef = useRef(null);
301
+ if (isLoaded && google2 && !directionsServiceRef.current) {
302
+ directionsServiceRef.current = new google2.maps.DirectionsService();
303
+ }
304
+ return directionsServiceRef.current;
305
+ }
306
+
307
+ // src/utils.ts
308
+ function addListener(target, eventName, handler) {
309
+ if (!target || !handler) {
310
+ return null;
311
+ }
312
+ return google.maps.event.addListener(target, eventName, (...args) => {
313
+ handler(...args);
314
+ });
315
+ }
316
+ function composeMapOptions(options, extra) {
317
+ return {
318
+ ...options,
319
+ ...removeUndefined(extra)
320
+ };
321
+ }
322
+ function removeUndefined(input) {
323
+ return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
324
+ }
325
+ function toLatLng(value) {
326
+ if (!value) {
327
+ return null;
328
+ }
329
+ if (value instanceof google.maps.LatLng) {
330
+ return value;
331
+ }
332
+ return new google.maps.LatLng(value);
333
+ }
334
+ function toMVCArrayPath(path) {
335
+ return path.map((point) => point instanceof google.maps.LatLng ? point : new google.maps.LatLng(point));
336
+ }
337
+ function shallowBoundsEqual(left, right) {
338
+ return left?.east === right?.east && left?.west === right?.west && left?.north === right?.north && left?.south === right?.south;
339
+ }
340
+
341
+ // src/GoogleMap.tsx
342
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
343
+ var DEFAULT_CENTER = { lat: 37.421995, lng: -122.084092 };
344
+ var DEFAULT_ZOOM = 13;
345
+ var GoogleMap = forwardRef(function GoogleMap2({
346
+ children,
347
+ center = DEFAULT_CENTER,
348
+ zoom = DEFAULT_ZOOM,
349
+ mapId,
350
+ options,
351
+ width = "100%",
352
+ height = 460,
353
+ loadingFallback,
354
+ errorFallback,
355
+ onMapLoad,
356
+ onMapUnmount,
357
+ onClick,
358
+ onDblClick,
359
+ onDrag,
360
+ onDragStart,
361
+ onDragEnd,
362
+ onIdle,
363
+ onBoundsChanged,
364
+ onCenterChanged,
365
+ onHeadingChanged,
366
+ onMapTypeIdChanged,
367
+ onMouseMove,
368
+ onMouseOut,
369
+ onMouseOver,
370
+ onProjectionChanged,
371
+ onRightClick,
372
+ onTilesLoaded,
373
+ onTiltChanged,
374
+ onZoomChanged,
375
+ className,
376
+ style,
377
+ ...divProps
378
+ }, ref) {
379
+ const { isLoaded, status, error, google: google2 } = useGoogleMapsApi();
380
+ const containerRef = useRef2(null);
381
+ const [map, setMap] = useState2(null);
382
+ const initialMapIdRef = useRef2(mapId);
383
+ useImperativeHandle(
384
+ ref,
385
+ () => ({
386
+ map,
387
+ fitBounds(bounds) {
388
+ map?.fitBounds(bounds);
389
+ },
390
+ panBy(x, y) {
391
+ map?.panBy(x, y);
392
+ },
393
+ panTo(position) {
394
+ map?.panTo(position);
395
+ },
396
+ panToBounds(bounds, padding) {
397
+ map?.panToBounds(bounds, padding);
398
+ },
399
+ setZoom(nextZoom) {
400
+ map?.setZoom(nextZoom);
401
+ },
402
+ setCenter(position) {
403
+ map?.setCenter(position);
404
+ },
405
+ setOptions(nextOptions) {
406
+ map?.setOptions(nextOptions);
407
+ },
408
+ getBounds() {
409
+ return map?.getBounds() || null;
410
+ },
411
+ getCenter() {
412
+ return map?.getCenter();
413
+ },
414
+ getClickableIcons() {
415
+ return map?.getClickableIcons();
416
+ },
417
+ getHeading() {
418
+ return map?.getHeading();
419
+ },
420
+ getMapTypeId() {
421
+ return map?.getMapTypeId();
422
+ },
423
+ getProjection() {
424
+ return map?.getProjection() || null;
425
+ },
426
+ getStreetView() {
427
+ return map?.getStreetView() || null;
428
+ },
429
+ getTilt() {
430
+ return map?.getTilt();
431
+ },
432
+ getZoom() {
433
+ return map?.getZoom();
434
+ },
435
+ controls() {
436
+ return map?.controls || null;
437
+ },
438
+ data() {
439
+ return map?.data || null;
440
+ },
441
+ mapTypes() {
442
+ return map?.mapTypes || null;
443
+ },
444
+ overlayMapTypes() {
445
+ return map?.overlayMapTypes || null;
446
+ }
447
+ }),
448
+ [map]
449
+ );
450
+ useEffect2(() => {
451
+ if (!isLoaded || !google2 || !containerRef.current || map) {
452
+ return;
453
+ }
454
+ const nextMap = new google2.maps.Map(
455
+ containerRef.current,
456
+ composeMapOptions(options, {
457
+ center,
458
+ zoom,
459
+ mapId: initialMapIdRef.current
460
+ })
461
+ );
462
+ setMap(nextMap);
463
+ onMapLoad?.(nextMap);
464
+ return () => {
465
+ onMapUnmount?.(nextMap);
466
+ setMap(null);
467
+ };
468
+ }, [isLoaded, google2, map]);
469
+ useEffect2(() => {
470
+ if (!map) {
471
+ return;
472
+ }
473
+ map.setOptions(
474
+ composeMapOptions(options, {
475
+ center,
476
+ zoom
477
+ })
478
+ );
479
+ }, [map, options, center, zoom]);
480
+ useEffect2(() => {
481
+ if (!map || !center) {
482
+ return;
483
+ }
484
+ const nextCenter = toLatLng(center);
485
+ if (nextCenter) {
486
+ map.setCenter(nextCenter);
487
+ }
488
+ }, [map, center]);
489
+ useEffect2(() => {
490
+ if (!map || zoom === void 0) {
491
+ return;
492
+ }
493
+ if (map.getZoom() !== zoom) {
494
+ map.setZoom(zoom);
495
+ }
496
+ }, [map, zoom]);
497
+ useEffect2(() => {
498
+ if (!map) {
499
+ return;
500
+ }
501
+ const listeners = [
502
+ addListener(map, "click", onClick),
503
+ addListener(map, "dblclick", onDblClick),
504
+ addListener(map, "drag", onDrag),
505
+ addListener(map, "dragstart", onDragStart),
506
+ addListener(map, "dragend", onDragEnd),
507
+ addListener(map, "idle", onIdle),
508
+ addListener(map, "bounds_changed", onBoundsChanged),
509
+ addListener(map, "center_changed", onCenterChanged),
510
+ addListener(map, "heading_changed", onHeadingChanged),
511
+ addListener(map, "maptypeid_changed", onMapTypeIdChanged),
512
+ addListener(map, "mousemove", onMouseMove),
513
+ addListener(map, "mouseout", onMouseOut),
514
+ addListener(map, "mouseover", onMouseOver),
515
+ addListener(map, "projection_changed", onProjectionChanged),
516
+ addListener(map, "rightclick", onRightClick),
517
+ addListener(map, "tilesloaded", onTilesLoaded),
518
+ addListener(map, "tilt_changed", onTiltChanged),
519
+ addListener(map, "zoom_changed", onZoomChanged)
520
+ ].filter(Boolean);
521
+ return () => {
522
+ listeners.forEach((listener) => listener?.remove());
523
+ };
524
+ }, [
525
+ map,
526
+ onClick,
527
+ onDblClick,
528
+ onDrag,
529
+ onDragStart,
530
+ onDragEnd,
531
+ onIdle,
532
+ onBoundsChanged,
533
+ onCenterChanged,
534
+ onHeadingChanged,
535
+ onMapTypeIdChanged,
536
+ onMouseMove,
537
+ onMouseOut,
538
+ onMouseOver,
539
+ onProjectionChanged,
540
+ onRightClick,
541
+ onTilesLoaded,
542
+ onTiltChanged,
543
+ onZoomChanged
544
+ ]);
545
+ useEffect2(() => {
546
+ if (!map || !google2 || !containerRef.current || typeof ResizeObserver === "undefined") {
547
+ return;
548
+ }
549
+ const observer = new ResizeObserver(() => {
550
+ const currentCenter = map.getCenter();
551
+ google2.maps.event.trigger(map, "resize");
552
+ if (currentCenter) {
553
+ map.setCenter(currentCenter);
554
+ }
555
+ });
556
+ observer.observe(containerRef.current);
557
+ return () => {
558
+ observer.disconnect();
559
+ };
560
+ }, [map, google2]);
561
+ const mergedStyle = useMemo2(
562
+ () => ({
563
+ width,
564
+ height,
565
+ minHeight: typeof height === "number" ? `${height}px` : void 0,
566
+ position: "relative",
567
+ overflow: "hidden",
568
+ ...style
569
+ }),
570
+ [width, height, style]
571
+ );
572
+ return /* @__PURE__ */ jsxs("div", { ...divProps, className, style: mergedStyle, ref: containerRef, children: [
573
+ status === "error" ? errorFallback || /* @__PURE__ */ jsx2(MapStatus, { message: error?.message || "The Google Maps API failed to load.", tone: "error" }) : null,
574
+ !isLoaded && status !== "error" ? loadingFallback || /* @__PURE__ */ jsx2(MapStatus, { message: "Loading Google Maps JavaScript API\u2026", tone: "loading" }) : null,
575
+ map ? /* @__PURE__ */ jsx2(GoogleMapContext.Provider, { value: map, children }) : null
576
+ ] });
577
+ });
578
+ function MapStatus({ message, tone }) {
579
+ return /* @__PURE__ */ jsx2(
580
+ "div",
581
+ {
582
+ style: {
583
+ position: "absolute",
584
+ inset: 0,
585
+ display: "grid",
586
+ placeItems: "center",
587
+ padding: "1rem",
588
+ background: tone === "error" ? "rgba(255, 245, 245, 0.9)" : "rgba(244, 249, 255, 0.9)",
589
+ color: tone === "error" ? "#8c2b2b" : "#24415f",
590
+ fontSize: "0.95rem",
591
+ zIndex: 0
592
+ },
593
+ children: /* @__PURE__ */ jsx2("div", { children: message })
594
+ }
595
+ );
596
+ }
597
+
598
+ // src/markers.tsx
599
+ import { MarkerClusterer } from "@googlemaps/markerclusterer";
600
+ import {
601
+ useContext as useContext3,
602
+ forwardRef as forwardRef2,
603
+ useEffect as useEffect3,
604
+ useImperativeHandle as useImperativeHandle2,
605
+ useMemo as useMemo3,
606
+ useRef as useRef3,
607
+ useState as useState3
608
+ } from "react";
609
+ import { createPortal } from "react-dom";
610
+ import { jsx as jsx3 } from "react/jsx-runtime";
611
+ var MapMarker = forwardRef2(function MapMarker2({
612
+ position,
613
+ title,
614
+ label,
615
+ clickable,
616
+ draggable,
617
+ icon,
618
+ visible,
619
+ zIndex,
620
+ animation,
621
+ options,
622
+ onLoad,
623
+ onUnmount,
624
+ onClick,
625
+ onDblClick,
626
+ onDrag,
627
+ onDragEnd,
628
+ onDragStart,
629
+ onMouseDown,
630
+ onMouseOut,
631
+ onMouseOver,
632
+ onMouseUp,
633
+ onRightClick
634
+ }, ref) {
635
+ const map = useGoogleMap();
636
+ const clustererContext = useContext3(MarkerClustererContext);
637
+ const [marker, setMarker] = useState3(null);
638
+ useImperativeHandle2(
639
+ ref,
640
+ () => ({
641
+ marker,
642
+ getAnimation() {
643
+ return marker?.getAnimation();
644
+ },
645
+ getClickable() {
646
+ return marker?.getClickable();
647
+ },
648
+ getDraggable() {
649
+ return marker?.getDraggable();
650
+ },
651
+ getIcon() {
652
+ return marker?.getIcon();
653
+ },
654
+ getLabel() {
655
+ return marker?.getLabel();
656
+ },
657
+ getPosition() {
658
+ return marker?.getPosition();
659
+ },
660
+ getTitle() {
661
+ return marker?.getTitle();
662
+ },
663
+ getVisible() {
664
+ return marker?.getVisible();
665
+ },
666
+ getZIndex() {
667
+ return marker?.getZIndex();
668
+ },
669
+ setAnimation(nextAnimation) {
670
+ marker?.setAnimation(nextAnimation);
671
+ },
672
+ setOptions(nextOptions) {
673
+ marker?.setOptions(nextOptions);
674
+ },
675
+ setPosition(nextPosition) {
676
+ marker?.setPosition(nextPosition);
677
+ },
678
+ setTitle(nextTitle) {
679
+ marker?.setTitle(nextTitle);
680
+ },
681
+ setVisible(nextVisible) {
682
+ marker?.setVisible(nextVisible);
683
+ },
684
+ setZIndex(nextZIndex) {
685
+ marker?.setZIndex(nextZIndex);
686
+ }
687
+ }),
688
+ [marker]
689
+ );
690
+ useEffect3(() => {
691
+ if (!map || marker) {
692
+ return;
693
+ }
694
+ const instance = new google.maps.Marker();
695
+ setMarker(instance);
696
+ onLoad?.(instance);
697
+ return () => {
698
+ onUnmount?.(instance);
699
+ clustererContext?.unregisterMarker(instance);
700
+ instance.setMap(null);
701
+ };
702
+ }, [map, marker]);
703
+ useEffect3(() => {
704
+ if (!marker || !map) {
705
+ return;
706
+ }
707
+ marker.setOptions({
708
+ ...options,
709
+ ...removeUndefined({
710
+ position,
711
+ title,
712
+ label,
713
+ clickable,
714
+ draggable,
715
+ icon,
716
+ visible,
717
+ zIndex,
718
+ animation
719
+ })
720
+ });
721
+ if (clustererContext) {
722
+ marker.setMap(null);
723
+ clustererContext.registerMarker(marker);
724
+ } else {
725
+ marker.setMap(map);
726
+ }
727
+ }, [marker, map, clustererContext, position, title, label, clickable, draggable, icon, visible, zIndex, animation, options]);
728
+ useEffect3(() => {
729
+ if (!marker) {
730
+ return;
731
+ }
732
+ const listeners = [
733
+ addListener(marker, "click", onClick),
734
+ addListener(marker, "dblclick", onDblClick),
735
+ addListener(marker, "drag", onDrag),
736
+ addListener(marker, "dragend", onDragEnd),
737
+ addListener(marker, "dragstart", onDragStart),
738
+ addListener(marker, "mousedown", onMouseDown),
739
+ addListener(marker, "mouseout", onMouseOut),
740
+ addListener(marker, "mouseover", onMouseOver),
741
+ addListener(marker, "mouseup", onMouseUp),
742
+ addListener(marker, "rightclick", onRightClick)
743
+ ].filter(Boolean);
744
+ return () => {
745
+ listeners.forEach((listener) => listener?.remove());
746
+ };
747
+ }, [marker, onClick, onDblClick, onDrag, onDragEnd, onDragStart, onMouseDown, onMouseOut, onMouseOver, onMouseUp, onRightClick]);
748
+ return null;
749
+ });
750
+ var MapAdvancedMarker = forwardRef2(function MapAdvancedMarker2({
751
+ position,
752
+ title,
753
+ zIndex,
754
+ gmpClickable,
755
+ gmpDraggable,
756
+ options,
757
+ collisionBehavior,
758
+ children,
759
+ onLoad,
760
+ onUnmount,
761
+ onClick,
762
+ onDragStart,
763
+ onDrag,
764
+ onDragEnd
765
+ }, ref) {
766
+ const map = useGoogleMap();
767
+ const { isLoaded } = useGoogleMapsApi();
768
+ const clustererContext = useContext3(MarkerClustererContext);
769
+ const [marker, setMarker] = useState3(null);
770
+ const [contentElement] = useState3(() => typeof document !== "undefined" ? document.createElement("div") : null);
771
+ useImperativeHandle2(
772
+ ref,
773
+ () => ({
774
+ marker,
775
+ content: contentElement,
776
+ setMap(nextMap) {
777
+ if (marker) {
778
+ marker.map = nextMap;
779
+ }
780
+ },
781
+ setPosition(nextPosition) {
782
+ if (marker) {
783
+ marker.position = toLatLng(nextPosition) || nextPosition;
784
+ }
785
+ },
786
+ setZIndex(nextZIndex) {
787
+ if (marker) {
788
+ marker.zIndex = nextZIndex;
789
+ }
790
+ }
791
+ }),
792
+ [marker, contentElement]
793
+ );
794
+ useEffect3(() => {
795
+ if (!map || !isLoaded || marker) {
796
+ return;
797
+ }
798
+ if (!google.maps.marker?.AdvancedMarkerElement) {
799
+ throw new Error(
800
+ "AdvancedMarkerElement is unavailable. Make sure the marker library is enabled and the map uses a valid mapId."
801
+ );
802
+ }
803
+ const instance = new google.maps.marker.AdvancedMarkerElement({
804
+ map: clustererContext ? void 0 : map,
805
+ content: children && contentElement ? contentElement : options?.content,
806
+ ...options
807
+ });
808
+ setMarker(instance);
809
+ onLoad?.(instance);
810
+ return () => {
811
+ onUnmount?.(instance);
812
+ clustererContext?.unregisterMarker(instance);
813
+ instance.map = null;
814
+ };
815
+ }, [map, isLoaded, marker, clustererContext, children, contentElement, options]);
816
+ useEffect3(() => {
817
+ if (!marker || !map) {
818
+ return;
819
+ }
820
+ marker.position = toLatLng(position) || position;
821
+ if (title !== void 0) {
822
+ marker.title = title;
823
+ }
824
+ marker.zIndex = zIndex;
825
+ marker.gmpClickable = gmpClickable;
826
+ marker.gmpDraggable = gmpDraggable;
827
+ if (collisionBehavior !== void 0) {
828
+ marker.collisionBehavior = collisionBehavior;
829
+ }
830
+ if (children && contentElement) {
831
+ marker.content = contentElement;
832
+ }
833
+ if (clustererContext) {
834
+ marker.map = null;
835
+ clustererContext.registerMarker(marker);
836
+ } else {
837
+ marker.map = map;
838
+ }
839
+ }, [marker, map, clustererContext, position, title, zIndex, gmpClickable, gmpDraggable, collisionBehavior, children, contentElement]);
840
+ useEffect3(() => {
841
+ if (!marker) {
842
+ return;
843
+ }
844
+ const listeners = [
845
+ addListener(marker, "click", onClick),
846
+ addListener(marker, "dragstart", onDragStart),
847
+ addListener(marker, "drag", onDrag),
848
+ addListener(marker, "dragend", onDragEnd)
849
+ ].filter(Boolean);
850
+ return () => {
851
+ listeners.forEach((listener) => listener?.remove());
852
+ };
853
+ }, [marker, onClick, onDragStart, onDrag, onDragEnd]);
854
+ return children && contentElement ? createPortal(children, contentElement) : null;
855
+ });
856
+ var MapInfoWindow = forwardRef2(function MapInfoWindow2({
857
+ anchor,
858
+ open = true,
859
+ position,
860
+ zIndex,
861
+ options,
862
+ children,
863
+ onLoad,
864
+ onUnmount,
865
+ onCloseClick,
866
+ onDomReady,
867
+ onContentChanged,
868
+ onPositionChanged,
869
+ onZIndexChanged
870
+ }, ref) {
871
+ const map = useGoogleMap();
872
+ const [infoWindow, setInfoWindow] = useState3(null);
873
+ const [contentElement] = useState3(() => typeof document !== "undefined" ? document.createElement("div") : null);
874
+ useImperativeHandle2(
875
+ ref,
876
+ () => ({
877
+ infoWindow,
878
+ open(nextAnchor) {
879
+ if (!infoWindow) {
880
+ return;
881
+ }
882
+ infoWindow.open({
883
+ map,
884
+ anchor: nextAnchor || anchor || void 0
885
+ });
886
+ },
887
+ close() {
888
+ infoWindow?.close();
889
+ },
890
+ getContent() {
891
+ return infoWindow?.getContent();
892
+ },
893
+ getPosition() {
894
+ return infoWindow?.getPosition() || null;
895
+ },
896
+ getZIndex() {
897
+ return infoWindow?.getZIndex();
898
+ },
899
+ setContent(content) {
900
+ infoWindow?.setContent(content);
901
+ },
902
+ setPosition(nextPosition) {
903
+ infoWindow?.setPosition(nextPosition);
904
+ },
905
+ setZIndex(nextZIndex) {
906
+ infoWindow?.setZIndex(nextZIndex);
907
+ }
908
+ }),
909
+ [infoWindow, map, anchor]
910
+ );
911
+ useEffect3(() => {
912
+ if (!map || infoWindow) {
913
+ return;
914
+ }
915
+ const instance = new google.maps.InfoWindow({
916
+ ...options,
917
+ content: contentElement || options?.content,
918
+ position,
919
+ zIndex
920
+ });
921
+ setInfoWindow(instance);
922
+ onLoad?.(instance);
923
+ return () => {
924
+ onUnmount?.(instance);
925
+ instance.close();
926
+ };
927
+ }, [map, infoWindow, options, contentElement, position, zIndex]);
928
+ useEffect3(() => {
929
+ if (!infoWindow) {
930
+ return;
931
+ }
932
+ infoWindow.setOptions({
933
+ ...options,
934
+ content: children && contentElement ? contentElement : options?.content,
935
+ position,
936
+ zIndex
937
+ });
938
+ }, [infoWindow, options, position, zIndex, children, contentElement]);
939
+ useEffect3(() => {
940
+ if (!infoWindow) {
941
+ return;
942
+ }
943
+ if (!open) {
944
+ infoWindow.close();
945
+ return;
946
+ }
947
+ infoWindow.open({
948
+ map,
949
+ anchor
950
+ });
951
+ }, [infoWindow, map, anchor, open, position]);
952
+ useEffect3(() => {
953
+ if (!infoWindow) {
954
+ return;
955
+ }
956
+ const listeners = [
957
+ addListener(infoWindow, "closeclick", onCloseClick),
958
+ addListener(infoWindow, "domready", onDomReady),
959
+ addListener(infoWindow, "content_changed", onContentChanged),
960
+ addListener(infoWindow, "position_changed", onPositionChanged),
961
+ addListener(infoWindow, "zindex_changed", onZIndexChanged)
962
+ ].filter(Boolean);
963
+ return () => {
964
+ listeners.forEach((listener) => listener?.remove());
965
+ };
966
+ }, [infoWindow, onCloseClick, onDomReady, onContentChanged, onPositionChanged, onZIndexChanged]);
967
+ return children && contentElement ? createPortal(children, contentElement) : null;
968
+ });
969
+ var MapMarkerClusterer = forwardRef2(function MapMarkerClusterer2({
970
+ children,
971
+ algorithm,
972
+ renderer,
973
+ onLoad,
974
+ onUnmount,
975
+ onClusterClick
976
+ }, ref) {
977
+ const map = useGoogleMap();
978
+ const [clusterer, setClusterer] = useState3(null);
979
+ const pendingMarkersRef = useRef3(/* @__PURE__ */ new Set());
980
+ useImperativeHandle2(
981
+ ref,
982
+ () => ({
983
+ clusterer,
984
+ addMarker(marker, noDraw) {
985
+ clusterer?.addMarker(marker, noDraw);
986
+ },
987
+ addMarkers(markers, noDraw) {
988
+ clusterer?.addMarkers(markers, noDraw);
989
+ },
990
+ removeMarker(marker, noDraw) {
991
+ return clusterer?.removeMarker(marker, noDraw) ?? false;
992
+ },
993
+ clearMarkers(noDraw) {
994
+ clusterer?.clearMarkers(noDraw);
995
+ },
996
+ render() {
997
+ clusterer?.render();
998
+ }
999
+ }),
1000
+ [clusterer]
1001
+ );
1002
+ useEffect3(() => {
1003
+ if (!map || clusterer) {
1004
+ return;
1005
+ }
1006
+ const instance = new MarkerClusterer({
1007
+ map,
1008
+ markers: Array.from(pendingMarkersRef.current),
1009
+ algorithm,
1010
+ renderer,
1011
+ onClusterClick
1012
+ });
1013
+ setClusterer(instance);
1014
+ onLoad?.(instance);
1015
+ return () => {
1016
+ onUnmount?.(instance);
1017
+ instance.clearMarkers();
1018
+ instance.setMap?.(null);
1019
+ };
1020
+ }, [map, clusterer, algorithm, renderer, onClusterClick]);
1021
+ const contextValue = useMemo3(
1022
+ () => ({
1023
+ clusterer,
1024
+ registerMarker(marker) {
1025
+ if (clusterer) {
1026
+ clusterer.addMarker(marker, true);
1027
+ clusterer.render();
1028
+ } else {
1029
+ pendingMarkersRef.current.add(marker);
1030
+ }
1031
+ },
1032
+ unregisterMarker(marker) {
1033
+ pendingMarkersRef.current.delete(marker);
1034
+ if (clusterer) {
1035
+ clusterer.removeMarker(marker, true);
1036
+ clusterer.render();
1037
+ }
1038
+ }
1039
+ }),
1040
+ [clusterer]
1041
+ );
1042
+ return /* @__PURE__ */ jsx3(MarkerClustererContext.Provider, { value: contextValue, children });
1043
+ });
1044
+
1045
+ // src/shapes.tsx
1046
+ import { createPortal as createPortal2 } from "react-dom";
1047
+ import { forwardRef as forwardRef3, useEffect as useEffect4, useImperativeHandle as useImperativeHandle3, useState as useState4 } from "react";
1048
+ var MapPolyline = forwardRef3(function MapPolyline2({
1049
+ path,
1050
+ options,
1051
+ onLoad,
1052
+ onUnmount,
1053
+ onClick,
1054
+ onDblClick,
1055
+ onMouseDown,
1056
+ onMouseMove,
1057
+ onMouseOut,
1058
+ onMouseOver,
1059
+ onMouseUp,
1060
+ onRightClick,
1061
+ onDrag,
1062
+ onDragEnd,
1063
+ onDragStart
1064
+ }, ref) {
1065
+ const map = useGoogleMap();
1066
+ const [polyline, setPolyline] = useState4(null);
1067
+ useImperativeHandle3(
1068
+ ref,
1069
+ () => ({
1070
+ polyline,
1071
+ getPath() {
1072
+ return polyline?.getPath() || null;
1073
+ },
1074
+ getVisible() {
1075
+ return polyline?.getVisible();
1076
+ },
1077
+ getDraggable() {
1078
+ return polyline?.getDraggable();
1079
+ },
1080
+ getEditable() {
1081
+ return polyline?.getEditable();
1082
+ },
1083
+ setPath(nextPath) {
1084
+ polyline?.setPath(toMVCArrayPath(nextPath));
1085
+ },
1086
+ setOptions(nextOptions) {
1087
+ polyline?.setOptions(nextOptions);
1088
+ }
1089
+ }),
1090
+ [polyline]
1091
+ );
1092
+ useEffect4(() => {
1093
+ if (!map || polyline) {
1094
+ return;
1095
+ }
1096
+ const instance = new google.maps.Polyline({ map });
1097
+ setPolyline(instance);
1098
+ onLoad?.(instance);
1099
+ return () => {
1100
+ onUnmount?.(instance);
1101
+ instance.setMap(null);
1102
+ };
1103
+ }, [map, polyline]);
1104
+ useEffect4(() => {
1105
+ if (!polyline) {
1106
+ return;
1107
+ }
1108
+ polyline.setOptions({
1109
+ ...options,
1110
+ path: toMVCArrayPath(path),
1111
+ map
1112
+ });
1113
+ }, [polyline, map, path, options]);
1114
+ useShapeEvents(polyline, { onClick, onDblClick, onMouseDown, onMouseMove, onMouseOut, onMouseOver, onMouseUp, onRightClick, onDrag, onDragEnd, onDragStart });
1115
+ return null;
1116
+ });
1117
+ var MapPolygon = forwardRef3(function MapPolygon2({
1118
+ paths,
1119
+ options,
1120
+ onLoad,
1121
+ onUnmount,
1122
+ onClick,
1123
+ onDblClick,
1124
+ onMouseDown,
1125
+ onMouseMove,
1126
+ onMouseOut,
1127
+ onMouseOver,
1128
+ onMouseUp,
1129
+ onRightClick,
1130
+ onDrag,
1131
+ onDragEnd,
1132
+ onDragStart
1133
+ }, ref) {
1134
+ const map = useGoogleMap();
1135
+ const [polygon, setPolygon] = useState4(null);
1136
+ useImperativeHandle3(
1137
+ ref,
1138
+ () => ({
1139
+ polygon,
1140
+ getPath() {
1141
+ return polygon?.getPath() || null;
1142
+ },
1143
+ getPaths() {
1144
+ return polygon?.getPaths() || null;
1145
+ },
1146
+ getVisible() {
1147
+ return polygon?.getVisible();
1148
+ },
1149
+ getDraggable() {
1150
+ return polygon?.getDraggable();
1151
+ },
1152
+ getEditable() {
1153
+ return polygon?.getEditable();
1154
+ },
1155
+ setPaths(nextPaths) {
1156
+ const value = Array.isArray(nextPaths[0]) ? nextPaths.map((path) => toMVCArrayPath(path)) : toMVCArrayPath(nextPaths);
1157
+ polygon?.setPaths(value);
1158
+ },
1159
+ setOptions(nextOptions) {
1160
+ polygon?.setOptions(nextOptions);
1161
+ }
1162
+ }),
1163
+ [polygon]
1164
+ );
1165
+ useEffect4(() => {
1166
+ if (!map || polygon) {
1167
+ return;
1168
+ }
1169
+ const instance = new google.maps.Polygon({ map });
1170
+ setPolygon(instance);
1171
+ onLoad?.(instance);
1172
+ return () => {
1173
+ onUnmount?.(instance);
1174
+ instance.setMap(null);
1175
+ };
1176
+ }, [map, polygon]);
1177
+ useEffect4(() => {
1178
+ if (!polygon) {
1179
+ return;
1180
+ }
1181
+ const nextPaths = Array.isArray(paths[0]) ? paths.map((path) => toMVCArrayPath(path)) : toMVCArrayPath(paths);
1182
+ polygon.setOptions({
1183
+ ...options,
1184
+ paths: nextPaths,
1185
+ map
1186
+ });
1187
+ }, [polygon, map, paths, options]);
1188
+ useShapeEvents(polygon, { onClick, onDblClick, onMouseDown, onMouseMove, onMouseOut, onMouseOver, onMouseUp, onRightClick, onDrag, onDragEnd, onDragStart });
1189
+ return null;
1190
+ });
1191
+ var MapRectangle = forwardRef3(function MapRectangle2({
1192
+ bounds,
1193
+ options,
1194
+ onLoad,
1195
+ onUnmount,
1196
+ onClick,
1197
+ onDblClick,
1198
+ onMouseDown,
1199
+ onMouseMove,
1200
+ onMouseOut,
1201
+ onMouseOver,
1202
+ onMouseUp,
1203
+ onRightClick,
1204
+ onDrag,
1205
+ onDragEnd,
1206
+ onDragStart
1207
+ }, ref) {
1208
+ const map = useGoogleMap();
1209
+ const [rectangle, setRectangle] = useState4(null);
1210
+ useImperativeHandle3(
1211
+ ref,
1212
+ () => ({
1213
+ rectangle,
1214
+ getBounds() {
1215
+ return rectangle?.getBounds() || null;
1216
+ },
1217
+ getVisible() {
1218
+ return rectangle?.getVisible();
1219
+ },
1220
+ getDraggable() {
1221
+ return rectangle?.getDraggable();
1222
+ },
1223
+ getEditable() {
1224
+ return rectangle?.getEditable();
1225
+ },
1226
+ setBounds(nextBounds) {
1227
+ rectangle?.setBounds(nextBounds);
1228
+ },
1229
+ setOptions(nextOptions) {
1230
+ rectangle?.setOptions(nextOptions);
1231
+ }
1232
+ }),
1233
+ [rectangle]
1234
+ );
1235
+ useEffect4(() => {
1236
+ if (!map || rectangle) {
1237
+ return;
1238
+ }
1239
+ const instance = new google.maps.Rectangle({ map });
1240
+ setRectangle(instance);
1241
+ onLoad?.(instance);
1242
+ return () => {
1243
+ onUnmount?.(instance);
1244
+ instance.setMap(null);
1245
+ };
1246
+ }, [map, rectangle]);
1247
+ useEffect4(() => {
1248
+ if (!rectangle) {
1249
+ return;
1250
+ }
1251
+ if (!shallowBoundsEqual(rectangle.getBounds()?.toJSON(), bounds)) {
1252
+ rectangle.setBounds(bounds);
1253
+ }
1254
+ rectangle.setOptions({
1255
+ ...options,
1256
+ map
1257
+ });
1258
+ }, [rectangle, map, bounds, options]);
1259
+ useShapeEvents(rectangle, { onClick, onDblClick, onMouseDown, onMouseMove, onMouseOut, onMouseOver, onMouseUp, onRightClick, onDrag, onDragEnd, onDragStart });
1260
+ return null;
1261
+ });
1262
+ var MapCircle = forwardRef3(function MapCircle2({
1263
+ center,
1264
+ radius,
1265
+ options,
1266
+ onLoad,
1267
+ onUnmount,
1268
+ onClick,
1269
+ onDblClick,
1270
+ onMouseDown,
1271
+ onMouseMove,
1272
+ onMouseOut,
1273
+ onMouseOver,
1274
+ onMouseUp,
1275
+ onRightClick,
1276
+ onDrag,
1277
+ onDragEnd,
1278
+ onDragStart
1279
+ }, ref) {
1280
+ const map = useGoogleMap();
1281
+ const [circle, setCircle] = useState4(null);
1282
+ useImperativeHandle3(
1283
+ ref,
1284
+ () => ({
1285
+ circle,
1286
+ getBounds() {
1287
+ return circle?.getBounds() || null;
1288
+ },
1289
+ getCenter() {
1290
+ return circle?.getCenter() || null;
1291
+ },
1292
+ getRadius() {
1293
+ return circle?.getRadius();
1294
+ },
1295
+ getVisible() {
1296
+ return circle?.getVisible();
1297
+ },
1298
+ getDraggable() {
1299
+ return circle?.getDraggable();
1300
+ },
1301
+ getEditable() {
1302
+ return circle?.getEditable();
1303
+ },
1304
+ setCenter(nextCenter) {
1305
+ circle?.setCenter(nextCenter);
1306
+ },
1307
+ setRadius(nextRadius) {
1308
+ circle?.setRadius(nextRadius);
1309
+ },
1310
+ setOptions(nextOptions) {
1311
+ circle?.setOptions(nextOptions);
1312
+ }
1313
+ }),
1314
+ [circle]
1315
+ );
1316
+ useEffect4(() => {
1317
+ if (!map || circle) {
1318
+ return;
1319
+ }
1320
+ const instance = new google.maps.Circle({ map });
1321
+ setCircle(instance);
1322
+ onLoad?.(instance);
1323
+ return () => {
1324
+ onUnmount?.(instance);
1325
+ instance.setMap(null);
1326
+ };
1327
+ }, [map, circle]);
1328
+ useEffect4(() => {
1329
+ if (!circle) {
1330
+ return;
1331
+ }
1332
+ circle.setOptions({
1333
+ ...options,
1334
+ center,
1335
+ radius,
1336
+ map
1337
+ });
1338
+ }, [circle, map, center, radius, options]);
1339
+ useShapeEvents(circle, { onClick, onDblClick, onMouseDown, onMouseMove, onMouseOut, onMouseOver, onMouseUp, onRightClick, onDrag, onDragEnd, onDragStart });
1340
+ return null;
1341
+ });
1342
+ var MapGroundOverlay = forwardRef3(function MapGroundOverlay2({ url, bounds, opacity, clickable, onLoad, onUnmount, onClick }, ref) {
1343
+ const map = useGoogleMap();
1344
+ const [overlay, setOverlay] = useState4(null);
1345
+ useImperativeHandle3(
1346
+ ref,
1347
+ () => ({
1348
+ overlay,
1349
+ getBounds() {
1350
+ return overlay?.getBounds() || null;
1351
+ },
1352
+ getOpacity() {
1353
+ return overlay?.getOpacity();
1354
+ },
1355
+ getUrl() {
1356
+ return overlay?.getUrl();
1357
+ },
1358
+ setOpacity(nextOpacity) {
1359
+ overlay?.setOpacity(nextOpacity);
1360
+ },
1361
+ setMap(nextMap) {
1362
+ overlay?.setMap(nextMap);
1363
+ }
1364
+ }),
1365
+ [overlay]
1366
+ );
1367
+ useEffect4(() => {
1368
+ if (!map) {
1369
+ return;
1370
+ }
1371
+ const instance = new google.maps.GroundOverlay(url, bounds, removeUndefined({ opacity, clickable }));
1372
+ instance.setMap(map);
1373
+ setOverlay(instance);
1374
+ onLoad?.(instance);
1375
+ return () => {
1376
+ onUnmount?.(instance);
1377
+ instance.setMap(null);
1378
+ };
1379
+ }, [map, url, JSON.stringify(bounds), opacity, clickable]);
1380
+ useEffect4(() => {
1381
+ if (!overlay) {
1382
+ return;
1383
+ }
1384
+ const listener = addListener(overlay, "click", onClick);
1385
+ return () => {
1386
+ listener?.remove();
1387
+ };
1388
+ }, [overlay, onClick]);
1389
+ return null;
1390
+ });
1391
+ function MapControl({ position, children, index }) {
1392
+ const map = useGoogleMap();
1393
+ const [element] = useState4(() => typeof document !== "undefined" ? document.createElement("div") : null);
1394
+ useEffect4(() => {
1395
+ if (!map || !element) {
1396
+ return;
1397
+ }
1398
+ const controls = map.controls[position];
1399
+ if (typeof index === "number" && index >= 0 && index < controls.getLength()) {
1400
+ controls.insertAt(index, element);
1401
+ } else {
1402
+ controls.push(element);
1403
+ }
1404
+ return () => {
1405
+ const nextControls = map.controls[position];
1406
+ for (let currentIndex = 0; currentIndex < nextControls.getLength(); currentIndex += 1) {
1407
+ if (nextControls.getAt(currentIndex) === element) {
1408
+ nextControls.removeAt(currentIndex);
1409
+ break;
1410
+ }
1411
+ }
1412
+ };
1413
+ }, [map, element, position, index]);
1414
+ return element ? createPortal2(children, element) : null;
1415
+ }
1416
+ function useShapeEvents(shape, handlers) {
1417
+ useEffect4(() => {
1418
+ if (!shape) {
1419
+ return;
1420
+ }
1421
+ const listeners = [
1422
+ addListener(shape, "click", handlers.onClick),
1423
+ addListener(shape, "dblclick", handlers.onDblClick),
1424
+ addListener(shape, "mousedown", handlers.onMouseDown),
1425
+ addListener(shape, "mousemove", handlers.onMouseMove),
1426
+ addListener(shape, "mouseout", handlers.onMouseOut),
1427
+ addListener(shape, "mouseover", handlers.onMouseOver),
1428
+ addListener(shape, "mouseup", handlers.onMouseUp),
1429
+ addListener(shape, "rightclick", handlers.onRightClick),
1430
+ addListener(shape, "drag", handlers.onDrag),
1431
+ addListener(shape, "dragend", handlers.onDragEnd),
1432
+ addListener(shape, "dragstart", handlers.onDragStart)
1433
+ ].filter(Boolean);
1434
+ return () => {
1435
+ listeners.forEach((listener) => listener?.remove());
1436
+ };
1437
+ }, [shape, handlers.onClick, handlers.onDblClick, handlers.onMouseDown, handlers.onMouseMove, handlers.onMouseOut, handlers.onMouseOver, handlers.onMouseUp, handlers.onRightClick, handlers.onDrag, handlers.onDragEnd, handlers.onDragStart]);
1438
+ }
1439
+
1440
+ // src/layers.tsx
1441
+ import { forwardRef as forwardRef4, useEffect as useEffect5, useImperativeHandle as useImperativeHandle4, useState as useState5 } from "react";
1442
+ var MapTrafficLayer = forwardRef4(function MapTrafficLayer2({ options, onLoad, onUnmount }, ref) {
1443
+ const map = useGoogleMap();
1444
+ const [layer, setLayer] = useState5(null);
1445
+ useImperativeHandle4(
1446
+ ref,
1447
+ () => ({
1448
+ layer,
1449
+ setMap(nextMap) {
1450
+ layer?.setMap(nextMap);
1451
+ },
1452
+ setOptions(nextOptions) {
1453
+ layer?.setOptions(nextOptions);
1454
+ }
1455
+ }),
1456
+ [layer]
1457
+ );
1458
+ useEffect5(() => {
1459
+ if (!map || layer) {
1460
+ return;
1461
+ }
1462
+ const instance = new google.maps.TrafficLayer(options);
1463
+ instance.setMap(map);
1464
+ setLayer(instance);
1465
+ onLoad?.(instance);
1466
+ return () => {
1467
+ onUnmount?.(instance);
1468
+ instance.setMap(null);
1469
+ };
1470
+ }, [map, layer]);
1471
+ useEffect5(() => {
1472
+ if (layer && options) {
1473
+ layer.setOptions(options);
1474
+ }
1475
+ }, [layer, options]);
1476
+ return null;
1477
+ });
1478
+ var MapTransitLayer = forwardRef4(function MapTransitLayer2({ onLoad, onUnmount }, ref) {
1479
+ const map = useGoogleMap();
1480
+ const [layer, setLayer] = useState5(null);
1481
+ useImperativeHandle4(
1482
+ ref,
1483
+ () => ({
1484
+ layer,
1485
+ setMap(nextMap) {
1486
+ layer?.setMap(nextMap);
1487
+ }
1488
+ }),
1489
+ [layer]
1490
+ );
1491
+ useEffect5(() => {
1492
+ if (!map) {
1493
+ return;
1494
+ }
1495
+ const layer2 = new google.maps.TransitLayer();
1496
+ layer2.setMap(map);
1497
+ setLayer(layer2);
1498
+ onLoad?.(layer2);
1499
+ return () => {
1500
+ onUnmount?.(layer2);
1501
+ layer2.setMap(null);
1502
+ };
1503
+ }, [map]);
1504
+ return null;
1505
+ });
1506
+ var MapBicyclingLayer = forwardRef4(function MapBicyclingLayer2({ onLoad, onUnmount }, ref) {
1507
+ const map = useGoogleMap();
1508
+ const [layer, setLayer] = useState5(null);
1509
+ useImperativeHandle4(
1510
+ ref,
1511
+ () => ({
1512
+ layer,
1513
+ setMap(nextMap) {
1514
+ layer?.setMap(nextMap);
1515
+ }
1516
+ }),
1517
+ [layer]
1518
+ );
1519
+ useEffect5(() => {
1520
+ if (!map) {
1521
+ return;
1522
+ }
1523
+ const layer2 = new google.maps.BicyclingLayer();
1524
+ layer2.setMap(map);
1525
+ setLayer(layer2);
1526
+ onLoad?.(layer2);
1527
+ return () => {
1528
+ onUnmount?.(layer2);
1529
+ layer2.setMap(null);
1530
+ };
1531
+ }, [map]);
1532
+ return null;
1533
+ });
1534
+ var MapKmlLayer = forwardRef4(function MapKmlLayer2({
1535
+ url,
1536
+ options,
1537
+ onLoad,
1538
+ onUnmount
1539
+ }, ref) {
1540
+ const map = useGoogleMap();
1541
+ const [layer, setLayer] = useState5(null);
1542
+ useImperativeHandle4(
1543
+ ref,
1544
+ () => ({
1545
+ layer,
1546
+ getDefaultViewport() {
1547
+ return layer?.getDefaultViewport() || null;
1548
+ },
1549
+ getMetadata() {
1550
+ return layer?.getMetadata() || null;
1551
+ },
1552
+ getStatus() {
1553
+ return layer?.getStatus() || null;
1554
+ },
1555
+ getUrl() {
1556
+ return layer?.getUrl() || null;
1557
+ },
1558
+ setMap(nextMap) {
1559
+ layer?.setMap(nextMap);
1560
+ },
1561
+ setOptions(nextOptions) {
1562
+ layer?.setOptions(nextOptions);
1563
+ },
1564
+ setUrl(nextUrl) {
1565
+ layer?.setUrl(nextUrl);
1566
+ }
1567
+ }),
1568
+ [layer]
1569
+ );
1570
+ useEffect5(() => {
1571
+ if (!map) {
1572
+ return;
1573
+ }
1574
+ const instance = new google.maps.KmlLayer({
1575
+ ...options,
1576
+ map,
1577
+ url
1578
+ });
1579
+ setLayer(instance);
1580
+ onLoad?.(instance);
1581
+ return () => {
1582
+ onUnmount?.(instance);
1583
+ instance.setMap(null);
1584
+ };
1585
+ }, [map, url]);
1586
+ useEffect5(() => {
1587
+ if (!layer) {
1588
+ return;
1589
+ }
1590
+ layer.setOptions({
1591
+ ...options,
1592
+ map
1593
+ });
1594
+ layer.setUrl(url);
1595
+ }, [layer, options, map, url]);
1596
+ return null;
1597
+ });
1598
+ var MapHeatmapLayer = forwardRef4(function MapHeatmapLayer2({
1599
+ data,
1600
+ options,
1601
+ onLoad,
1602
+ onUnmount
1603
+ }, ref) {
1604
+ const map = useGoogleMap();
1605
+ const [layer, setLayer] = useState5(null);
1606
+ useImperativeHandle4(
1607
+ ref,
1608
+ () => ({
1609
+ layer,
1610
+ getData() {
1611
+ return layer?.getData() || null;
1612
+ },
1613
+ setData(nextData) {
1614
+ layer?.setData(normalizeHeatmapData(nextData));
1615
+ },
1616
+ setMap(nextMap) {
1617
+ layer?.setMap(nextMap);
1618
+ },
1619
+ setOptions(nextOptions) {
1620
+ layer?.setOptions(nextOptions);
1621
+ }
1622
+ }),
1623
+ [layer]
1624
+ );
1625
+ useEffect5(() => {
1626
+ if (!map) {
1627
+ return;
1628
+ }
1629
+ if (!google.maps.visualization?.HeatmapLayer) {
1630
+ throw new Error("HeatmapLayer is unavailable. Make sure the visualization library is enabled.");
1631
+ }
1632
+ const instance = new google.maps.visualization.HeatmapLayer({
1633
+ ...options,
1634
+ map,
1635
+ data: normalizeHeatmapData(data)
1636
+ });
1637
+ setLayer(instance);
1638
+ onLoad?.(instance);
1639
+ return () => {
1640
+ onUnmount?.(instance);
1641
+ instance.setMap(null);
1642
+ };
1643
+ }, [map]);
1644
+ useEffect5(() => {
1645
+ if (!layer) {
1646
+ return;
1647
+ }
1648
+ layer.setOptions({
1649
+ ...options,
1650
+ data: normalizeHeatmapData(data),
1651
+ map
1652
+ });
1653
+ }, [layer, options, data, map]);
1654
+ return null;
1655
+ });
1656
+ function normalizeHeatmapData(data) {
1657
+ return data.map((entry) => {
1658
+ if ("location" in entry) {
1659
+ const weighted = entry;
1660
+ return {
1661
+ location: toLatLng(weighted.location),
1662
+ weight: weighted.weight
1663
+ };
1664
+ }
1665
+ return toLatLng(entry);
1666
+ });
1667
+ }
1668
+
1669
+ // src/directions.tsx
1670
+ import { forwardRef as forwardRef5, useEffect as useEffect6, useImperativeHandle as useImperativeHandle5, useRef as useRef4, useState as useState6 } from "react";
1671
+ var MapDirectionsRenderer = forwardRef5(function MapDirectionsRenderer2({
1672
+ directions,
1673
+ options,
1674
+ onLoad,
1675
+ onUnmount,
1676
+ onDirectionsChanged
1677
+ }, ref) {
1678
+ const map = useGoogleMap();
1679
+ const [renderer, setRenderer] = useState6(null);
1680
+ useImperativeHandle5(
1681
+ ref,
1682
+ () => ({
1683
+ renderer,
1684
+ getDirections() {
1685
+ return renderer?.getDirections() || null;
1686
+ },
1687
+ getPanel() {
1688
+ return renderer?.getPanel() || null;
1689
+ },
1690
+ getRouteIndex() {
1691
+ return renderer?.getRouteIndex();
1692
+ },
1693
+ setDirections(nextDirections) {
1694
+ renderer?.setDirections(nextDirections);
1695
+ },
1696
+ setOptions(nextOptions) {
1697
+ renderer?.setOptions(nextOptions);
1698
+ },
1699
+ setRouteIndex(nextRouteIndex) {
1700
+ renderer?.setRouteIndex(nextRouteIndex);
1701
+ }
1702
+ }),
1703
+ [renderer]
1704
+ );
1705
+ useEffect6(() => {
1706
+ if (!map || renderer) {
1707
+ return;
1708
+ }
1709
+ const instance = new google.maps.DirectionsRenderer({
1710
+ ...options,
1711
+ map
1712
+ });
1713
+ setRenderer(instance);
1714
+ onLoad?.(instance);
1715
+ return () => {
1716
+ onUnmount?.(instance);
1717
+ instance.setMap(null);
1718
+ };
1719
+ }, [map, renderer]);
1720
+ useEffect6(() => {
1721
+ if (!renderer) {
1722
+ return;
1723
+ }
1724
+ renderer.setOptions({
1725
+ ...options,
1726
+ directions: directions || void 0,
1727
+ map
1728
+ });
1729
+ }, [renderer, directions, options, map]);
1730
+ useEffect6(() => {
1731
+ if (!renderer) {
1732
+ return;
1733
+ }
1734
+ const listener = addListener(renderer, "directions_changed", onDirectionsChanged);
1735
+ return () => {
1736
+ listener?.remove();
1737
+ };
1738
+ }, [renderer, onDirectionsChanged]);
1739
+ return null;
1740
+ });
1741
+ function MapDirectionsService({
1742
+ request,
1743
+ onResult,
1744
+ onError
1745
+ }) {
1746
+ const service = useDirectionsService();
1747
+ const requestIdRef = useRef4(0);
1748
+ useEffect6(() => {
1749
+ if (!service || !request) {
1750
+ return;
1751
+ }
1752
+ requestIdRef.current += 1;
1753
+ const currentRequestId = requestIdRef.current;
1754
+ service.route(request, (result, status) => {
1755
+ if (currentRequestId !== requestIdRef.current) {
1756
+ return;
1757
+ }
1758
+ if (status === google.maps.DirectionsStatus.OK && result) {
1759
+ onResult({ status, result });
1760
+ } else {
1761
+ const error = new Error(`Directions request failed with status ${status}.`);
1762
+ onResult({ status, result: result || null });
1763
+ onError?.(error);
1764
+ }
1765
+ });
1766
+ }, [service, request, onResult, onError]);
1767
+ return null;
1768
+ }
1769
+ export {
1770
+ GoogleMap,
1771
+ GoogleMapsProvider,
1772
+ MapAdvancedMarker,
1773
+ MapBicyclingLayer,
1774
+ MapCircle,
1775
+ MapControl,
1776
+ MapDirectionsRenderer,
1777
+ MapDirectionsService,
1778
+ MapGroundOverlay,
1779
+ MapHeatmapLayer,
1780
+ MapInfoWindow,
1781
+ MapKmlLayer,
1782
+ MapMarker,
1783
+ MapMarkerClusterer,
1784
+ MapPolygon,
1785
+ MapPolyline,
1786
+ MapRectangle,
1787
+ MapTrafficLayer,
1788
+ MapTransitLayer,
1789
+ createClusterRenderer,
1790
+ getDefaultGoogleMapsLibraries,
1791
+ loadGoogleMapsApi,
1792
+ useDirectionsService,
1793
+ useGoogleMap,
1794
+ useGoogleMapsApi,
1795
+ useMapGeocoder
1796
+ };
1797
+ //# sourceMappingURL=index.js.map