react-bkoi-gl 2.0.1 → 2.1.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 CHANGED
@@ -1,13 +1,6 @@
1
1
  // src/components/map.tsx
2
2
  import * as React2 from "react";
3
- import {
4
- useState as useState2,
5
- useRef,
6
- useEffect as useEffect5,
7
- useContext as useContext3,
8
- useMemo as useMemo3,
9
- useImperativeHandle
10
- } from "react";
3
+ import { useState as useState2, useRef, useEffect as useEffect5, useContext as useContext3, useMemo as useMemo3, useImperativeHandle } from "react";
11
4
 
12
5
  // src/components/use-map.tsx
13
6
  import * as React from "react";
@@ -52,7 +45,8 @@ function useMap() {
52
45
  const maps = useContext(MountedMapsContext)?.maps;
53
46
  const currentMap = useContext(MapContext);
54
47
  const mapsWithCurrent = useMemo(() => {
55
- return { ...maps, current: currentMap?.map };
48
+ const current = currentMap?.map || (maps ? Object.values(maps)[0] : void 0);
49
+ return { ...maps, current };
56
50
  }, [maps, currentMap]);
57
51
  return mapsWithCurrent;
58
52
  }
@@ -138,15 +132,7 @@ function applyViewStateToTransform(tr, props) {
138
132
  }
139
133
 
140
134
  // src/utils/style-utils.ts
141
- var refProps = [
142
- "type",
143
- "source",
144
- "source-layer",
145
- "minzoom",
146
- "maxzoom",
147
- "filter",
148
- "layout"
149
- ];
135
+ var refProps = ["type", "source", "source-layer", "minzoom", "maxzoom", "filter", "layout"];
150
136
  function normalizeStyle(style) {
151
137
  if (!style) {
152
138
  return null;
@@ -165,14 +151,15 @@ function normalizeStyle(style) {
165
151
  layerIndex[layer.id] = layer;
166
152
  }
167
153
  const layers = style.layers.map((layer) => {
154
+ const legacyLayer = layer;
168
155
  let normalizedLayer = null;
169
- if ("interactive" in layer) {
170
- normalizedLayer = Object.assign({}, layer);
156
+ if ("interactive" in legacyLayer) {
157
+ normalizedLayer = Object.assign({}, legacyLayer);
171
158
  delete normalizedLayer.interactive;
172
159
  }
173
- const layerRef = layerIndex[layer.ref];
160
+ const layerRef = layerIndex[legacyLayer.ref];
174
161
  if (layerRef) {
175
- normalizedLayer = normalizedLayer || Object.assign({}, layer);
162
+ normalizedLayer = normalizedLayer || Object.assign({}, legacyLayer);
176
163
  delete normalizedLayer.ref;
177
164
  for (const propName of refProps) {
178
165
  if (propName in layerRef) {
@@ -268,7 +255,8 @@ var Maplibre = class _Maplibre {
268
255
  this._propsedCameraUpdate = null;
269
256
  this._styleComponents = {};
270
257
  this._onEvent = (e) => {
271
- const cb = this.props[otherEvents[e.type]];
258
+ const handlerName = otherEvents[e.type];
259
+ const cb = this.props[handlerName];
272
260
  if (cb) {
273
261
  cb(e);
274
262
  } else if (e.type === "error") {
@@ -280,7 +268,8 @@ var Maplibre = class _Maplibre {
280
268
  return;
281
269
  }
282
270
  e.viewState = this._propsedCameraUpdate || transformToViewState(this._map.transform);
283
- const cb = this.props[cameraEvents[e.type]];
271
+ const handlerName = cameraEvents[e.type];
272
+ const cb = this.props[handlerName];
284
273
  if (cb) {
285
274
  cb(e);
286
275
  }
@@ -296,7 +285,8 @@ var Maplibre = class _Maplibre {
296
285
  if (e.type === "mousemove" || e.type === "mouseout") {
297
286
  this._updateHover(e);
298
287
  }
299
- const cb = this.props[pointerEvents[e.type]];
288
+ const handlerName = pointerEvents[e.type];
289
+ const cb = this.props[handlerName];
300
290
  if (cb) {
301
291
  if (this.props.interactiveLayerIds && e.type !== "mouseover" && e.type !== "mouseout") {
302
292
  e.features = this._hoveredFeatures || this._queryRenderedFeatures(e.point);
@@ -310,7 +300,6 @@ var Maplibre = class _Maplibre {
310
300
  this._initialize(container);
311
301
  }
312
302
  static {
313
- // eslint-disable-next-line no-use-before-define
314
303
  this.savedMaps = [];
315
304
  }
316
305
  get map() {
@@ -340,8 +329,9 @@ var Maplibre = class _Maplibre {
340
329
  while (oldContainer.childNodes.length > 0) {
341
330
  container.appendChild(oldContainer.childNodes[0]);
342
331
  }
343
- map._container = container;
344
- const resizeObserver = map._resizeObserver;
332
+ const mapInternal = map;
333
+ mapInternal._container = container;
334
+ const resizeObserver = mapInternal._resizeObserver;
345
335
  if (resizeObserver) {
346
336
  resizeObserver.disconnect();
347
337
  resizeObserver.observe(container);
@@ -364,10 +354,10 @@ var Maplibre = class _Maplibre {
364
354
  } else {
365
355
  map.once("style.load", () => map.fire("load"));
366
356
  }
367
- map._update();
357
+ const mapInternalForUpdate = map;
358
+ mapInternalForUpdate._update();
368
359
  return that;
369
360
  }
370
- /* eslint-disable complexity,max-statements */
371
361
  _initialize(container) {
372
362
  const { props } = this;
373
363
  const { mapStyle = DEFAULT_STYLE } = props;
@@ -400,11 +390,11 @@ var Maplibre = class _Maplibre {
400
390
  }
401
391
  map.transformCameraUpdate = this._onCameraUpdate;
402
392
  map.on("style.load", () => {
393
+ const mapWithProjection = map;
403
394
  this._styleComponents = {
404
395
  light: map.getLight(),
405
396
  sky: map.getSky(),
406
- // @ts-ignore getProjection() does not exist in v4
407
- projection: map.getProjection?.(),
397
+ projection: mapWithProjection.getProjection?.(),
408
398
  terrain: map.getTerrain()
409
399
  };
410
400
  this._updateStyleComponents(this.props);
@@ -423,7 +413,6 @@ var Maplibre = class _Maplibre {
423
413
  }
424
414
  this._map = map;
425
415
  }
426
- /* eslint-enable complexity,max-statements */
427
416
  recycle() {
428
417
  const container = this.map.getContainer();
429
418
  const children = container.querySelector("[mapboxgl-children]");
@@ -520,14 +509,10 @@ var Maplibre = class _Maplibre {
520
509
  * 1. They can not be applied right away. Certain conditions (style loaded, source loaded, etc.) must be met
521
510
  * 2. They can be overwritten by mapStyle
522
511
  */
523
- _updateStyleComponents({
524
- light,
525
- projection,
526
- sky,
527
- terrain
528
- }) {
512
+ _updateStyleComponents({ light, projection, sky, terrain }) {
529
513
  const map = this._map;
530
514
  const currProps = this._styleComponents;
515
+ const mapWithProjection = map;
531
516
  if (map.style._loaded) {
532
517
  if (light && !deepEqual(light, currProps.light)) {
533
518
  currProps.light = light;
@@ -535,7 +520,7 @@ var Maplibre = class _Maplibre {
535
520
  }
536
521
  if (projection && !deepEqual(projection, currProps.projection) && projection !== currProps.projection?.type) {
537
522
  currProps.projection = typeof projection === "string" ? { type: projection } : projection;
538
- map.setProjection?.(currProps.projection);
523
+ mapWithProjection.setProjection?.(currProps.projection);
539
524
  }
540
525
  if (sky && !deepEqual(sky, currProps.sky)) {
541
526
  currProps.sky = sky;
@@ -657,19 +642,34 @@ var useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffec
657
642
  var use_isomorphic_layout_effect_default = useIsomorphicLayoutEffect;
658
643
 
659
644
  // src/utils/set-globals.ts
645
+ var validateUrl = (url, settingName) => {
646
+ try {
647
+ const parsed = new URL(url);
648
+ if (!["http:", "https:"].includes(parsed.protocol)) {
649
+ console.warn(`${settingName}: Only http/https protocols are allowed, got: ${parsed.protocol}`);
650
+ return false;
651
+ }
652
+ return true;
653
+ } catch {
654
+ console.warn(`${settingName}: Invalid URL format: ${url}`);
655
+ return false;
656
+ }
657
+ };
660
658
  function setGlobals(mapLib, props) {
661
659
  const { RTLTextPlugin, maxParallelImageRequests, workerCount, workerUrl } = props;
662
660
  if (RTLTextPlugin && mapLib.getRTLTextPluginStatus && mapLib.getRTLTextPluginStatus() === "unavailable") {
663
661
  const { pluginUrl, lazy = true } = typeof RTLTextPlugin === "string" ? { pluginUrl: RTLTextPlugin } : RTLTextPlugin;
664
- mapLib.setRTLTextPlugin(
665
- pluginUrl,
666
- (error) => {
667
- if (error) {
668
- console.error(error);
669
- }
670
- },
671
- lazy
672
- );
662
+ if (validateUrl(pluginUrl, "RTLTextPlugin")) {
663
+ mapLib.setRTLTextPlugin(
664
+ pluginUrl,
665
+ (error) => {
666
+ if (error) {
667
+ console.error(error);
668
+ }
669
+ },
670
+ lazy
671
+ );
672
+ }
673
673
  }
674
674
  if (maxParallelImageRequests !== void 0) {
675
675
  mapLib.setMaxParallelImageRequests(maxParallelImageRequests);
@@ -678,7 +678,9 @@ function setGlobals(mapLib, props) {
678
678
  mapLib.setWorkerCount(workerCount);
679
679
  }
680
680
  if (workerUrl !== void 0) {
681
- mapLib.setWorkerUrl(workerUrl);
681
+ if (validateUrl(workerUrl, "workerUrl")) {
682
+ mapLib.setWorkerUrl(workerUrl);
683
+ }
682
684
  }
683
685
  }
684
686
 
@@ -706,14 +708,18 @@ function applyReactStyle(element, styles) {
706
708
  import { useContext as useContext2, useMemo as useMemo2, useEffect as useEffect2 } from "react";
707
709
  function useControl(onCreate, arg1, arg2, arg3) {
708
710
  const context = useContext2(MapContext);
711
+ if (!context) {
712
+ throw new Error("useControl must be used within a Map component");
713
+ }
709
714
  const ctrl = useMemo2(() => onCreate(context), []);
710
715
  useEffect2(() => {
711
716
  const opts = arg3 || arg2 || arg1;
712
717
  const onAdd = typeof arg1 === "function" && typeof arg2 === "function" ? arg1 : null;
713
718
  const onRemove = typeof arg2 === "function" ? arg2 : typeof arg1 === "function" ? arg1 : null;
714
719
  const { map } = context;
715
- if (!map.hasControl(ctrl)) {
716
- map.addControl(ctrl, opts?.position);
720
+ const ctrlAsIControl = ctrl;
721
+ if (!map.hasControl(ctrlAsIControl)) {
722
+ map.addControl(ctrlAsIControl, opts?.position);
717
723
  if (onAdd) {
718
724
  onAdd(context);
719
725
  }
@@ -722,8 +728,8 @@ function useControl(onCreate, arg1, arg2, arg3) {
722
728
  if (onRemove) {
723
729
  onRemove(context);
724
730
  }
725
- if (map.hasControl(ctrl)) {
726
- map.removeControl(ctrl);
731
+ if (map.hasControl(ctrlAsIControl)) {
732
+ map.removeControl(ctrlAsIControl);
727
733
  }
728
734
  };
729
735
  }, []);
@@ -783,11 +789,24 @@ function _AttributionControl(props) {
783
789
  if (!ctrl._container || !map) return;
784
790
  const onLoad = () => {
785
791
  setTimeout(() => {
786
- const inner = ctrl._container.querySelector(
787
- ".maplibregl-ctrl-attrib-inner"
788
- );
792
+ const inner = ctrl._container.querySelector(".maplibregl-ctrl-attrib-inner");
789
793
  if (inner) {
790
- inner.innerHTML = '\xA9 <a href="https://barikoi.com" target="_blank">Barikoi</a> \xA9 <a href="https://openmaptiles.org" target="_blank">OpenMapTiles</a> \xA9 <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap contributors</a>';
794
+ inner.textContent = "";
795
+ const createLink = (text, href) => {
796
+ const a = document.createElement("a");
797
+ a.href = href;
798
+ a.target = "_blank";
799
+ a.rel = "noopener noreferrer";
800
+ a.textContent = text;
801
+ return a;
802
+ };
803
+ inner.appendChild(createLink("Barikoi", "https://barikoi.com"));
804
+ inner.appendChild(document.createTextNode(" \xA9 "));
805
+ inner.appendChild(createLink("OpenMapTiles", "https://openmaptiles.org"));
806
+ inner.appendChild(document.createTextNode(" \xA9 "));
807
+ inner.appendChild(
808
+ createLink("OpenStreetMap contributors", "https://www.openstreetmap.org/copyright")
809
+ );
791
810
  }
792
811
  }, 0);
793
812
  };
@@ -817,7 +836,7 @@ function _Map(props, ref) {
817
836
  useEffect5(() => {
818
837
  const mapLib = props.mapLib;
819
838
  let isMounted = true;
820
- let maplibre;
839
+ let maplibre = null;
821
840
  Promise.resolve(mapLib || import("maplibre-gl")).then((module) => {
822
841
  if (!isMounted) {
823
842
  return;
@@ -838,15 +857,16 @@ function _Map(props, ref) {
838
857
  mapboxgl.Map,
839
858
  {
840
859
  ...props,
841
- // @ts-ignore - attributionControl is not in the type definition but is supported by maplibre-gl
842
860
  attributionControl: false
843
861
  },
844
862
  containerRef.current
845
863
  );
846
864
  }
847
- contextValue.map = createRef(maplibre);
848
- contextValue.mapLib = mapboxgl;
849
- setMapInstance(maplibre);
865
+ if (maplibre) {
866
+ contextValue.map = createRef(maplibre);
867
+ contextValue.mapLib = mapboxgl;
868
+ setMapInstance(maplibre);
869
+ }
850
870
  mountedMapsContext?.onMapMount(contextValue.map, props.id);
851
871
  }).catch((error) => {
852
872
  const { onError } = props;
@@ -891,7 +911,7 @@ function _Map(props, ref) {
891
911
  const CHILD_CONTAINER_STYLE = {
892
912
  height: "100%"
893
913
  };
894
- return /* @__PURE__ */ React2.createElement("div", { id: props.id, ref: containerRef, style }, mapInstance && /* @__PURE__ */ React2.createElement(MapContext.Provider, { value: contextValue }, /* @__PURE__ */ React2.createElement("div", { "mapboxgl-children": "", style: CHILD_CONTAINER_STYLE }, /* @__PURE__ */ React2.createElement(LogoControl, { position: "bottom-left" }), /* @__PURE__ */ React2.createElement(AttributionControl, { position: "bottom-right" }), props.children)));
914
+ return /* @__PURE__ */ React2.createElement("div", { id: props.id, ref: containerRef, style }, mapInstance && /* @__PURE__ */ React2.createElement(MapContext.Provider, { value: contextValue }, /* @__PURE__ */ React2.createElement("div", { style: CHILD_CONTAINER_STYLE }, /* @__PURE__ */ React2.createElement(LogoControl, { position: "bottom-left" }), /* @__PURE__ */ React2.createElement(AttributionControl, { position: "bottom-right" }), props.children)));
895
915
  }
896
916
  var Map = React2.forwardRef(_Map);
897
917
 
@@ -936,7 +956,7 @@ function getClassList(className) {
936
956
  var Marker = memo3(
937
957
  forwardRef2((props, ref) => {
938
958
  const { map, mapLib } = useContext4(MapContext);
939
- const thisRef = useRef2({ props });
959
+ const callbackRef = useRef2({});
940
960
  const marker = useMemo4(() => {
941
961
  let hasChildren = false;
942
962
  React3.Children.forEach(props.children, (el) => {
@@ -950,33 +970,46 @@ var Marker = memo3(
950
970
  };
951
971
  const mk = new mapLib.Marker(options);
952
972
  mk.setLngLat([props.longitude, props.latitude]);
953
- mk.getElement().addEventListener("click", (e) => {
954
- thisRef.current.props.onClick?.({
955
- type: "click",
956
- target: mk,
957
- originalEvent: e
958
- });
959
- });
960
- mk.on("dragstart", (e) => {
961
- const evt = e;
962
- evt.lngLat = marker.getLngLat();
963
- thisRef.current.props.onDragStart?.(evt);
964
- });
965
- mk.on("drag", (e) => {
966
- const evt = e;
967
- evt.lngLat = marker.getLngLat();
968
- thisRef.current.props.onDrag?.(evt);
969
- });
970
- mk.on("dragend", (e) => {
971
- const evt = e;
972
- evt.lngLat = marker.getLngLat();
973
- thisRef.current.props.onDragEnd?.(evt);
974
- });
975
973
  return mk;
976
974
  }, []);
977
975
  useEffect6(() => {
976
+ callbackRef.current = {
977
+ onClick: props.onClick,
978
+ onDragStart: props.onDragStart,
979
+ onDrag: props.onDrag,
980
+ onDragEnd: props.onDragEnd
981
+ };
982
+ });
983
+ useEffect6(() => {
984
+ const clickHandler = (e) => {
985
+ callbackRef.current.onClick?.({
986
+ type: "click",
987
+ target: marker,
988
+ originalEvent: e
989
+ });
990
+ };
991
+ marker.getElement().addEventListener("click", clickHandler);
992
+ const dragStartHandler = (e) => {
993
+ e.lngLat = marker.getLngLat();
994
+ callbackRef.current.onDragStart?.(e);
995
+ };
996
+ const dragHandler = (e) => {
997
+ e.lngLat = marker.getLngLat();
998
+ callbackRef.current.onDrag?.(e);
999
+ };
1000
+ const dragEndHandler = (e) => {
1001
+ e.lngLat = marker.getLngLat();
1002
+ callbackRef.current.onDragEnd?.(e);
1003
+ };
1004
+ marker.on("dragstart", dragStartHandler);
1005
+ marker.on("drag", dragHandler);
1006
+ marker.on("dragend", dragEndHandler);
978
1007
  marker.addTo(map.getMap());
979
1008
  return () => {
1009
+ marker.getElement().removeEventListener("click", clickHandler);
1010
+ marker.off("dragstart", dragStartHandler);
1011
+ marker.off("drag", dragHandler);
1012
+ marker.off("dragend", dragEndHandler);
980
1013
  marker.remove();
981
1014
  };
982
1015
  }, []);
@@ -989,82 +1022,76 @@ var Marker = memo3(
989
1022
  popup = null,
990
1023
  rotation = 0,
991
1024
  rotationAlignment = "auto",
992
- pitchAlignment = "auto"
1025
+ pitchAlignment = "auto",
1026
+ className
993
1027
  } = props;
994
1028
  useEffect6(() => {
995
1029
  applyReactStyle(marker.getElement(), style);
996
1030
  }, [style]);
997
1031
  useImperativeHandle2(ref, () => marker, []);
998
- const oldProps = thisRef.current.props;
999
- if (marker.getLngLat().lng !== longitude || marker.getLngLat().lat !== latitude) {
1000
- marker.setLngLat([longitude, latitude]);
1001
- }
1002
- if (offset && !arePointsEqual(marker.getOffset(), offset)) {
1003
- marker.setOffset(offset);
1004
- }
1005
- if (marker.isDraggable() !== draggable) {
1006
- marker.setDraggable(draggable);
1007
- }
1008
- if (marker.getRotation() !== rotation) {
1009
- marker.setRotation(rotation);
1010
- }
1011
- if (marker.getRotationAlignment() !== rotationAlignment) {
1012
- marker.setRotationAlignment(rotationAlignment);
1013
- }
1014
- if (marker.getPitchAlignment() !== pitchAlignment) {
1015
- marker.setPitchAlignment(pitchAlignment);
1016
- }
1017
- if (marker.getPopup() !== popup) {
1018
- marker.setPopup(popup);
1019
- }
1020
- const classNameDiff = compareClassNames(
1021
- oldProps.className,
1022
- props.className
1023
- );
1024
- if (classNameDiff) {
1025
- for (const c of classNameDiff) {
1026
- marker.toggleClassName(c);
1032
+ const prevClassNameRef = useRef2(className);
1033
+ useEffect6(() => {
1034
+ if (marker.getLngLat().lng !== longitude || marker.getLngLat().lat !== latitude) {
1035
+ marker.setLngLat([longitude, latitude]);
1027
1036
  }
1028
- }
1029
- thisRef.current.props = props;
1037
+ if (offset && !arePointsEqual(marker.getOffset(), offset)) {
1038
+ marker.setOffset(offset);
1039
+ }
1040
+ if (marker.isDraggable() !== draggable) {
1041
+ marker.setDraggable(draggable);
1042
+ }
1043
+ if (marker.getRotation() !== rotation) {
1044
+ marker.setRotation(rotation);
1045
+ }
1046
+ if (marker.getRotationAlignment() !== rotationAlignment) {
1047
+ marker.setRotationAlignment(rotationAlignment);
1048
+ }
1049
+ if (marker.getPitchAlignment() !== pitchAlignment) {
1050
+ marker.setPitchAlignment(pitchAlignment);
1051
+ }
1052
+ if (marker.getPopup() !== popup) {
1053
+ marker.setPopup(popup);
1054
+ }
1055
+ const classNameDiff = compareClassNames(prevClassNameRef.current, className);
1056
+ if (classNameDiff) {
1057
+ for (const c of classNameDiff) {
1058
+ marker.toggleClassName(c);
1059
+ }
1060
+ }
1061
+ prevClassNameRef.current = className;
1062
+ });
1030
1063
  return createPortal(props.children, marker.getElement());
1031
1064
  })
1032
1065
  );
1033
1066
 
1034
1067
  // src/components/popup.ts
1035
1068
  import { createPortal as createPortal2 } from "react-dom";
1036
- import {
1037
- useImperativeHandle as useImperativeHandle3,
1038
- useEffect as useEffect7,
1039
- useMemo as useMemo5,
1040
- useRef as useRef3,
1041
- useContext as useContext5,
1042
- forwardRef as forwardRef3,
1043
- memo as memo4
1044
- } from "react";
1069
+ import { useImperativeHandle as useImperativeHandle3, useEffect as useEffect7, useMemo as useMemo5, useContext as useContext5, forwardRef as forwardRef3, memo as memo4 } from "react";
1045
1070
  var Popup = memo4(
1046
1071
  forwardRef3((props, ref) => {
1047
1072
  const { map, mapLib } = useContext5(MapContext);
1048
1073
  const container = useMemo5(() => {
1049
1074
  return document.createElement("div");
1050
1075
  }, []);
1051
- const thisRef = useRef3({ props });
1052
1076
  const popup = useMemo5(() => {
1053
1077
  const options = { ...props };
1054
1078
  const pp = new mapLib.Popup(options);
1055
1079
  pp.setLngLat([props.longitude, props.latitude]);
1056
- pp.once("open", (e) => {
1057
- thisRef.current.props.onOpen?.(e);
1058
- });
1059
1080
  return pp;
1060
1081
  }, []);
1082
+ useImperativeHandle3(ref, () => popup, []);
1061
1083
  useEffect7(() => {
1084
+ const onOpen = (e) => {
1085
+ props.onOpen?.(e);
1086
+ };
1062
1087
  const onClose = (e) => {
1063
- thisRef.current.props.onClose?.(e);
1088
+ props.onClose?.(e);
1064
1089
  };
1090
+ popup.on("open", onOpen);
1065
1091
  popup.on("close", onClose);
1066
1092
  popup.setDOMContent(container).addTo(map.getMap());
1067
1093
  return () => {
1094
+ popup.off("open", onOpen);
1068
1095
  popup.off("close", onClose);
1069
1096
  if (popup.isOpen()) {
1070
1097
  popup.remove();
@@ -1074,30 +1101,34 @@ var Popup = memo4(
1074
1101
  useEffect7(() => {
1075
1102
  applyReactStyle(popup.getElement(), props.style);
1076
1103
  }, [props.style]);
1077
- useImperativeHandle3(ref, () => popup, []);
1078
- if (popup.isOpen()) {
1079
- const oldProps = thisRef.current.props;
1080
- if (popup.getLngLat().lng !== props.longitude || popup.getLngLat().lat !== props.latitude) {
1081
- popup.setLngLat([props.longitude, props.latitude]);
1104
+ useEffect7(() => {
1105
+ if (popup.isOpen()) {
1106
+ if (popup.getLngLat().lng !== props.longitude || popup.getLngLat().lat !== props.latitude) {
1107
+ popup.setLngLat([props.longitude, props.latitude]);
1108
+ }
1082
1109
  }
1083
- if (props.offset && !deepEqual(oldProps.offset, props.offset)) {
1110
+ }, [props.longitude, props.latitude]);
1111
+ useEffect7(() => {
1112
+ if (popup.isOpen() && props.offset) {
1084
1113
  popup.setOffset(props.offset);
1085
1114
  }
1086
- if (oldProps.anchor !== props.anchor || oldProps.maxWidth !== props.maxWidth) {
1087
- popup.options.anchor = props.anchor;
1115
+ }, [props.offset]);
1116
+ useEffect7(() => {
1117
+ if (popup.isOpen() && props.maxWidth !== void 0) {
1088
1118
  popup.setMaxWidth(props.maxWidth);
1089
1119
  }
1090
- const classNameDiff = compareClassNames(
1091
- oldProps.className,
1092
- props.className
1093
- );
1094
- if (classNameDiff) {
1095
- for (const c of classNameDiff) {
1096
- popup.toggleClassName(c);
1120
+ }, [props.maxWidth]);
1121
+ useEffect7(() => {
1122
+ if (popup.isOpen() && props.className) {
1123
+ const currentClassName = popup.options.className || "";
1124
+ const classNameDiff = compareClassNames(currentClassName, props.className);
1125
+ if (classNameDiff) {
1126
+ for (const c of classNameDiff) {
1127
+ popup.toggleClassName(c);
1128
+ }
1097
1129
  }
1098
1130
  }
1099
- thisRef.current.props = props;
1100
- }
1131
+ }, [props.className]);
1101
1132
  return createPortal2(props.children, container);
1102
1133
  })
1103
1134
  );
@@ -1119,15 +1150,9 @@ function _FullscreenControl(props) {
1119
1150
  var FullscreenControl = memo5(_FullscreenControl);
1120
1151
 
1121
1152
  // src/components/geolocate-control.ts
1122
- import {
1123
- useImperativeHandle as useImperativeHandle4,
1124
- useRef as useRef4,
1125
- useEffect as useEffect9,
1126
- forwardRef as forwardRef4,
1127
- memo as memo6
1128
- } from "react";
1153
+ import { useImperativeHandle as useImperativeHandle4, useRef as useRef3, useEffect as useEffect9, forwardRef as forwardRef4, memo as memo6 } from "react";
1129
1154
  function _GeolocateControl(props, ref) {
1130
- const thisRef = useRef4({ props });
1155
+ const thisRef = useRef3({ props });
1131
1156
  const ctrl = useControl(
1132
1157
  ({ mapLib }) => {
1133
1158
  const gc = new mapLib.GeolocateControl(props);
@@ -1163,9 +1188,7 @@ function _GeolocateControl(props, ref) {
1163
1188
  }, [props.style]);
1164
1189
  return null;
1165
1190
  }
1166
- var GeolocateControl = memo6(
1167
- forwardRef4(_GeolocateControl)
1168
- );
1191
+ var GeolocateControl = memo6(forwardRef4(_GeolocateControl));
1169
1192
 
1170
1193
  // src/components/navigation-control.ts
1171
1194
  import { useEffect as useEffect10, memo as memo7 } from "react";
@@ -1181,24 +1204,26 @@ function _NavigationControl(props) {
1181
1204
  var NavigationControl = memo7(_NavigationControl);
1182
1205
 
1183
1206
  // src/components/scale-control.ts
1184
- import { useEffect as useEffect11, useRef as useRef5, memo as memo8 } from "react";
1207
+ import { useEffect as useEffect11, useRef as useRef4, memo as memo8 } from "react";
1185
1208
  function _ScaleControl(props) {
1186
1209
  const ctrl = useControl(({ mapLib }) => new mapLib.ScaleControl(props), {
1187
1210
  position: props.position
1188
1211
  });
1189
- const propsRef = useRef5(props);
1212
+ const propsRef = useRef4(props);
1190
1213
  const prevProps = propsRef.current;
1191
1214
  propsRef.current = props;
1192
- const { style } = props;
1193
- if (props.maxWidth !== void 0 && props.maxWidth !== prevProps.maxWidth) {
1194
- ctrl.options.maxWidth = props.maxWidth;
1195
- }
1196
- if (props.unit !== void 0 && props.unit !== prevProps.unit) {
1197
- ctrl.setUnit(props.unit);
1198
- }
1215
+ const { style, maxWidth, unit } = props;
1216
+ useEffect11(() => {
1217
+ if (maxWidth !== void 0 && maxWidth !== prevProps.maxWidth) {
1218
+ ctrl.options.maxWidth = maxWidth;
1219
+ }
1220
+ if (unit !== void 0 && unit !== prevProps.unit) {
1221
+ ctrl.setUnit(unit);
1222
+ }
1223
+ }, [ctrl, maxWidth, unit, prevProps.maxWidth, prevProps.unit]);
1199
1224
  useEffect11(() => {
1200
1225
  applyReactStyle(ctrl._container, style);
1201
- }, [style]);
1226
+ }, [ctrl, style]);
1202
1227
  return null;
1203
1228
  }
1204
1229
  var ScaleControl = memo8(_ScaleControl);
@@ -1223,8 +1248,11 @@ import {
1223
1248
  useEffect as useEffect13,
1224
1249
  useMemo as useMemo6,
1225
1250
  useState as useState3,
1226
- useRef as useRef6,
1227
- cloneElement
1251
+ useRef as useRef5,
1252
+ cloneElement,
1253
+ memo as memo10,
1254
+ useId,
1255
+ useImperativeHandle as useImperativeHandle5
1228
1256
  } from "react";
1229
1257
 
1230
1258
  // src/utils/assert.ts
@@ -1235,9 +1263,9 @@ function assert(condition, message) {
1235
1263
  }
1236
1264
 
1237
1265
  // src/components/source.ts
1238
- var sourceCounter = 0;
1239
1266
  function createSource(map, id, props) {
1240
- if (map.style && map.style._loaded) {
1267
+ const mapInternal = map;
1268
+ if (mapInternal.style && mapInternal.style._loaded) {
1241
1269
  const options = { ...props };
1242
1270
  delete options.id;
1243
1271
  delete options.children;
@@ -1262,33 +1290,43 @@ function updateSource(source, props, prevProps) {
1262
1290
  }
1263
1291
  const type = props.type;
1264
1292
  if (type === "geojson") {
1293
+ ;
1265
1294
  source.setData(props.data);
1266
1295
  } else if (type === "image") {
1296
+ ;
1267
1297
  source.updateImage({
1268
1298
  url: props.url,
1269
1299
  coordinates: props.coordinates
1270
1300
  });
1271
1301
  } else {
1302
+ const sourceWithMethods = source;
1303
+ const propsWithOptional = props;
1272
1304
  switch (changedKey) {
1273
1305
  case "coordinates":
1274
- source.setCoordinates?.(props.coordinates);
1306
+ sourceWithMethods.setCoordinates?.(propsWithOptional.coordinates);
1275
1307
  break;
1276
1308
  case "url":
1277
- source.setUrl?.(props.url);
1309
+ sourceWithMethods.setUrl?.(propsWithOptional.url);
1278
1310
  break;
1279
1311
  case "tiles":
1280
- source.setTiles?.(props.tiles);
1312
+ sourceWithMethods.setTiles?.(propsWithOptional.tiles);
1281
1313
  break;
1282
1314
  default:
1283
1315
  console.warn(`Unable to update <Source> prop: ${changedKey}`);
1284
1316
  }
1285
1317
  }
1286
1318
  }
1287
- function Source(props) {
1319
+ function _Source(props, ref) {
1288
1320
  const map = useContext6(MapContext).map.getMap();
1289
- const propsRef = useRef6(props);
1321
+ const propsRef = useRef5(props);
1322
+ const sourceRef = useRef5(null);
1290
1323
  const [, setStyleLoaded] = useState3(0);
1291
- const id = useMemo6(() => props.id || `jsx-source-${sourceCounter++}`, []);
1324
+ const generatedId = useId();
1325
+ const id = useMemo6(
1326
+ () => props.id || `jsx-source-${generatedId.replace(/:/g, "-")}`,
1327
+ // Empty deps - id is set once on mount and should not change
1328
+ []
1329
+ );
1292
1330
  useEffect13(() => {
1293
1331
  if (map) {
1294
1332
  const forceUpdate = () => setTimeout(() => setStyleLoaded((version) => version + 1), 0);
@@ -1296,11 +1334,13 @@ function Source(props) {
1296
1334
  forceUpdate();
1297
1335
  return () => {
1298
1336
  map.off("styledata", forceUpdate);
1299
- if (map.style && map.style._loaded && map.getSource(id)) {
1337
+ const mapInternal2 = map;
1338
+ if (mapInternal2.style && mapInternal2.style._loaded && map.getSource(id)) {
1300
1339
  const allLayers = map.getStyle()?.layers;
1301
1340
  if (allLayers) {
1302
1341
  for (const layer of allLayers) {
1303
- if (layer.source === id) {
1342
+ const layerWithSource = layer;
1343
+ if (layerWithSource.source === id) {
1304
1344
  map.removeLayer(layer.id);
1305
1345
  }
1306
1346
  }
@@ -1311,13 +1351,16 @@ function Source(props) {
1311
1351
  }
1312
1352
  return void 0;
1313
1353
  }, [map]);
1314
- let source = map && map.style && map.getSource(id);
1354
+ const mapInternal = map;
1355
+ let source = map && mapInternal.style && map.getSource(id);
1315
1356
  if (source) {
1316
1357
  updateSource(source, props, propsRef.current);
1317
1358
  } else {
1318
1359
  source = createSource(map, id, props);
1319
1360
  }
1361
+ sourceRef.current = source;
1320
1362
  propsRef.current = props;
1363
+ useImperativeHandle5(ref, () => sourceRef.current, [source]);
1321
1364
  return source && React4.Children.map(
1322
1365
  props.children,
1323
1366
  (child) => child && cloneElement(child, {
@@ -1325,21 +1368,103 @@ function Source(props) {
1325
1368
  })
1326
1369
  ) || null;
1327
1370
  }
1371
+ var Source = memo10(React4.forwardRef(_Source));
1372
+
1373
+ // src/components/canvas-source.ts
1374
+ import * as React5 from "react";
1375
+ import { useContext as useContext7, useEffect as useEffect14, useMemo as useMemo7, useRef as useRef6, memo as memo11 } from "react";
1376
+ function _CanvasSource(props) {
1377
+ const map = useContext7(MapContext).map.getMap();
1378
+ const propsRef = useRef6(props);
1379
+ const id = useMemo7(() => props.id || `canvas-source-${Date.now()}`, [props.id]);
1380
+ useEffect14(() => {
1381
+ if (!map) return void 0;
1382
+ const mapInternal2 = map;
1383
+ let source = null;
1384
+ const addSource = () => {
1385
+ if (!mapInternal2.style || !mapInternal2.style._loaded) return;
1386
+ if (map.getSource(id)) return;
1387
+ const { coordinates, canvas, animate } = props;
1388
+ map.addSource(id, {
1389
+ type: "canvas",
1390
+ coordinates,
1391
+ canvas,
1392
+ animate: animate || false
1393
+ });
1394
+ source = map.getSource(id);
1395
+ };
1396
+ const updateSource2 = () => {
1397
+ if (!source) return;
1398
+ const { coordinates, canvas } = props;
1399
+ const prevProps = propsRef.current;
1400
+ if (JSON.stringify(coordinates) !== JSON.stringify(prevProps.coordinates)) {
1401
+ const sourceWithMethods = source;
1402
+ sourceWithMethods.setCoordinates?.(coordinates);
1403
+ }
1404
+ };
1405
+ if (mapInternal2.style && mapInternal2.style._loaded) {
1406
+ addSource();
1407
+ } else {
1408
+ map.once("styledata", addSource);
1409
+ }
1410
+ return () => {
1411
+ map.off("styledata", addSource);
1412
+ const mapInternalForCleanup = map;
1413
+ if (mapInternalForCleanup.style && mapInternalForCleanup.style._loaded && map.getSource(id)) {
1414
+ const allLayers = map.getStyle()?.layers;
1415
+ if (allLayers) {
1416
+ for (const layer of allLayers) {
1417
+ if (layer.source === id) {
1418
+ map.removeLayer(layer.id);
1419
+ }
1420
+ }
1421
+ }
1422
+ map.removeSource(id);
1423
+ }
1424
+ };
1425
+ }, [map, id]);
1426
+ useEffect14(() => {
1427
+ if (!map) return;
1428
+ const source = map.getSource(id);
1429
+ if (!source) return;
1430
+ const { coordinates } = props;
1431
+ const prevProps = propsRef.current;
1432
+ if (JSON.stringify(coordinates) !== JSON.stringify(prevProps.coordinates)) {
1433
+ const sourceWithMethods = source;
1434
+ sourceWithMethods.setCoordinates?.(coordinates);
1435
+ }
1436
+ propsRef.current = props;
1437
+ }, [map, id, props.coordinates, props.canvas]);
1438
+ if (!map) return null;
1439
+ const mapInternal = map;
1440
+ if (!mapInternal.style || !mapInternal.style._loaded || !map.getSource(id)) {
1441
+ return null;
1442
+ }
1443
+ return props.children && React5.Children.map(
1444
+ props.children,
1445
+ (child) => child && React5.cloneElement(child, {
1446
+ source: id
1447
+ })
1448
+ ) || null;
1449
+ }
1450
+ var CanvasSource = memo11(_CanvasSource);
1328
1451
 
1329
1452
  // src/components/layer.ts
1330
- import { useContext as useContext7, useEffect as useEffect14, useMemo as useMemo7, useState as useState4, useRef as useRef7 } from "react";
1453
+ import { useContext as useContext8, useEffect as useEffect15, useMemo as useMemo8, useState as useState5, useRef as useRef7, memo as memo12, useId as useId2 } from "react";
1331
1454
  function updateLayer(map, id, props, prevProps) {
1332
1455
  assert(props.id === prevProps.id, "layer id changed");
1333
1456
  assert(props.type === prevProps.type, "layer type changed");
1334
1457
  if (props.type === "custom" || prevProps.type === "custom") {
1335
1458
  return;
1336
1459
  }
1337
- const { layout = {}, paint = {}, filter, minzoom, maxzoom, beforeId } = props;
1338
- if (beforeId !== prevProps.beforeId) {
1460
+ const propsWithFilter = props;
1461
+ const prevPropsWithFilter = prevProps;
1462
+ const { layout = {}, paint = {}, filter, minzoom, maxzoom, beforeId } = propsWithFilter;
1463
+ if (beforeId !== prevPropsWithFilter.beforeId) {
1339
1464
  map.moveLayer(id, beforeId);
1340
1465
  }
1341
- if (layout !== prevProps.layout) {
1342
- const prevLayout = prevProps.layout || {};
1466
+ if (layout !== prevPropsWithFilter.layout) {
1467
+ const prevLayout = prevPropsWithFilter.layout || {};
1343
1468
  for (const key in layout) {
1344
1469
  if (!deepEqual(layout[key], prevLayout[key])) {
1345
1470
  map.setLayoutProperty(id, key, layout[key]);
@@ -1351,8 +1476,8 @@ function updateLayer(map, id, props, prevProps) {
1351
1476
  }
1352
1477
  }
1353
1478
  }
1354
- if (paint !== prevProps.paint) {
1355
- const prevPaint = prevProps.paint || {};
1479
+ if (paint !== prevPropsWithFilter.paint) {
1480
+ const prevPaint = prevPropsWithFilter.paint || {};
1356
1481
  for (const key in paint) {
1357
1482
  if (!deepEqual(paint[key], prevPaint[key])) {
1358
1483
  map.setPaintProperty(id, key, paint[key]);
@@ -1364,41 +1489,151 @@ function updateLayer(map, id, props, prevProps) {
1364
1489
  }
1365
1490
  }
1366
1491
  }
1367
- if (!deepEqual(filter, prevProps.filter)) {
1368
- map.setFilter(id, filter);
1492
+ if (!deepEqual(filter, prevPropsWithFilter.filter)) {
1493
+ map.setFilter(id, filter ?? null);
1369
1494
  }
1370
- if (minzoom !== prevProps.minzoom || maxzoom !== prevProps.maxzoom) {
1495
+ if (minzoom !== prevPropsWithFilter.minzoom || maxzoom !== prevPropsWithFilter.maxzoom) {
1371
1496
  map.setLayerZoomRange(id, minzoom, maxzoom);
1372
1497
  }
1373
1498
  }
1374
1499
  function createLayer(map, id, props) {
1375
- if (map.style && map.style._loaded && (!("source" in props) || map.getSource(props.source))) {
1500
+ const mapInternal = map;
1501
+ if (mapInternal.style && mapInternal.style._loaded && (!("source" in props) || map.getSource(props.source))) {
1376
1502
  const options = { ...props, id };
1377
1503
  delete options.beforeId;
1378
1504
  map.addLayer(options, props.beforeId);
1379
1505
  }
1380
1506
  }
1381
- var layerCounter = 0;
1382
- function Layer(props) {
1383
- const map = useContext7(MapContext).map.getMap();
1507
+ function _Layer(props) {
1508
+ const map = useContext8(MapContext).map.getMap();
1384
1509
  const propsRef = useRef7(props);
1385
- const [, setStyleLoaded] = useState4(0);
1386
- const id = useMemo7(() => props.id || `jsx-layer-${layerCounter++}`, []);
1387
- useEffect14(() => {
1510
+ const [, setStyleLoaded] = useState5(0);
1511
+ const generatedId = useId2();
1512
+ const id = useMemo8(
1513
+ () => props.id || `jsx-layer-${generatedId.replace(/:/g, "-")}`,
1514
+ // Empty deps - id is set once on mount and should not change
1515
+ []
1516
+ );
1517
+ const {
1518
+ onClick,
1519
+ onMouseEnter,
1520
+ onMouseLeave,
1521
+ onMouseMove,
1522
+ onMouseDown,
1523
+ onMouseUp,
1524
+ onContextMenu,
1525
+ onDoubleClick
1526
+ } = props;
1527
+ const callbacksRef = useRef7({
1528
+ onClick,
1529
+ onMouseEnter,
1530
+ onMouseLeave,
1531
+ onMouseMove,
1532
+ onMouseDown,
1533
+ onMouseUp,
1534
+ onContextMenu,
1535
+ onDoubleClick
1536
+ });
1537
+ useEffect15(() => {
1538
+ callbacksRef.current = {
1539
+ onClick,
1540
+ onMouseEnter,
1541
+ onMouseLeave,
1542
+ onMouseMove,
1543
+ onMouseDown,
1544
+ onMouseUp,
1545
+ onContextMenu,
1546
+ onDoubleClick
1547
+ };
1548
+ }, [
1549
+ onClick,
1550
+ onMouseEnter,
1551
+ onMouseLeave,
1552
+ onMouseMove,
1553
+ onMouseDown,
1554
+ onMouseUp,
1555
+ onContextMenu,
1556
+ onDoubleClick
1557
+ ]);
1558
+ useEffect15(() => {
1388
1559
  if (map) {
1389
1560
  const forceUpdate = () => setStyleLoaded((version) => version + 1);
1390
1561
  map.on("styledata", forceUpdate);
1391
1562
  forceUpdate();
1392
1563
  return () => {
1393
1564
  map.off("styledata", forceUpdate);
1394
- if (map.style && map.style._loaded && map.getLayer(id)) {
1565
+ const mapInternal2 = map;
1566
+ if (mapInternal2.style && mapInternal2.style._loaded && map.getLayer(id)) {
1395
1567
  map.removeLayer(id);
1396
1568
  }
1397
1569
  };
1398
1570
  }
1399
1571
  return void 0;
1400
1572
  }, [map]);
1401
- const layer = map && map.style && map.getLayer(id);
1573
+ useEffect15(() => {
1574
+ if (!map) return void 0;
1575
+ const hasEventHandler = onClick || onMouseEnter || onMouseLeave || onMouseMove || onMouseDown || onMouseUp || onContextMenu || onDoubleClick;
1576
+ if (!hasEventHandler) return void 0;
1577
+ const handleClick = (e) => {
1578
+ callbacksRef.current.onClick?.(e);
1579
+ };
1580
+ const handleMouseEnter = (e) => {
1581
+ callbacksRef.current.onMouseEnter?.(e);
1582
+ if (callbacksRef.current.onClick) {
1583
+ map.getCanvas().style.cursor = "pointer";
1584
+ }
1585
+ };
1586
+ const handleMouseLeave = () => {
1587
+ callbacksRef.current.onMouseLeave?.();
1588
+ map.getCanvas().style.cursor = "";
1589
+ };
1590
+ const handleMouseMove = (e) => {
1591
+ callbacksRef.current.onMouseMove?.(e);
1592
+ };
1593
+ const handleMouseDown = (e) => {
1594
+ callbacksRef.current.onMouseDown?.(e);
1595
+ };
1596
+ const handleMouseUp = (e) => {
1597
+ callbacksRef.current.onMouseUp?.(e);
1598
+ };
1599
+ const handleContextMenu = (e) => {
1600
+ callbacksRef.current.onContextMenu?.(e);
1601
+ };
1602
+ const handleDoubleClick = (e) => {
1603
+ callbacksRef.current.onDoubleClick?.(e);
1604
+ };
1605
+ if (onClick) map.on("click", id, handleClick);
1606
+ if (onMouseEnter) map.on("mouseenter", id, handleMouseEnter);
1607
+ if (onMouseLeave) map.on("mouseleave", id, handleMouseLeave);
1608
+ if (onMouseMove) map.on("mousemove", id, handleMouseMove);
1609
+ if (onMouseDown) map.on("mousedown", id, handleMouseDown);
1610
+ if (onMouseUp) map.on("mouseup", id, handleMouseUp);
1611
+ if (onContextMenu) map.on("contextmenu", id, handleContextMenu);
1612
+ if (onDoubleClick) map.on("dblclick", id, handleDoubleClick);
1613
+ return () => {
1614
+ if (onClick) map.off("click", id, handleClick);
1615
+ if (onMouseEnter) map.off("mouseenter", id, handleMouseEnter);
1616
+ if (onMouseLeave) map.off("mouseleave", id, handleMouseLeave);
1617
+ if (onMouseMove) map.off("mousemove", id, handleMouseMove);
1618
+ if (onMouseDown) map.off("mousedown", id, handleMouseDown);
1619
+ if (onMouseUp) map.off("mouseup", id, handleMouseUp);
1620
+ if (onContextMenu) map.off("contextmenu", id, handleContextMenu);
1621
+ if (onDoubleClick) map.off("dblclick", id, handleDoubleClick);
1622
+ };
1623
+ }, [
1624
+ map,
1625
+ id,
1626
+ onClick,
1627
+ onMouseEnter,
1628
+ onMouseLeave,
1629
+ onMouseMove,
1630
+ onMouseDown,
1631
+ onMouseUp,
1632
+ onContextMenu,
1633
+ onDoubleClick
1634
+ ]);
1635
+ const mapInternal = map;
1636
+ const layer = map && mapInternal.style && map.getLayer(id);
1402
1637
  if (layer) {
1403
1638
  try {
1404
1639
  updateLayer(map, id, props, propsRef.current);
@@ -1411,18 +1646,769 @@ function Layer(props) {
1411
1646
  propsRef.current = props;
1412
1647
  return null;
1413
1648
  }
1649
+ var Layer = memo12(_Layer);
1650
+
1651
+ // src/components/draw-control.ts
1652
+ import { useEffect as useEffect16, useMemo as useMemo9, memo as memo13, useRef as useRef8, useContext as useContext9 } from "react";
1653
+ import MapboxDraw from "maplibre-gl-draw";
1654
+ var defaultDrawOptions = {
1655
+ displayControlsDefault: false,
1656
+ controls: {
1657
+ polygon: true,
1658
+ trash: true
1659
+ }
1660
+ };
1661
+ function _DrawControl(props) {
1662
+ const {
1663
+ position,
1664
+ style,
1665
+ onDrawCreate,
1666
+ onDrawDelete,
1667
+ onDrawUpdate,
1668
+ onDrawSelectionChange,
1669
+ onDrawModeChange,
1670
+ onDrawCombine,
1671
+ onDrawUncombine,
1672
+ onDrawRender,
1673
+ ...drawOptions
1674
+ } = props;
1675
+ const context = useContext9(MapContext);
1676
+ if (!context) {
1677
+ throw new Error("DrawControl must be used within a Map component");
1678
+ }
1679
+ const options = useMemo9(
1680
+ () => ({
1681
+ ...defaultDrawOptions,
1682
+ ...drawOptions,
1683
+ controls: {
1684
+ ...defaultDrawOptions.controls,
1685
+ ...drawOptions.controls
1686
+ }
1687
+ }),
1688
+ [
1689
+ drawOptions.displayControlsDefault,
1690
+ drawOptions.controls,
1691
+ drawOptions.styles,
1692
+ drawOptions.modes,
1693
+ drawOptions.defaultMode
1694
+ ]
1695
+ );
1696
+ const optionsKey = useMemo9(() => JSON.stringify(options), [options]);
1697
+ const callbacksRef = useRef8({
1698
+ onDrawCreate,
1699
+ onDrawDelete,
1700
+ onDrawUpdate,
1701
+ onDrawSelectionChange,
1702
+ onDrawModeChange,
1703
+ onDrawCombine,
1704
+ onDrawUncombine,
1705
+ onDrawRender
1706
+ });
1707
+ useEffect16(() => {
1708
+ callbacksRef.current = {
1709
+ onDrawCreate,
1710
+ onDrawDelete,
1711
+ onDrawUpdate,
1712
+ onDrawSelectionChange,
1713
+ onDrawModeChange,
1714
+ onDrawCombine,
1715
+ onDrawUncombine,
1716
+ onDrawRender
1717
+ };
1718
+ }, [
1719
+ onDrawCreate,
1720
+ onDrawDelete,
1721
+ onDrawUpdate,
1722
+ onDrawSelectionChange,
1723
+ onDrawModeChange,
1724
+ onDrawCombine,
1725
+ onDrawUncombine,
1726
+ onDrawRender
1727
+ ]);
1728
+ const ctrlRef = useRef8(null);
1729
+ const listenersRef = useRef8({});
1730
+ useEffect16(() => {
1731
+ const { map } = context;
1732
+ if (!map) return;
1733
+ const mapInstance = map.getMap();
1734
+ if (!mapInstance) return;
1735
+ const DrawClass = MapboxDraw;
1736
+ const resetCursorIfNeeded = () => {
1737
+ if (ctrlRef.current) {
1738
+ const currentMode = ctrlRef.current.getMode();
1739
+ if (currentMode === "simple_select") {
1740
+ mapInstance.getCanvas().style.cursor = "";
1741
+ }
1742
+ }
1743
+ };
1744
+ const handleCreate = (e) => {
1745
+ resetCursorIfNeeded();
1746
+ callbacksRef.current.onDrawCreate?.(e);
1747
+ };
1748
+ const handleUpdate = (e) => {
1749
+ resetCursorIfNeeded();
1750
+ callbacksRef.current.onDrawUpdate?.(e);
1751
+ };
1752
+ const handleDelete = (e) => {
1753
+ resetCursorIfNeeded();
1754
+ callbacksRef.current.onDrawDelete?.(e);
1755
+ };
1756
+ const handleSelectionChange = (e) => {
1757
+ resetCursorIfNeeded();
1758
+ callbacksRef.current.onDrawSelectionChange?.(e);
1759
+ };
1760
+ const handleModeChange = (e) => {
1761
+ resetCursorIfNeeded();
1762
+ callbacksRef.current.onDrawModeChange?.(e);
1763
+ };
1764
+ const handleCombine = (e) => {
1765
+ callbacksRef.current.onDrawCombine?.(e);
1766
+ };
1767
+ const handleUncombine = (e) => {
1768
+ callbacksRef.current.onDrawUncombine?.(e);
1769
+ };
1770
+ const handleRender = (e) => {
1771
+ callbacksRef.current.onDrawRender?.(e);
1772
+ };
1773
+ const ctrl = new DrawClass(options);
1774
+ ctrlRef.current = ctrl;
1775
+ map.addControl(ctrl, position);
1776
+ listenersRef.current = {
1777
+ handleCreate,
1778
+ handleUpdate,
1779
+ handleDelete,
1780
+ handleSelectionChange,
1781
+ handleModeChange,
1782
+ handleCombine,
1783
+ handleUncombine,
1784
+ handleRender
1785
+ };
1786
+ mapInstance.on("draw.create", handleCreate);
1787
+ mapInstance.on("draw.update", handleUpdate);
1788
+ mapInstance.on("draw.delete", handleDelete);
1789
+ mapInstance.on("draw.selectionchange", handleSelectionChange);
1790
+ mapInstance.on("draw.modechange", handleModeChange);
1791
+ mapInstance.on("draw.combine", handleCombine);
1792
+ mapInstance.on("draw.uncombine", handleUncombine);
1793
+ mapInstance.on("draw.render", handleRender);
1794
+ return () => {
1795
+ if (listenersRef.current.handleCreate) {
1796
+ mapInstance.off("draw.create", listenersRef.current.handleCreate);
1797
+ }
1798
+ if (listenersRef.current.handleUpdate) {
1799
+ mapInstance.off("draw.update", listenersRef.current.handleUpdate);
1800
+ }
1801
+ if (listenersRef.current.handleDelete) {
1802
+ mapInstance.off("draw.delete", listenersRef.current.handleDelete);
1803
+ }
1804
+ if (listenersRef.current.handleSelectionChange) {
1805
+ mapInstance.off("draw.selectionchange", listenersRef.current.handleSelectionChange);
1806
+ }
1807
+ if (listenersRef.current.handleModeChange) {
1808
+ mapInstance.off("draw.modechange", listenersRef.current.handleModeChange);
1809
+ }
1810
+ if (listenersRef.current.handleCombine) {
1811
+ mapInstance.off("draw.combine", listenersRef.current.handleCombine);
1812
+ }
1813
+ if (listenersRef.current.handleUncombine) {
1814
+ mapInstance.off("draw.uncombine", listenersRef.current.handleUncombine);
1815
+ }
1816
+ if (listenersRef.current.handleRender) {
1817
+ mapInstance.off("draw.render", listenersRef.current.handleRender);
1818
+ }
1819
+ if (ctrlRef.current && map.hasControl(ctrlRef.current)) {
1820
+ map.removeControl(ctrlRef.current);
1821
+ }
1822
+ ctrlRef.current = null;
1823
+ };
1824
+ }, [context, optionsKey, position]);
1825
+ return null;
1826
+ }
1827
+ var DrawControl = memo13(_DrawControl);
1828
+
1829
+ // src/components/globe-control.ts
1830
+ import { useEffect as useEffect17, memo as memo14, useRef as useRef9 } from "react";
1831
+ var GLOBE_SVG = `<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2">
1832
+ <circle cx="12" cy="12" r="9" fill="none"/>
1833
+ <path d="M12 21a9 9-9 0 0-9 9-9 0 0 9h0c2.2a8.2 2.3 5.1 5.8-5.5c-.4-.4-.5-.9-.5-1.5v-1.3c0-2.3 1.8-4.2 4-4.5V5.5c-1.8.5-3.5 2-4.5 2.8 0 5.2 2.3 5.2 5 0z"/>
1834
+ <path d="M12 3c-2.8 0-5.2 2.3-5.2 5h2c0-1.5.1-1.1.5-1.5L5.8 9 2.3 5.1 8.2 2c.4 0 .9-.5 1.5-.5h1.3c2.3 0 4.2-1.8 4.5-4h-2c0 1.5-1.8 3.5-4 4.5V21c2.8 0 5.2-2.3 5.2-5h-2c0 1.5-.1 1.1-.5 1.5L18.2 15 14.8l2.7-5.1c-.4 0-.9.5-1.5.5h-1.3c-2.3 0-4.2 1.8-4.5 4h2c0-1.5 1.8-3.5 4-4.5V3z"/>
1835
+ </svg>`;
1836
+ var MAP_SVG = `<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2">
1837
+ <rect x="3" y="3" width="18" height="18" rx="2" fill="none"/>
1838
+ <path d="M3 9h18M3 15h18M9 3v18M15 3v18"/>
1839
+ </svg>`;
1840
+ var GlobeControlImpl = class {
1841
+ constructor(options, callbacks) {
1842
+ this._map = null;
1843
+ this._isGlobe = false;
1844
+ this._options = options;
1845
+ this._onProjectionChange = callbacks.onProjectionChange;
1846
+ this._container = document.createElement("div");
1847
+ this._container.className = "maplibregl-ctrl maplibregl-ctrl-group";
1848
+ this._button = this._createButton();
1849
+ this._container.appendChild(this._button);
1850
+ }
1851
+ _createButton() {
1852
+ const button = this._options.buttonElement || document.createElement("button");
1853
+ if (!this._options.buttonElement) {
1854
+ button.className = this._options.buttonClassName || "maplibregl-ctrl-globe";
1855
+ button.type = "button";
1856
+ button.title = this._options.buttonTitle || "Toggle Globe View";
1857
+ button.setAttribute("aria-label", "Toggle Globe View");
1858
+ button.innerHTML = this._isGlobe ? MAP_SVG : GLOBE_SVG;
1859
+ Object.assign(button.style, {
1860
+ padding: "5px",
1861
+ border: "none",
1862
+ background: "white",
1863
+ cursor: "pointer",
1864
+ borderRadius: "4px",
1865
+ display: "flex",
1866
+ alignItems: "center",
1867
+ justifyContent: "center",
1868
+ ...this._options.buttonStyle
1869
+ });
1870
+ }
1871
+ button.addEventListener("click", () => this._toggleGlobe());
1872
+ return button;
1873
+ }
1874
+ _toggleGlobe() {
1875
+ if (!this._map) return;
1876
+ this._isGlobe = !this._isGlobe;
1877
+ this._button.innerHTML = this._isGlobe ? MAP_SVG : GLOBE_SVG;
1878
+ this._button.title = this._isGlobe ? "Switch to Map View" : "Switch to Globe View";
1879
+ try {
1880
+ const projection = this._isGlobe ? { type: "globe" } : { type: "mercator" };
1881
+ this._map.setProjection(projection);
1882
+ this._onProjectionChange?.(this._isGlobe);
1883
+ } catch (error) {
1884
+ console.warn("GlobeControl: setProjection not available", error);
1885
+ }
1886
+ }
1887
+ onAdd(map) {
1888
+ this._map = map;
1889
+ try {
1890
+ const currentProjection = map.getProjection?.();
1891
+ this._isGlobe = currentProjection?.type === "globe";
1892
+ this._button.innerHTML = this._isGlobe ? MAP_SVG : GLOBE_SVG;
1893
+ } catch {
1894
+ this._isGlobe = false;
1895
+ }
1896
+ return this._container;
1897
+ }
1898
+ onRemove() {
1899
+ this._container.parentNode?.removeChild(this._container);
1900
+ this._map = null;
1901
+ }
1902
+ /**
1903
+ * Check if currently in globe view
1904
+ */
1905
+ isGlobe() {
1906
+ return this._isGlobe;
1907
+ }
1908
+ /**
1909
+ * Set the projection programmatically
1910
+ */
1911
+ setGlobe(isGlobe) {
1912
+ if (this._isGlobe !== isGlobe) {
1913
+ this._toggleGlobe();
1914
+ }
1915
+ }
1916
+ };
1917
+ function _GlobeControl(props) {
1918
+ const { position, onProjectionChange, ...options } = props;
1919
+ const callbacksRef = useRef9({ onProjectionChange });
1920
+ useEffect17(() => {
1921
+ callbacksRef.current = { onProjectionChange };
1922
+ }, [onProjectionChange]);
1923
+ useControl(
1924
+ () => {
1925
+ return new GlobeControlImpl(options, {
1926
+ onProjectionChange: (isGlobe) => callbacksRef.current.onProjectionChange?.(isGlobe)
1927
+ });
1928
+ },
1929
+ { position }
1930
+ );
1931
+ return null;
1932
+ }
1933
+ var GlobeControl = memo14(_GlobeControl);
1934
+
1935
+ // src/components/minimap-control.ts
1936
+ import { memo as memo15 } from "react";
1937
+ import {
1938
+ Map as Map2
1939
+ } from "maplibre-gl";
1940
+ var DEFAULT_ZOOM_ADJUST = -4;
1941
+ var DEFAULT_COLLAPSED_SIZE = "29px";
1942
+ var DEFAULT_BORDER_RADIUS = "3px";
1943
+ var TRANSITION_DURATION_MS = 600;
1944
+ var RESIZE_DEBOUNCE_MS = 100;
1945
+ var DEFAULT_WIDTH = "400px";
1946
+ var DEFAULT_HEIGHT = "300px";
1947
+ var defaultInteractions = {
1948
+ dragPan: true,
1949
+ scrollZoom: false,
1950
+ boxZoom: false,
1951
+ dragRotate: false,
1952
+ keyboard: false,
1953
+ doubleClickZoom: false,
1954
+ touchZoomRotate: false
1955
+ };
1956
+ var DEFAULT_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17.6 18L8 8.4V17H6V5h12v2H9.4l9.6 9.6l-1.4 1.4Z" /></svg>`;
1957
+ function getRandomUUID() {
1958
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
1959
+ return crypto.randomUUID();
1960
+ }
1961
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
1962
+ const array = new Uint8Array(1);
1963
+ crypto.getRandomValues(array);
1964
+ const r = array[0] % 16;
1965
+ const v = c === "x" ? r : r & 3 | 8;
1966
+ return v.toString(16);
1967
+ });
1968
+ }
1969
+ function sanitizeSVG(svgString) {
1970
+ const svgPattern = /^<svg[^>]*>[\s\S]*<\/svg>$/i;
1971
+ if (!svgPattern.test(svgString)) {
1972
+ console.warn("Invalid SVG format, using default icon");
1973
+ return DEFAULT_ICON;
1974
+ }
1975
+ return svgString.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi, "").replace(/javascript:/gi, "");
1976
+ }
1977
+ var Minimap = class {
1978
+ constructor(options = {}) {
1979
+ this.differentStyle = false;
1980
+ this.isMinimized = false;
1981
+ this.id = `minimap-${getRandomUUID()}`;
1982
+ if (options.style !== void 0) {
1983
+ this.differentStyle = true;
1984
+ }
1985
+ const interactions = { ...defaultInteractions, ...options.interactions ?? {} };
1986
+ const containerStyle = this.validateContainerStyle(options.containerStyle);
1987
+ this.options = {
1988
+ zoomAdjust: DEFAULT_ZOOM_ADJUST,
1989
+ position: "top-right",
1990
+ pitchAdjust: false,
1991
+ attributionControl: false,
1992
+ logoPosition: "bottom-left",
1993
+ toggleable: true,
1994
+ initialMinimized: false,
1995
+ collapsedWidth: DEFAULT_COLLAPSED_SIZE,
1996
+ collapsedHeight: DEFAULT_COLLAPSED_SIZE,
1997
+ borderRadius: DEFAULT_BORDER_RADIUS,
1998
+ hideText: "Hide minimap",
1999
+ showText: "Show minimap",
2000
+ responsive: true,
2001
+ responsiveWidth: "20vw",
2002
+ responsiveHeight: "20vh",
2003
+ minWidth: "200px",
2004
+ minHeight: "150px",
2005
+ maxWidth: DEFAULT_WIDTH,
2006
+ maxHeight: DEFAULT_HEIGHT,
2007
+ interactions,
2008
+ ...options,
2009
+ containerStyle
2010
+ };
2011
+ if (options.lockZoom !== void 0) {
2012
+ this.options.minZoom = options.lockZoom;
2013
+ this.options.maxZoom = options.lockZoom;
2014
+ }
2015
+ this.isMinimized = this.options.initialMinimized ?? false;
2016
+ }
2017
+ onAdd(parentMap) {
2018
+ this.parentMap = parentMap;
2019
+ this.container = this.createContainer();
2020
+ this.options.container = this.container;
2021
+ this.options.zoom = parentMap.getZoom() + (this.options.zoomAdjust ?? DEFAULT_ZOOM_ADJUST);
2022
+ this.options.center ??= parentMap.getCenter().toArray();
2023
+ this.options.bearing = parentMap.getBearing();
2024
+ this.options.pitch = this.options.pitchAdjust ? parentMap.getPitch() : 0;
2025
+ if (!this.differentStyle) {
2026
+ this.options.style = parentMap.getStyle();
2027
+ }
2028
+ this.map = new Map2(this.options);
2029
+ this.map.once("style.load", () => {
2030
+ this.map.resize();
2031
+ });
2032
+ this.map.once("load", () => {
2033
+ this.configureInteractions();
2034
+ this.addParentRect(this.options.parentRect);
2035
+ this.desync = this.syncMaps();
2036
+ this.setupToggleButton();
2037
+ this.setupResponsiveSizing();
2038
+ });
2039
+ return this.container;
2040
+ }
2041
+ onRemove() {
2042
+ if (this.resizeHandler) {
2043
+ window.removeEventListener("resize", this.resizeHandler);
2044
+ this.resizeHandler = void 0;
2045
+ }
2046
+ this.toggleButtonCleanup?.();
2047
+ this.desync?.();
2048
+ this.container.remove();
2049
+ }
2050
+ createContainer() {
2051
+ const container = document.createElement("div");
2052
+ container.id = this.id;
2053
+ container.className = "maplibregl-ctrl maplibregl-ctrl-group maplibregl-ctrl-minimap custom-ctrl-minimap";
2054
+ if (this.isMinimized) {
2055
+ container.classList.add("minimized");
2056
+ }
2057
+ const styleEl = document.createElement("style");
2058
+ styleEl.innerHTML = this.getContainerStyles();
2059
+ container.appendChild(styleEl);
2060
+ if (this.options.containerStyle) {
2061
+ for (const [key, value] of Object.entries(this.options.containerStyle)) {
2062
+ container.style.setProperty(key, value);
2063
+ }
2064
+ }
2065
+ if (this.isMinimized) {
2066
+ container.style.width = this.options.collapsedWidth || DEFAULT_COLLAPSED_SIZE;
2067
+ container.style.height = this.options.collapsedHeight || DEFAULT_COLLAPSED_SIZE;
2068
+ }
2069
+ const preventDefault = (e) => e.preventDefault();
2070
+ container.addEventListener("contextmenu", preventDefault);
2071
+ return container;
2072
+ }
2073
+ getContainerStyles() {
2074
+ const width = this.options.containerStyle?.width || DEFAULT_WIDTH;
2075
+ const height = this.options.containerStyle?.height || DEFAULT_HEIGHT;
2076
+ const collapsedWidth = this.options.collapsedWidth || DEFAULT_COLLAPSED_SIZE;
2077
+ const collapsedHeight = this.options.collapsedHeight || DEFAULT_COLLAPSED_SIZE;
2078
+ const borderRadius = this.options.borderRadius || DEFAULT_BORDER_RADIUS;
2079
+ return `
2080
+ #${this.id}.custom-ctrl-minimap {
2081
+ cursor: default !important;
2082
+ box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
2083
+ transition: width 0.6s ease-in, height 0.6s ease-in, border-color 0s ease-in;
2084
+ border-style: solid;
2085
+ border-radius: ${borderRadius};
2086
+ border-width: 4px;
2087
+ border-color: white;
2088
+ width: ${width};
2089
+ height: ${height};
2090
+ overflow: hidden;
2091
+ background: #fff;
2092
+ position: relative;
2093
+ }
2094
+ #${this.id}.minimized {
2095
+ border-radius: 3px !important;
2096
+ width: ${collapsedWidth};
2097
+ height: ${collapsedHeight};
2098
+ }
2099
+ #${this.id} canvas {
2100
+ width: 100% !important;
2101
+ height: 100% !important;
2102
+ display: block;
2103
+ }
2104
+ @media (prefers-color-scheme: dark) {
2105
+ #${this.id}.custom-ctrl-minimap {
2106
+ border-color: hsl(0, 0%, 15.2%);
2107
+ }
2108
+ }
2109
+ `;
2110
+ }
2111
+ validateContainerStyle(style) {
2112
+ const defaults = { border: "1px solid #000", width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
2113
+ if (!style) return defaults;
2114
+ const validated = {};
2115
+ if (style.width) {
2116
+ validated.width = CSS.supports("width", style.width) ? style.width : defaults.width;
2117
+ } else {
2118
+ validated.width = defaults.width;
2119
+ }
2120
+ if (style.height) {
2121
+ validated.height = CSS.supports("height", style.height) ? style.height : defaults.height;
2122
+ } else {
2123
+ validated.height = defaults.height;
2124
+ }
2125
+ for (const [key, value] of Object.entries(style)) {
2126
+ if (key !== "width" && key !== "height") {
2127
+ validated[key] = value;
2128
+ }
2129
+ }
2130
+ return validated;
2131
+ }
2132
+ configureInteractions() {
2133
+ const interactions = this.options.interactions || defaultInteractions;
2134
+ for (const [interaction, enabled] of Object.entries(interactions)) {
2135
+ if (!enabled) {
2136
+ const interactionMethod = interaction;
2137
+ const interactionObj = this.map[interactionMethod];
2138
+ interactionObj?.disable();
2139
+ }
2140
+ }
2141
+ }
2142
+ setupToggleButton() {
2143
+ if (!this.options.toggleable) return;
2144
+ const el = document.createElement("button");
2145
+ const elId = "btn-" + getRandomUUID();
2146
+ el.innerHTML = sanitizeSVG(this.options.toggleButton?.icon || DEFAULT_ICON);
2147
+ el.setAttribute("id", elId);
2148
+ el.setAttribute("type", "button");
2149
+ el.setAttribute("aria-label", this.options.hideText || "Hide minimap");
2150
+ el.setAttribute("title", this.options.hideText || "Hide minimap");
2151
+ if (this.options.toggleButton?.className) {
2152
+ const classes = this.options.toggleButton.className.split(" ");
2153
+ classes.forEach((cls) => el.classList.add(cls));
2154
+ }
2155
+ const iconBackgroundColor = this.options.toggleButton?.iconBackgroundColor || "black";
2156
+ const hoverColor = this.options.toggleButton?.hoverColor || "#e5e7e3";
2157
+ const styleEl = document.createElement("style");
2158
+ styleEl.innerHTML = `
2159
+ button#${elId} {
2160
+ border-radius: 0 !important;
2161
+ color: black;
2162
+ background-color: ${iconBackgroundColor};
2163
+ border: none;
2164
+ display: flex;
2165
+ align-items: center;
2166
+ justify-content: center;
2167
+ cursor: pointer;
2168
+ transition: all 0.2s ease-in;
2169
+ position: absolute;
2170
+ width: 24px;
2171
+ height: 24px;
2172
+ z-index: 2;
2173
+ padding: 0;
2174
+ left: 0;
2175
+ top: 0;
2176
+ }
2177
+ button#${elId}:hover {
2178
+ background-color: ${hoverColor} !important;
2179
+ }
2180
+ button#${elId} svg {
2181
+ fill: white;
2182
+ width: 16px;
2183
+ height: 16px;
2184
+ }
2185
+ .minimized > button#${elId} > * {
2186
+ transform: rotate(-180deg);
2187
+ }
2188
+ `;
2189
+ const clickHandler = () => {
2190
+ this.toggle();
2191
+ const minimized = this.container.classList.contains("minimized");
2192
+ const text = minimized ? this.options.showText || "Show minimap" : this.options.hideText || "Hide minimap";
2193
+ el.setAttribute("aria-label", text);
2194
+ el.setAttribute("title", text);
2195
+ };
2196
+ el.addEventListener("click", clickHandler);
2197
+ document.head.appendChild(styleEl);
2198
+ this.container.appendChild(el);
2199
+ this.toggleButtonCleanup = () => {
2200
+ el.removeEventListener("click", clickHandler);
2201
+ styleEl.remove();
2202
+ this.container.removeChild(el);
2203
+ };
2204
+ }
2205
+ setupResponsiveSizing() {
2206
+ if (!this.options.responsive) return;
2207
+ const updateSize = () => {
2208
+ if (this.isMinimized) return;
2209
+ const vw = window.innerWidth / 100;
2210
+ const vh = window.innerHeight / 100;
2211
+ const responsiveWidth = this.options.responsiveWidth || "20vw";
2212
+ const responsiveHeight = this.options.responsiveHeight || "20vh";
2213
+ let width;
2214
+ let height;
2215
+ if (responsiveWidth.endsWith("vw")) {
2216
+ width = parseFloat(responsiveWidth) * vw;
2217
+ } else if (responsiveWidth.endsWith("%")) {
2218
+ width = parseFloat(responsiveWidth) / 100 * window.innerWidth;
2219
+ } else {
2220
+ width = parseFloat(responsiveWidth);
2221
+ }
2222
+ if (responsiveHeight.endsWith("vh")) {
2223
+ height = parseFloat(responsiveHeight) * vh;
2224
+ } else if (responsiveHeight.endsWith("%")) {
2225
+ height = parseFloat(responsiveHeight) / 100 * window.innerHeight;
2226
+ } else {
2227
+ height = parseFloat(responsiveHeight);
2228
+ }
2229
+ const minW = parseFloat(this.options.minWidth || "200px");
2230
+ const minH = parseFloat(this.options.minHeight || "150px");
2231
+ const maxW = parseFloat(this.options.maxWidth || DEFAULT_WIDTH);
2232
+ const maxH = parseFloat(this.options.maxHeight || DEFAULT_HEIGHT);
2233
+ width = Math.max(minW, Math.min(maxW, width));
2234
+ height = Math.max(minH, Math.min(maxH, height));
2235
+ this.container.style.width = `${width}px`;
2236
+ this.container.style.height = `${height}px`;
2237
+ this.map.resize();
2238
+ this.setParentBounds();
2239
+ };
2240
+ updateSize();
2241
+ let resizeTimeout;
2242
+ this.resizeHandler = () => {
2243
+ clearTimeout(resizeTimeout);
2244
+ resizeTimeout = setTimeout(updateSize, RESIZE_DEBOUNCE_MS);
2245
+ };
2246
+ window.addEventListener("resize", this.resizeHandler);
2247
+ }
2248
+ toggle() {
2249
+ this.isMinimized = !this.isMinimized;
2250
+ const collapsedWidth = this.options.collapsedWidth || DEFAULT_COLLAPSED_SIZE;
2251
+ const collapsedHeight = this.options.collapsedHeight || DEFAULT_COLLAPSED_SIZE;
2252
+ if (this.isMinimized) {
2253
+ this.container.classList.add("minimized");
2254
+ this.container.style.width = collapsedWidth;
2255
+ this.container.style.height = collapsedHeight;
2256
+ } else {
2257
+ this.container.classList.remove("minimized");
2258
+ if (this.options.responsive && this.resizeHandler) {
2259
+ this.resizeHandler();
2260
+ } else {
2261
+ const expandedWidth = this.options.containerStyle?.width || DEFAULT_WIDTH;
2262
+ const expandedHeight = this.options.containerStyle?.height || DEFAULT_HEIGHT;
2263
+ this.container.style.width = expandedWidth;
2264
+ this.container.style.height = expandedHeight;
2265
+ }
2266
+ }
2267
+ this.options.onToggle?.(this.isMinimized);
2268
+ setTimeout(() => {
2269
+ this.map.resize();
2270
+ this.setParentBounds();
2271
+ }, TRANSITION_DURATION_MS);
2272
+ }
2273
+ isMinimizedState() {
2274
+ return this.isMinimized;
2275
+ }
2276
+ addParentRect(rect) {
2277
+ if (rect === void 0 || rect.linePaint === void 0 && rect.fillPaint === void 0) {
2278
+ return;
2279
+ }
2280
+ this.parentRect = {
2281
+ type: "Feature",
2282
+ properties: { name: "parentRect" },
2283
+ geometry: {
2284
+ type: "Polygon",
2285
+ coordinates: [[[], [], [], [], []]]
2286
+ }
2287
+ };
2288
+ this.map.addSource("parentRect", {
2289
+ type: "geojson",
2290
+ data: this.parentRect
2291
+ });
2292
+ if (rect.lineLayout !== void 0 || rect.linePaint !== void 0) {
2293
+ this.map.addLayer({
2294
+ id: "parentRectOutline",
2295
+ type: "line",
2296
+ source: "parentRect",
2297
+ layout: { ...rect.lineLayout || {} },
2298
+ paint: {
2299
+ "line-color": "#FFF",
2300
+ "line-width": 1,
2301
+ "line-opacity": 0.85,
2302
+ ...rect.linePaint || {}
2303
+ }
2304
+ });
2305
+ }
2306
+ if (rect.fillPaint !== void 0) {
2307
+ this.map.addLayer({
2308
+ id: "parentRectFill",
2309
+ type: "fill",
2310
+ source: "parentRect",
2311
+ layout: {},
2312
+ paint: {
2313
+ "fill-color": "#08F",
2314
+ "fill-opacity": 0.135,
2315
+ ...rect.fillPaint || {}
2316
+ }
2317
+ });
2318
+ }
2319
+ this.setParentBounds();
2320
+ }
2321
+ setParentBounds() {
2322
+ if (this.parentRect === void 0 || this.isMinimized) return;
2323
+ const { devicePixelRatio } = window;
2324
+ const canvas = this.parentMap.getCanvas();
2325
+ const width = canvas.width / devicePixelRatio;
2326
+ const height = canvas.height / devicePixelRatio;
2327
+ const unproject = this.parentMap.unproject.bind(this.parentMap);
2328
+ const northWest = unproject([0, 0]);
2329
+ const northEast = unproject([width, 0]);
2330
+ const southWest = unproject([0, height]);
2331
+ const southEast = unproject([width, height]);
2332
+ this.parentRect.geometry.coordinates = [
2333
+ [
2334
+ southWest.toArray(),
2335
+ southEast.toArray(),
2336
+ northEast.toArray(),
2337
+ northWest.toArray(),
2338
+ southWest.toArray()
2339
+ ]
2340
+ ];
2341
+ const source = this.map.getSource("parentRect");
2342
+ if (source !== void 0) {
2343
+ source.setData(this.parentRect);
2344
+ }
2345
+ }
2346
+ syncMaps() {
2347
+ const { pitchAdjust } = this.options;
2348
+ const parentCallback = () => {
2349
+ if (!this.isMinimized) {
2350
+ sync("parent");
2351
+ }
2352
+ };
2353
+ const minimapCallback = () => {
2354
+ if (!this.isMinimized) {
2355
+ sync("minimap");
2356
+ }
2357
+ };
2358
+ const on = () => {
2359
+ this.parentMap.on("move", parentCallback);
2360
+ this.map.on("move", minimapCallback);
2361
+ };
2362
+ const off = () => {
2363
+ this.parentMap.off("move", parentCallback);
2364
+ this.map.off("move", minimapCallback);
2365
+ };
2366
+ const sync = (which) => {
2367
+ off();
2368
+ const from = which === "parent" ? this.parentMap : this.map;
2369
+ const to = which === "parent" ? this.map : this.parentMap;
2370
+ const center = from.getCenter();
2371
+ const zoom = from.getZoom() + (this.options.zoomAdjust ?? DEFAULT_ZOOM_ADJUST) * (which === "parent" ? 1 : -1);
2372
+ const bearing = from.getBearing();
2373
+ const pitch = from.getPitch();
2374
+ to.jumpTo({
2375
+ center,
2376
+ zoom,
2377
+ bearing,
2378
+ pitch: pitchAdjust ? pitch : 0
2379
+ });
2380
+ this.setParentBounds();
2381
+ on();
2382
+ };
2383
+ on();
2384
+ return () => {
2385
+ off();
2386
+ };
2387
+ }
2388
+ };
2389
+ function _MinimapControl(props) {
2390
+ const { position, ...options } = props;
2391
+ useControl(() => new Minimap(options), { position });
2392
+ return null;
2393
+ }
2394
+ var MinimapControl = memo15(_MinimapControl);
1414
2395
 
1415
2396
  // src/exports-maplibre-gl.ts
1416
2397
  var exports_maplibre_gl_default = Map;
1417
2398
  export {
1418
2399
  AttributionControl,
2400
+ CanvasSource,
2401
+ DrawControl,
1419
2402
  FullscreenControl,
1420
2403
  GeolocateControl,
2404
+ GlobeControl,
1421
2405
  Layer,
1422
2406
  LogoControl,
1423
2407
  Map,
1424
2408
  MapProvider,
1425
2409
  Marker,
2410
+ Minimap,
2411
+ MinimapControl,
1426
2412
  NavigationControl,
1427
2413
  Popup,
1428
2414
  ScaleControl,