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.cjs CHANGED
@@ -30,13 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
32
  AttributionControl: () => AttributionControl,
33
+ CanvasSource: () => CanvasSource,
34
+ DrawControl: () => DrawControl,
33
35
  FullscreenControl: () => FullscreenControl,
34
36
  GeolocateControl: () => GeolocateControl,
37
+ GlobeControl: () => GlobeControl,
35
38
  Layer: () => Layer,
36
39
  LogoControl: () => LogoControl,
37
40
  Map: () => Map,
38
41
  MapProvider: () => MapProvider,
39
42
  Marker: () => Marker,
43
+ Minimap: () => Minimap,
44
+ MinimapControl: () => MinimapControl,
40
45
  NavigationControl: () => NavigationControl,
41
46
  Popup: () => Popup,
42
47
  ScaleControl: () => ScaleControl,
@@ -95,7 +100,8 @@ function useMap() {
95
100
  const maps = (0, import_react.useContext)(MountedMapsContext)?.maps;
96
101
  const currentMap = (0, import_react.useContext)(MapContext);
97
102
  const mapsWithCurrent = (0, import_react.useMemo)(() => {
98
- return { ...maps, current: currentMap?.map };
103
+ const current = currentMap?.map || (maps ? Object.values(maps)[0] : void 0);
104
+ return { ...maps, current };
99
105
  }, [maps, currentMap]);
100
106
  return mapsWithCurrent;
101
107
  }
@@ -181,15 +187,7 @@ function applyViewStateToTransform(tr, props) {
181
187
  }
182
188
 
183
189
  // src/utils/style-utils.ts
184
- var refProps = [
185
- "type",
186
- "source",
187
- "source-layer",
188
- "minzoom",
189
- "maxzoom",
190
- "filter",
191
- "layout"
192
- ];
190
+ var refProps = ["type", "source", "source-layer", "minzoom", "maxzoom", "filter", "layout"];
193
191
  function normalizeStyle(style) {
194
192
  if (!style) {
195
193
  return null;
@@ -208,14 +206,15 @@ function normalizeStyle(style) {
208
206
  layerIndex[layer.id] = layer;
209
207
  }
210
208
  const layers = style.layers.map((layer) => {
209
+ const legacyLayer = layer;
211
210
  let normalizedLayer = null;
212
- if ("interactive" in layer) {
213
- normalizedLayer = Object.assign({}, layer);
211
+ if ("interactive" in legacyLayer) {
212
+ normalizedLayer = Object.assign({}, legacyLayer);
214
213
  delete normalizedLayer.interactive;
215
214
  }
216
- const layerRef = layerIndex[layer.ref];
215
+ const layerRef = layerIndex[legacyLayer.ref];
217
216
  if (layerRef) {
218
- normalizedLayer = normalizedLayer || Object.assign({}, layer);
217
+ normalizedLayer = normalizedLayer || Object.assign({}, legacyLayer);
219
218
  delete normalizedLayer.ref;
220
219
  for (const propName of refProps) {
221
220
  if (propName in layerRef) {
@@ -311,7 +310,8 @@ var Maplibre = class _Maplibre {
311
310
  this._propsedCameraUpdate = null;
312
311
  this._styleComponents = {};
313
312
  this._onEvent = (e) => {
314
- const cb = this.props[otherEvents[e.type]];
313
+ const handlerName = otherEvents[e.type];
314
+ const cb = this.props[handlerName];
315
315
  if (cb) {
316
316
  cb(e);
317
317
  } else if (e.type === "error") {
@@ -323,7 +323,8 @@ var Maplibre = class _Maplibre {
323
323
  return;
324
324
  }
325
325
  e.viewState = this._propsedCameraUpdate || transformToViewState(this._map.transform);
326
- const cb = this.props[cameraEvents[e.type]];
326
+ const handlerName = cameraEvents[e.type];
327
+ const cb = this.props[handlerName];
327
328
  if (cb) {
328
329
  cb(e);
329
330
  }
@@ -339,7 +340,8 @@ var Maplibre = class _Maplibre {
339
340
  if (e.type === "mousemove" || e.type === "mouseout") {
340
341
  this._updateHover(e);
341
342
  }
342
- const cb = this.props[pointerEvents[e.type]];
343
+ const handlerName = pointerEvents[e.type];
344
+ const cb = this.props[handlerName];
343
345
  if (cb) {
344
346
  if (this.props.interactiveLayerIds && e.type !== "mouseover" && e.type !== "mouseout") {
345
347
  e.features = this._hoveredFeatures || this._queryRenderedFeatures(e.point);
@@ -353,7 +355,6 @@ var Maplibre = class _Maplibre {
353
355
  this._initialize(container);
354
356
  }
355
357
  static {
356
- // eslint-disable-next-line no-use-before-define
357
358
  this.savedMaps = [];
358
359
  }
359
360
  get map() {
@@ -383,8 +384,9 @@ var Maplibre = class _Maplibre {
383
384
  while (oldContainer.childNodes.length > 0) {
384
385
  container.appendChild(oldContainer.childNodes[0]);
385
386
  }
386
- map._container = container;
387
- const resizeObserver = map._resizeObserver;
387
+ const mapInternal = map;
388
+ mapInternal._container = container;
389
+ const resizeObserver = mapInternal._resizeObserver;
388
390
  if (resizeObserver) {
389
391
  resizeObserver.disconnect();
390
392
  resizeObserver.observe(container);
@@ -407,10 +409,10 @@ var Maplibre = class _Maplibre {
407
409
  } else {
408
410
  map.once("style.load", () => map.fire("load"));
409
411
  }
410
- map._update();
412
+ const mapInternalForUpdate = map;
413
+ mapInternalForUpdate._update();
411
414
  return that;
412
415
  }
413
- /* eslint-disable complexity,max-statements */
414
416
  _initialize(container) {
415
417
  const { props } = this;
416
418
  const { mapStyle = DEFAULT_STYLE } = props;
@@ -443,11 +445,11 @@ var Maplibre = class _Maplibre {
443
445
  }
444
446
  map.transformCameraUpdate = this._onCameraUpdate;
445
447
  map.on("style.load", () => {
448
+ const mapWithProjection = map;
446
449
  this._styleComponents = {
447
450
  light: map.getLight(),
448
451
  sky: map.getSky(),
449
- // @ts-ignore getProjection() does not exist in v4
450
- projection: map.getProjection?.(),
452
+ projection: mapWithProjection.getProjection?.(),
451
453
  terrain: map.getTerrain()
452
454
  };
453
455
  this._updateStyleComponents(this.props);
@@ -466,7 +468,6 @@ var Maplibre = class _Maplibre {
466
468
  }
467
469
  this._map = map;
468
470
  }
469
- /* eslint-enable complexity,max-statements */
470
471
  recycle() {
471
472
  const container = this.map.getContainer();
472
473
  const children = container.querySelector("[mapboxgl-children]");
@@ -563,14 +564,10 @@ var Maplibre = class _Maplibre {
563
564
  * 1. They can not be applied right away. Certain conditions (style loaded, source loaded, etc.) must be met
564
565
  * 2. They can be overwritten by mapStyle
565
566
  */
566
- _updateStyleComponents({
567
- light,
568
- projection,
569
- sky,
570
- terrain
571
- }) {
567
+ _updateStyleComponents({ light, projection, sky, terrain }) {
572
568
  const map = this._map;
573
569
  const currProps = this._styleComponents;
570
+ const mapWithProjection = map;
574
571
  if (map.style._loaded) {
575
572
  if (light && !deepEqual(light, currProps.light)) {
576
573
  currProps.light = light;
@@ -578,7 +575,7 @@ var Maplibre = class _Maplibre {
578
575
  }
579
576
  if (projection && !deepEqual(projection, currProps.projection) && projection !== currProps.projection?.type) {
580
577
  currProps.projection = typeof projection === "string" ? { type: projection } : projection;
581
- map.setProjection?.(currProps.projection);
578
+ mapWithProjection.setProjection?.(currProps.projection);
582
579
  }
583
580
  if (sky && !deepEqual(sky, currProps.sky)) {
584
581
  currProps.sky = sky;
@@ -700,19 +697,34 @@ var useIsomorphicLayoutEffect = typeof document !== "undefined" ? import_react2.
700
697
  var use_isomorphic_layout_effect_default = useIsomorphicLayoutEffect;
701
698
 
702
699
  // src/utils/set-globals.ts
700
+ var validateUrl = (url, settingName) => {
701
+ try {
702
+ const parsed = new URL(url);
703
+ if (!["http:", "https:"].includes(parsed.protocol)) {
704
+ console.warn(`${settingName}: Only http/https protocols are allowed, got: ${parsed.protocol}`);
705
+ return false;
706
+ }
707
+ return true;
708
+ } catch {
709
+ console.warn(`${settingName}: Invalid URL format: ${url}`);
710
+ return false;
711
+ }
712
+ };
703
713
  function setGlobals(mapLib, props) {
704
714
  const { RTLTextPlugin, maxParallelImageRequests, workerCount, workerUrl } = props;
705
715
  if (RTLTextPlugin && mapLib.getRTLTextPluginStatus && mapLib.getRTLTextPluginStatus() === "unavailable") {
706
716
  const { pluginUrl, lazy = true } = typeof RTLTextPlugin === "string" ? { pluginUrl: RTLTextPlugin } : RTLTextPlugin;
707
- mapLib.setRTLTextPlugin(
708
- pluginUrl,
709
- (error) => {
710
- if (error) {
711
- console.error(error);
712
- }
713
- },
714
- lazy
715
- );
717
+ if (validateUrl(pluginUrl, "RTLTextPlugin")) {
718
+ mapLib.setRTLTextPlugin(
719
+ pluginUrl,
720
+ (error) => {
721
+ if (error) {
722
+ console.error(error);
723
+ }
724
+ },
725
+ lazy
726
+ );
727
+ }
716
728
  }
717
729
  if (maxParallelImageRequests !== void 0) {
718
730
  mapLib.setMaxParallelImageRequests(maxParallelImageRequests);
@@ -721,7 +733,9 @@ function setGlobals(mapLib, props) {
721
733
  mapLib.setWorkerCount(workerCount);
722
734
  }
723
735
  if (workerUrl !== void 0) {
724
- mapLib.setWorkerUrl(workerUrl);
736
+ if (validateUrl(workerUrl, "workerUrl")) {
737
+ mapLib.setWorkerUrl(workerUrl);
738
+ }
725
739
  }
726
740
  }
727
741
 
@@ -749,14 +763,18 @@ function applyReactStyle(element, styles) {
749
763
  var import_react3 = require("react");
750
764
  function useControl(onCreate, arg1, arg2, arg3) {
751
765
  const context = (0, import_react3.useContext)(MapContext);
766
+ if (!context) {
767
+ throw new Error("useControl must be used within a Map component");
768
+ }
752
769
  const ctrl = (0, import_react3.useMemo)(() => onCreate(context), []);
753
770
  (0, import_react3.useEffect)(() => {
754
771
  const opts = arg3 || arg2 || arg1;
755
772
  const onAdd = typeof arg1 === "function" && typeof arg2 === "function" ? arg1 : null;
756
773
  const onRemove = typeof arg2 === "function" ? arg2 : typeof arg1 === "function" ? arg1 : null;
757
774
  const { map } = context;
758
- if (!map.hasControl(ctrl)) {
759
- map.addControl(ctrl, opts?.position);
775
+ const ctrlAsIControl = ctrl;
776
+ if (!map.hasControl(ctrlAsIControl)) {
777
+ map.addControl(ctrlAsIControl, opts?.position);
760
778
  if (onAdd) {
761
779
  onAdd(context);
762
780
  }
@@ -765,8 +783,8 @@ function useControl(onCreate, arg1, arg2, arg3) {
765
783
  if (onRemove) {
766
784
  onRemove(context);
767
785
  }
768
- if (map.hasControl(ctrl)) {
769
- map.removeControl(ctrl);
786
+ if (map.hasControl(ctrlAsIControl)) {
787
+ map.removeControl(ctrlAsIControl);
770
788
  }
771
789
  };
772
790
  }, []);
@@ -826,11 +844,24 @@ function _AttributionControl(props) {
826
844
  if (!ctrl._container || !map) return;
827
845
  const onLoad = () => {
828
846
  setTimeout(() => {
829
- const inner = ctrl._container.querySelector(
830
- ".maplibregl-ctrl-attrib-inner"
831
- );
847
+ const inner = ctrl._container.querySelector(".maplibregl-ctrl-attrib-inner");
832
848
  if (inner) {
833
- 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>';
849
+ inner.textContent = "";
850
+ const createLink = (text, href) => {
851
+ const a = document.createElement("a");
852
+ a.href = href;
853
+ a.target = "_blank";
854
+ a.rel = "noopener noreferrer";
855
+ a.textContent = text;
856
+ return a;
857
+ };
858
+ inner.appendChild(createLink("Barikoi", "https://barikoi.com"));
859
+ inner.appendChild(document.createTextNode(" \xA9 "));
860
+ inner.appendChild(createLink("OpenMapTiles", "https://openmaptiles.org"));
861
+ inner.appendChild(document.createTextNode(" \xA9 "));
862
+ inner.appendChild(
863
+ createLink("OpenStreetMap contributors", "https://www.openstreetmap.org/copyright")
864
+ );
834
865
  }
835
866
  }, 0);
836
867
  };
@@ -860,7 +891,7 @@ function _Map(props, ref) {
860
891
  (0, import_react6.useEffect)(() => {
861
892
  const mapLib = props.mapLib;
862
893
  let isMounted = true;
863
- let maplibre;
894
+ let maplibre = null;
864
895
  Promise.resolve(mapLib || import("maplibre-gl")).then((module2) => {
865
896
  if (!isMounted) {
866
897
  return;
@@ -881,15 +912,16 @@ function _Map(props, ref) {
881
912
  mapboxgl.Map,
882
913
  {
883
914
  ...props,
884
- // @ts-ignore - attributionControl is not in the type definition but is supported by maplibre-gl
885
915
  attributionControl: false
886
916
  },
887
917
  containerRef.current
888
918
  );
889
919
  }
890
- contextValue.map = createRef(maplibre);
891
- contextValue.mapLib = mapboxgl;
892
- setMapInstance(maplibre);
920
+ if (maplibre) {
921
+ contextValue.map = createRef(maplibre);
922
+ contextValue.mapLib = mapboxgl;
923
+ setMapInstance(maplibre);
924
+ }
893
925
  mountedMapsContext?.onMapMount(contextValue.map, props.id);
894
926
  }).catch((error) => {
895
927
  const { onError } = props;
@@ -934,7 +966,7 @@ function _Map(props, ref) {
934
966
  const CHILD_CONTAINER_STYLE = {
935
967
  height: "100%"
936
968
  };
937
- 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)));
969
+ 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)));
938
970
  }
939
971
  var Map = React2.forwardRef(_Map);
940
972
 
@@ -971,7 +1003,7 @@ function getClassList(className) {
971
1003
  var Marker = (0, import_react7.memo)(
972
1004
  (0, import_react7.forwardRef)((props, ref) => {
973
1005
  const { map, mapLib } = (0, import_react7.useContext)(MapContext);
974
- const thisRef = (0, import_react7.useRef)({ props });
1006
+ const callbackRef = (0, import_react7.useRef)({});
975
1007
  const marker = (0, import_react7.useMemo)(() => {
976
1008
  let hasChildren = false;
977
1009
  React3.Children.forEach(props.children, (el) => {
@@ -985,33 +1017,46 @@ var Marker = (0, import_react7.memo)(
985
1017
  };
986
1018
  const mk = new mapLib.Marker(options);
987
1019
  mk.setLngLat([props.longitude, props.latitude]);
988
- mk.getElement().addEventListener("click", (e) => {
989
- thisRef.current.props.onClick?.({
990
- type: "click",
991
- target: mk,
992
- originalEvent: e
993
- });
994
- });
995
- mk.on("dragstart", (e) => {
996
- const evt = e;
997
- evt.lngLat = marker.getLngLat();
998
- thisRef.current.props.onDragStart?.(evt);
999
- });
1000
- mk.on("drag", (e) => {
1001
- const evt = e;
1002
- evt.lngLat = marker.getLngLat();
1003
- thisRef.current.props.onDrag?.(evt);
1004
- });
1005
- mk.on("dragend", (e) => {
1006
- const evt = e;
1007
- evt.lngLat = marker.getLngLat();
1008
- thisRef.current.props.onDragEnd?.(evt);
1009
- });
1010
1020
  return mk;
1011
1021
  }, []);
1012
1022
  (0, import_react7.useEffect)(() => {
1023
+ callbackRef.current = {
1024
+ onClick: props.onClick,
1025
+ onDragStart: props.onDragStart,
1026
+ onDrag: props.onDrag,
1027
+ onDragEnd: props.onDragEnd
1028
+ };
1029
+ });
1030
+ (0, import_react7.useEffect)(() => {
1031
+ const clickHandler = (e) => {
1032
+ callbackRef.current.onClick?.({
1033
+ type: "click",
1034
+ target: marker,
1035
+ originalEvent: e
1036
+ });
1037
+ };
1038
+ marker.getElement().addEventListener("click", clickHandler);
1039
+ const dragStartHandler = (e) => {
1040
+ e.lngLat = marker.getLngLat();
1041
+ callbackRef.current.onDragStart?.(e);
1042
+ };
1043
+ const dragHandler = (e) => {
1044
+ e.lngLat = marker.getLngLat();
1045
+ callbackRef.current.onDrag?.(e);
1046
+ };
1047
+ const dragEndHandler = (e) => {
1048
+ e.lngLat = marker.getLngLat();
1049
+ callbackRef.current.onDragEnd?.(e);
1050
+ };
1051
+ marker.on("dragstart", dragStartHandler);
1052
+ marker.on("drag", dragHandler);
1053
+ marker.on("dragend", dragEndHandler);
1013
1054
  marker.addTo(map.getMap());
1014
1055
  return () => {
1056
+ marker.getElement().removeEventListener("click", clickHandler);
1057
+ marker.off("dragstart", dragStartHandler);
1058
+ marker.off("drag", dragHandler);
1059
+ marker.off("dragend", dragEndHandler);
1015
1060
  marker.remove();
1016
1061
  };
1017
1062
  }, []);
@@ -1024,44 +1069,44 @@ var Marker = (0, import_react7.memo)(
1024
1069
  popup = null,
1025
1070
  rotation = 0,
1026
1071
  rotationAlignment = "auto",
1027
- pitchAlignment = "auto"
1072
+ pitchAlignment = "auto",
1073
+ className
1028
1074
  } = props;
1029
1075
  (0, import_react7.useEffect)(() => {
1030
1076
  applyReactStyle(marker.getElement(), style);
1031
1077
  }, [style]);
1032
1078
  (0, import_react7.useImperativeHandle)(ref, () => marker, []);
1033
- const oldProps = thisRef.current.props;
1034
- if (marker.getLngLat().lng !== longitude || marker.getLngLat().lat !== latitude) {
1035
- marker.setLngLat([longitude, latitude]);
1036
- }
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(
1056
- oldProps.className,
1057
- props.className
1058
- );
1059
- if (classNameDiff) {
1060
- for (const c of classNameDiff) {
1061
- marker.toggleClassName(c);
1079
+ const prevClassNameRef = (0, import_react7.useRef)(className);
1080
+ (0, import_react7.useEffect)(() => {
1081
+ if (marker.getLngLat().lng !== longitude || marker.getLngLat().lat !== latitude) {
1082
+ marker.setLngLat([longitude, latitude]);
1062
1083
  }
1063
- }
1064
- thisRef.current.props = props;
1084
+ if (offset && !arePointsEqual(marker.getOffset(), offset)) {
1085
+ marker.setOffset(offset);
1086
+ }
1087
+ if (marker.isDraggable() !== draggable) {
1088
+ marker.setDraggable(draggable);
1089
+ }
1090
+ if (marker.getRotation() !== rotation) {
1091
+ marker.setRotation(rotation);
1092
+ }
1093
+ if (marker.getRotationAlignment() !== rotationAlignment) {
1094
+ marker.setRotationAlignment(rotationAlignment);
1095
+ }
1096
+ if (marker.getPitchAlignment() !== pitchAlignment) {
1097
+ marker.setPitchAlignment(pitchAlignment);
1098
+ }
1099
+ if (marker.getPopup() !== popup) {
1100
+ marker.setPopup(popup);
1101
+ }
1102
+ const classNameDiff = compareClassNames(prevClassNameRef.current, className);
1103
+ if (classNameDiff) {
1104
+ for (const c of classNameDiff) {
1105
+ marker.toggleClassName(c);
1106
+ }
1107
+ }
1108
+ prevClassNameRef.current = className;
1109
+ });
1065
1110
  return (0, import_react_dom.createPortal)(props.children, marker.getElement());
1066
1111
  })
1067
1112
  );
@@ -1075,23 +1120,25 @@ var Popup = (0, import_react8.memo)(
1075
1120
  const container = (0, import_react8.useMemo)(() => {
1076
1121
  return document.createElement("div");
1077
1122
  }, []);
1078
- const thisRef = (0, import_react8.useRef)({ props });
1079
1123
  const popup = (0, import_react8.useMemo)(() => {
1080
1124
  const options = { ...props };
1081
1125
  const pp = new mapLib.Popup(options);
1082
1126
  pp.setLngLat([props.longitude, props.latitude]);
1083
- pp.once("open", (e) => {
1084
- thisRef.current.props.onOpen?.(e);
1085
- });
1086
1127
  return pp;
1087
1128
  }, []);
1129
+ (0, import_react8.useImperativeHandle)(ref, () => popup, []);
1088
1130
  (0, import_react8.useEffect)(() => {
1131
+ const onOpen = (e) => {
1132
+ props.onOpen?.(e);
1133
+ };
1089
1134
  const onClose = (e) => {
1090
- thisRef.current.props.onClose?.(e);
1135
+ props.onClose?.(e);
1091
1136
  };
1137
+ popup.on("open", onOpen);
1092
1138
  popup.on("close", onClose);
1093
1139
  popup.setDOMContent(container).addTo(map.getMap());
1094
1140
  return () => {
1141
+ popup.off("open", onOpen);
1095
1142
  popup.off("close", onClose);
1096
1143
  if (popup.isOpen()) {
1097
1144
  popup.remove();
@@ -1101,30 +1148,34 @@ var Popup = (0, import_react8.memo)(
1101
1148
  (0, import_react8.useEffect)(() => {
1102
1149
  applyReactStyle(popup.getElement(), props.style);
1103
1150
  }, [props.style]);
1104
- (0, import_react8.useImperativeHandle)(ref, () => popup, []);
1105
- if (popup.isOpen()) {
1106
- const oldProps = thisRef.current.props;
1107
- if (popup.getLngLat().lng !== props.longitude || popup.getLngLat().lat !== props.latitude) {
1108
- popup.setLngLat([props.longitude, props.latitude]);
1151
+ (0, import_react8.useEffect)(() => {
1152
+ if (popup.isOpen()) {
1153
+ if (popup.getLngLat().lng !== props.longitude || popup.getLngLat().lat !== props.latitude) {
1154
+ popup.setLngLat([props.longitude, props.latitude]);
1155
+ }
1109
1156
  }
1110
- if (props.offset && !deepEqual(oldProps.offset, props.offset)) {
1157
+ }, [props.longitude, props.latitude]);
1158
+ (0, import_react8.useEffect)(() => {
1159
+ if (popup.isOpen() && props.offset) {
1111
1160
  popup.setOffset(props.offset);
1112
1161
  }
1113
- if (oldProps.anchor !== props.anchor || oldProps.maxWidth !== props.maxWidth) {
1114
- popup.options.anchor = props.anchor;
1162
+ }, [props.offset]);
1163
+ (0, import_react8.useEffect)(() => {
1164
+ if (popup.isOpen() && props.maxWidth !== void 0) {
1115
1165
  popup.setMaxWidth(props.maxWidth);
1116
1166
  }
1117
- const classNameDiff = compareClassNames(
1118
- oldProps.className,
1119
- props.className
1120
- );
1121
- if (classNameDiff) {
1122
- for (const c of classNameDiff) {
1123
- popup.toggleClassName(c);
1167
+ }, [props.maxWidth]);
1168
+ (0, import_react8.useEffect)(() => {
1169
+ if (popup.isOpen() && props.className) {
1170
+ const currentClassName = popup.options.className || "";
1171
+ const classNameDiff = compareClassNames(currentClassName, props.className);
1172
+ if (classNameDiff) {
1173
+ for (const c of classNameDiff) {
1174
+ popup.toggleClassName(c);
1175
+ }
1124
1176
  }
1125
1177
  }
1126
- thisRef.current.props = props;
1127
- }
1178
+ }, [props.className]);
1128
1179
  return (0, import_react_dom2.createPortal)(props.children, container);
1129
1180
  })
1130
1181
  );
@@ -1184,9 +1235,7 @@ function _GeolocateControl(props, ref) {
1184
1235
  }, [props.style]);
1185
1236
  return null;
1186
1237
  }
1187
- var GeolocateControl = (0, import_react10.memo)(
1188
- (0, import_react10.forwardRef)(_GeolocateControl)
1189
- );
1238
+ var GeolocateControl = (0, import_react10.memo)((0, import_react10.forwardRef)(_GeolocateControl));
1190
1239
 
1191
1240
  // src/components/navigation-control.ts
1192
1241
  var import_react11 = require("react");
@@ -1210,16 +1259,18 @@ function _ScaleControl(props) {
1210
1259
  const propsRef = (0, import_react12.useRef)(props);
1211
1260
  const prevProps = propsRef.current;
1212
1261
  propsRef.current = props;
1213
- const { style } = props;
1214
- if (props.maxWidth !== void 0 && props.maxWidth !== prevProps.maxWidth) {
1215
- ctrl.options.maxWidth = props.maxWidth;
1216
- }
1217
- if (props.unit !== void 0 && props.unit !== prevProps.unit) {
1218
- ctrl.setUnit(props.unit);
1219
- }
1262
+ const { style, maxWidth, unit } = props;
1263
+ (0, import_react12.useEffect)(() => {
1264
+ if (maxWidth !== void 0 && maxWidth !== prevProps.maxWidth) {
1265
+ ctrl.options.maxWidth = maxWidth;
1266
+ }
1267
+ if (unit !== void 0 && unit !== prevProps.unit) {
1268
+ ctrl.setUnit(unit);
1269
+ }
1270
+ }, [ctrl, maxWidth, unit, prevProps.maxWidth, prevProps.unit]);
1220
1271
  (0, import_react12.useEffect)(() => {
1221
1272
  applyReactStyle(ctrl._container, style);
1222
- }, [style]);
1273
+ }, [ctrl, style]);
1223
1274
  return null;
1224
1275
  }
1225
1276
  var ScaleControl = (0, import_react12.memo)(_ScaleControl);
@@ -1249,9 +1300,9 @@ function assert(condition, message) {
1249
1300
  }
1250
1301
 
1251
1302
  // src/components/source.ts
1252
- var sourceCounter = 0;
1253
1303
  function createSource(map, id, props) {
1254
- if (map.style && map.style._loaded) {
1304
+ const mapInternal = map;
1305
+ if (mapInternal.style && mapInternal.style._loaded) {
1255
1306
  const options = { ...props };
1256
1307
  delete options.id;
1257
1308
  delete options.children;
@@ -1276,33 +1327,43 @@ function updateSource(source, props, prevProps) {
1276
1327
  }
1277
1328
  const type = props.type;
1278
1329
  if (type === "geojson") {
1330
+ ;
1279
1331
  source.setData(props.data);
1280
1332
  } else if (type === "image") {
1333
+ ;
1281
1334
  source.updateImage({
1282
1335
  url: props.url,
1283
1336
  coordinates: props.coordinates
1284
1337
  });
1285
1338
  } else {
1339
+ const sourceWithMethods = source;
1340
+ const propsWithOptional = props;
1286
1341
  switch (changedKey) {
1287
1342
  case "coordinates":
1288
- source.setCoordinates?.(props.coordinates);
1343
+ sourceWithMethods.setCoordinates?.(propsWithOptional.coordinates);
1289
1344
  break;
1290
1345
  case "url":
1291
- source.setUrl?.(props.url);
1346
+ sourceWithMethods.setUrl?.(propsWithOptional.url);
1292
1347
  break;
1293
1348
  case "tiles":
1294
- source.setTiles?.(props.tiles);
1349
+ sourceWithMethods.setTiles?.(propsWithOptional.tiles);
1295
1350
  break;
1296
1351
  default:
1297
1352
  console.warn(`Unable to update <Source> prop: ${changedKey}`);
1298
1353
  }
1299
1354
  }
1300
1355
  }
1301
- function Source(props) {
1356
+ function _Source(props, ref) {
1302
1357
  const map = (0, import_react14.useContext)(MapContext).map.getMap();
1303
1358
  const propsRef = (0, import_react14.useRef)(props);
1359
+ const sourceRef = (0, import_react14.useRef)(null);
1304
1360
  const [, setStyleLoaded] = (0, import_react14.useState)(0);
1305
- const id = (0, import_react14.useMemo)(() => props.id || `jsx-source-${sourceCounter++}`, []);
1361
+ const generatedId = (0, import_react14.useId)();
1362
+ const id = (0, import_react14.useMemo)(
1363
+ () => props.id || `jsx-source-${generatedId.replace(/:/g, "-")}`,
1364
+ // Empty deps - id is set once on mount and should not change
1365
+ []
1366
+ );
1306
1367
  (0, import_react14.useEffect)(() => {
1307
1368
  if (map) {
1308
1369
  const forceUpdate = () => setTimeout(() => setStyleLoaded((version) => version + 1), 0);
@@ -1310,11 +1371,13 @@ function Source(props) {
1310
1371
  forceUpdate();
1311
1372
  return () => {
1312
1373
  map.off("styledata", forceUpdate);
1313
- if (map.style && map.style._loaded && map.getSource(id)) {
1374
+ const mapInternal2 = map;
1375
+ if (mapInternal2.style && mapInternal2.style._loaded && map.getSource(id)) {
1314
1376
  const allLayers = map.getStyle()?.layers;
1315
1377
  if (allLayers) {
1316
1378
  for (const layer of allLayers) {
1317
- if (layer.source === id) {
1379
+ const layerWithSource = layer;
1380
+ if (layerWithSource.source === id) {
1318
1381
  map.removeLayer(layer.id);
1319
1382
  }
1320
1383
  }
@@ -1325,13 +1388,16 @@ function Source(props) {
1325
1388
  }
1326
1389
  return void 0;
1327
1390
  }, [map]);
1328
- let source = map && map.style && map.getSource(id);
1391
+ const mapInternal = map;
1392
+ let source = map && mapInternal.style && map.getSource(id);
1329
1393
  if (source) {
1330
1394
  updateSource(source, props, propsRef.current);
1331
1395
  } else {
1332
1396
  source = createSource(map, id, props);
1333
1397
  }
1398
+ sourceRef.current = source;
1334
1399
  propsRef.current = props;
1400
+ (0, import_react14.useImperativeHandle)(ref, () => sourceRef.current, [source]);
1335
1401
  return source && React4.Children.map(
1336
1402
  props.children,
1337
1403
  (child) => child && (0, import_react14.cloneElement)(child, {
@@ -1339,21 +1405,103 @@ function Source(props) {
1339
1405
  })
1340
1406
  ) || null;
1341
1407
  }
1408
+ var Source = (0, import_react14.memo)(React4.forwardRef(_Source));
1342
1409
 
1343
- // src/components/layer.ts
1410
+ // src/components/canvas-source.ts
1411
+ var React5 = __toESM(require("react"), 1);
1344
1412
  var import_react15 = require("react");
1413
+ function _CanvasSource(props) {
1414
+ const map = (0, import_react15.useContext)(MapContext).map.getMap();
1415
+ const propsRef = (0, import_react15.useRef)(props);
1416
+ const id = (0, import_react15.useMemo)(() => props.id || `canvas-source-${Date.now()}`, [props.id]);
1417
+ (0, import_react15.useEffect)(() => {
1418
+ if (!map) return void 0;
1419
+ const mapInternal2 = map;
1420
+ let source = null;
1421
+ const addSource = () => {
1422
+ if (!mapInternal2.style || !mapInternal2.style._loaded) return;
1423
+ if (map.getSource(id)) return;
1424
+ const { coordinates, canvas, animate } = props;
1425
+ map.addSource(id, {
1426
+ type: "canvas",
1427
+ coordinates,
1428
+ canvas,
1429
+ animate: animate || false
1430
+ });
1431
+ source = map.getSource(id);
1432
+ };
1433
+ const updateSource2 = () => {
1434
+ if (!source) return;
1435
+ const { coordinates, canvas } = props;
1436
+ const prevProps = propsRef.current;
1437
+ if (JSON.stringify(coordinates) !== JSON.stringify(prevProps.coordinates)) {
1438
+ const sourceWithMethods = source;
1439
+ sourceWithMethods.setCoordinates?.(coordinates);
1440
+ }
1441
+ };
1442
+ if (mapInternal2.style && mapInternal2.style._loaded) {
1443
+ addSource();
1444
+ } else {
1445
+ map.once("styledata", addSource);
1446
+ }
1447
+ return () => {
1448
+ map.off("styledata", addSource);
1449
+ const mapInternalForCleanup = map;
1450
+ if (mapInternalForCleanup.style && mapInternalForCleanup.style._loaded && map.getSource(id)) {
1451
+ const allLayers = map.getStyle()?.layers;
1452
+ if (allLayers) {
1453
+ for (const layer of allLayers) {
1454
+ if (layer.source === id) {
1455
+ map.removeLayer(layer.id);
1456
+ }
1457
+ }
1458
+ }
1459
+ map.removeSource(id);
1460
+ }
1461
+ };
1462
+ }, [map, id]);
1463
+ (0, import_react15.useEffect)(() => {
1464
+ if (!map) return;
1465
+ const source = map.getSource(id);
1466
+ if (!source) return;
1467
+ const { coordinates } = props;
1468
+ const prevProps = propsRef.current;
1469
+ if (JSON.stringify(coordinates) !== JSON.stringify(prevProps.coordinates)) {
1470
+ const sourceWithMethods = source;
1471
+ sourceWithMethods.setCoordinates?.(coordinates);
1472
+ }
1473
+ propsRef.current = props;
1474
+ }, [map, id, props.coordinates, props.canvas]);
1475
+ if (!map) return null;
1476
+ const mapInternal = map;
1477
+ if (!mapInternal.style || !mapInternal.style._loaded || !map.getSource(id)) {
1478
+ return null;
1479
+ }
1480
+ return props.children && React5.Children.map(
1481
+ props.children,
1482
+ (child) => child && React5.cloneElement(child, {
1483
+ source: id
1484
+ })
1485
+ ) || null;
1486
+ }
1487
+ var CanvasSource = (0, import_react15.memo)(_CanvasSource);
1488
+
1489
+ // src/components/layer.ts
1490
+ var import_react16 = require("react");
1345
1491
  function updateLayer(map, id, props, prevProps) {
1346
1492
  assert(props.id === prevProps.id, "layer id changed");
1347
1493
  assert(props.type === prevProps.type, "layer type changed");
1348
1494
  if (props.type === "custom" || prevProps.type === "custom") {
1349
1495
  return;
1350
1496
  }
1351
- const { layout = {}, paint = {}, filter, minzoom, maxzoom, beforeId } = props;
1352
- if (beforeId !== prevProps.beforeId) {
1497
+ const propsWithFilter = props;
1498
+ const prevPropsWithFilter = prevProps;
1499
+ const { layout = {}, paint = {}, filter, minzoom, maxzoom, beforeId } = propsWithFilter;
1500
+ if (beforeId !== prevPropsWithFilter.beforeId) {
1353
1501
  map.moveLayer(id, beforeId);
1354
1502
  }
1355
- if (layout !== prevProps.layout) {
1356
- const prevLayout = prevProps.layout || {};
1503
+ if (layout !== prevPropsWithFilter.layout) {
1504
+ const prevLayout = prevPropsWithFilter.layout || {};
1357
1505
  for (const key in layout) {
1358
1506
  if (!deepEqual(layout[key], prevLayout[key])) {
1359
1507
  map.setLayoutProperty(id, key, layout[key]);
@@ -1365,8 +1513,8 @@ function updateLayer(map, id, props, prevProps) {
1365
1513
  }
1366
1514
  }
1367
1515
  }
1368
- if (paint !== prevProps.paint) {
1369
- const prevPaint = prevProps.paint || {};
1516
+ if (paint !== prevPropsWithFilter.paint) {
1517
+ const prevPaint = prevPropsWithFilter.paint || {};
1370
1518
  for (const key in paint) {
1371
1519
  if (!deepEqual(paint[key], prevPaint[key])) {
1372
1520
  map.setPaintProperty(id, key, paint[key]);
@@ -1378,41 +1526,151 @@ function updateLayer(map, id, props, prevProps) {
1378
1526
  }
1379
1527
  }
1380
1528
  }
1381
- if (!deepEqual(filter, prevProps.filter)) {
1382
- map.setFilter(id, filter);
1529
+ if (!deepEqual(filter, prevPropsWithFilter.filter)) {
1530
+ map.setFilter(id, filter ?? null);
1383
1531
  }
1384
- if (minzoom !== prevProps.minzoom || maxzoom !== prevProps.maxzoom) {
1532
+ if (minzoom !== prevPropsWithFilter.minzoom || maxzoom !== prevPropsWithFilter.maxzoom) {
1385
1533
  map.setLayerZoomRange(id, minzoom, maxzoom);
1386
1534
  }
1387
1535
  }
1388
1536
  function createLayer(map, id, props) {
1389
- if (map.style && map.style._loaded && (!("source" in props) || map.getSource(props.source))) {
1537
+ const mapInternal = map;
1538
+ if (mapInternal.style && mapInternal.style._loaded && (!("source" in props) || map.getSource(props.source))) {
1390
1539
  const options = { ...props, id };
1391
1540
  delete options.beforeId;
1392
1541
  map.addLayer(options, props.beforeId);
1393
1542
  }
1394
1543
  }
1395
- var layerCounter = 0;
1396
- function Layer(props) {
1397
- const map = (0, import_react15.useContext)(MapContext).map.getMap();
1398
- const propsRef = (0, import_react15.useRef)(props);
1399
- const [, setStyleLoaded] = (0, import_react15.useState)(0);
1400
- const id = (0, import_react15.useMemo)(() => props.id || `jsx-layer-${layerCounter++}`, []);
1401
- (0, import_react15.useEffect)(() => {
1544
+ function _Layer(props) {
1545
+ const map = (0, import_react16.useContext)(MapContext).map.getMap();
1546
+ const propsRef = (0, import_react16.useRef)(props);
1547
+ const [, setStyleLoaded] = (0, import_react16.useState)(0);
1548
+ const generatedId = (0, import_react16.useId)();
1549
+ const id = (0, import_react16.useMemo)(
1550
+ () => props.id || `jsx-layer-${generatedId.replace(/:/g, "-")}`,
1551
+ // Empty deps - id is set once on mount and should not change
1552
+ []
1553
+ );
1554
+ const {
1555
+ onClick,
1556
+ onMouseEnter,
1557
+ onMouseLeave,
1558
+ onMouseMove,
1559
+ onMouseDown,
1560
+ onMouseUp,
1561
+ onContextMenu,
1562
+ onDoubleClick
1563
+ } = props;
1564
+ const callbacksRef = (0, import_react16.useRef)({
1565
+ onClick,
1566
+ onMouseEnter,
1567
+ onMouseLeave,
1568
+ onMouseMove,
1569
+ onMouseDown,
1570
+ onMouseUp,
1571
+ onContextMenu,
1572
+ onDoubleClick
1573
+ });
1574
+ (0, import_react16.useEffect)(() => {
1575
+ callbacksRef.current = {
1576
+ onClick,
1577
+ onMouseEnter,
1578
+ onMouseLeave,
1579
+ onMouseMove,
1580
+ onMouseDown,
1581
+ onMouseUp,
1582
+ onContextMenu,
1583
+ onDoubleClick
1584
+ };
1585
+ }, [
1586
+ onClick,
1587
+ onMouseEnter,
1588
+ onMouseLeave,
1589
+ onMouseMove,
1590
+ onMouseDown,
1591
+ onMouseUp,
1592
+ onContextMenu,
1593
+ onDoubleClick
1594
+ ]);
1595
+ (0, import_react16.useEffect)(() => {
1402
1596
  if (map) {
1403
1597
  const forceUpdate = () => setStyleLoaded((version) => version + 1);
1404
1598
  map.on("styledata", forceUpdate);
1405
1599
  forceUpdate();
1406
1600
  return () => {
1407
1601
  map.off("styledata", forceUpdate);
1408
- if (map.style && map.style._loaded && map.getLayer(id)) {
1602
+ const mapInternal2 = map;
1603
+ if (mapInternal2.style && mapInternal2.style._loaded && map.getLayer(id)) {
1409
1604
  map.removeLayer(id);
1410
1605
  }
1411
1606
  };
1412
1607
  }
1413
1608
  return void 0;
1414
1609
  }, [map]);
1415
- const layer = map && map.style && map.getLayer(id);
1610
+ (0, import_react16.useEffect)(() => {
1611
+ if (!map) return void 0;
1612
+ const hasEventHandler = onClick || onMouseEnter || onMouseLeave || onMouseMove || onMouseDown || onMouseUp || onContextMenu || onDoubleClick;
1613
+ if (!hasEventHandler) return void 0;
1614
+ const handleClick = (e) => {
1615
+ callbacksRef.current.onClick?.(e);
1616
+ };
1617
+ const handleMouseEnter = (e) => {
1618
+ callbacksRef.current.onMouseEnter?.(e);
1619
+ if (callbacksRef.current.onClick) {
1620
+ map.getCanvas().style.cursor = "pointer";
1621
+ }
1622
+ };
1623
+ const handleMouseLeave = () => {
1624
+ callbacksRef.current.onMouseLeave?.();
1625
+ map.getCanvas().style.cursor = "";
1626
+ };
1627
+ const handleMouseMove = (e) => {
1628
+ callbacksRef.current.onMouseMove?.(e);
1629
+ };
1630
+ const handleMouseDown = (e) => {
1631
+ callbacksRef.current.onMouseDown?.(e);
1632
+ };
1633
+ const handleMouseUp = (e) => {
1634
+ callbacksRef.current.onMouseUp?.(e);
1635
+ };
1636
+ const handleContextMenu = (e) => {
1637
+ callbacksRef.current.onContextMenu?.(e);
1638
+ };
1639
+ const handleDoubleClick = (e) => {
1640
+ callbacksRef.current.onDoubleClick?.(e);
1641
+ };
1642
+ if (onClick) map.on("click", id, handleClick);
1643
+ if (onMouseEnter) map.on("mouseenter", id, handleMouseEnter);
1644
+ if (onMouseLeave) map.on("mouseleave", id, handleMouseLeave);
1645
+ if (onMouseMove) map.on("mousemove", id, handleMouseMove);
1646
+ if (onMouseDown) map.on("mousedown", id, handleMouseDown);
1647
+ if (onMouseUp) map.on("mouseup", id, handleMouseUp);
1648
+ if (onContextMenu) map.on("contextmenu", id, handleContextMenu);
1649
+ if (onDoubleClick) map.on("dblclick", id, handleDoubleClick);
1650
+ return () => {
1651
+ if (onClick) map.off("click", id, handleClick);
1652
+ if (onMouseEnter) map.off("mouseenter", id, handleMouseEnter);
1653
+ if (onMouseLeave) map.off("mouseleave", id, handleMouseLeave);
1654
+ if (onMouseMove) map.off("mousemove", id, handleMouseMove);
1655
+ if (onMouseDown) map.off("mousedown", id, handleMouseDown);
1656
+ if (onMouseUp) map.off("mouseup", id, handleMouseUp);
1657
+ if (onContextMenu) map.off("contextmenu", id, handleContextMenu);
1658
+ if (onDoubleClick) map.off("dblclick", id, handleDoubleClick);
1659
+ };
1660
+ }, [
1661
+ map,
1662
+ id,
1663
+ onClick,
1664
+ onMouseEnter,
1665
+ onMouseLeave,
1666
+ onMouseMove,
1667
+ onMouseDown,
1668
+ onMouseUp,
1669
+ onContextMenu,
1670
+ onDoubleClick
1671
+ ]);
1672
+ const mapInternal = map;
1673
+ const layer = map && mapInternal.style && map.getLayer(id);
1416
1674
  if (layer) {
1417
1675
  try {
1418
1676
  updateLayer(map, id, props, propsRef.current);
@@ -1425,19 +1683,768 @@ function Layer(props) {
1425
1683
  propsRef.current = props;
1426
1684
  return null;
1427
1685
  }
1686
+ var Layer = (0, import_react16.memo)(_Layer);
1687
+
1688
+ // src/components/draw-control.ts
1689
+ var import_react17 = require("react");
1690
+ var import_maplibre_gl_draw = __toESM(require("maplibre-gl-draw"), 1);
1691
+ var defaultDrawOptions = {
1692
+ displayControlsDefault: false,
1693
+ controls: {
1694
+ polygon: true,
1695
+ trash: true
1696
+ }
1697
+ };
1698
+ function _DrawControl(props) {
1699
+ const {
1700
+ position,
1701
+ style,
1702
+ onDrawCreate,
1703
+ onDrawDelete,
1704
+ onDrawUpdate,
1705
+ onDrawSelectionChange,
1706
+ onDrawModeChange,
1707
+ onDrawCombine,
1708
+ onDrawUncombine,
1709
+ onDrawRender,
1710
+ ...drawOptions
1711
+ } = props;
1712
+ const context = (0, import_react17.useContext)(MapContext);
1713
+ if (!context) {
1714
+ throw new Error("DrawControl must be used within a Map component");
1715
+ }
1716
+ const options = (0, import_react17.useMemo)(
1717
+ () => ({
1718
+ ...defaultDrawOptions,
1719
+ ...drawOptions,
1720
+ controls: {
1721
+ ...defaultDrawOptions.controls,
1722
+ ...drawOptions.controls
1723
+ }
1724
+ }),
1725
+ [
1726
+ drawOptions.displayControlsDefault,
1727
+ drawOptions.controls,
1728
+ drawOptions.styles,
1729
+ drawOptions.modes,
1730
+ drawOptions.defaultMode
1731
+ ]
1732
+ );
1733
+ const optionsKey = (0, import_react17.useMemo)(() => JSON.stringify(options), [options]);
1734
+ const callbacksRef = (0, import_react17.useRef)({
1735
+ onDrawCreate,
1736
+ onDrawDelete,
1737
+ onDrawUpdate,
1738
+ onDrawSelectionChange,
1739
+ onDrawModeChange,
1740
+ onDrawCombine,
1741
+ onDrawUncombine,
1742
+ onDrawRender
1743
+ });
1744
+ (0, import_react17.useEffect)(() => {
1745
+ callbacksRef.current = {
1746
+ onDrawCreate,
1747
+ onDrawDelete,
1748
+ onDrawUpdate,
1749
+ onDrawSelectionChange,
1750
+ onDrawModeChange,
1751
+ onDrawCombine,
1752
+ onDrawUncombine,
1753
+ onDrawRender
1754
+ };
1755
+ }, [
1756
+ onDrawCreate,
1757
+ onDrawDelete,
1758
+ onDrawUpdate,
1759
+ onDrawSelectionChange,
1760
+ onDrawModeChange,
1761
+ onDrawCombine,
1762
+ onDrawUncombine,
1763
+ onDrawRender
1764
+ ]);
1765
+ const ctrlRef = (0, import_react17.useRef)(null);
1766
+ const listenersRef = (0, import_react17.useRef)({});
1767
+ (0, import_react17.useEffect)(() => {
1768
+ const { map } = context;
1769
+ if (!map) return;
1770
+ const mapInstance = map.getMap();
1771
+ if (!mapInstance) return;
1772
+ const DrawClass = import_maplibre_gl_draw.default;
1773
+ const resetCursorIfNeeded = () => {
1774
+ if (ctrlRef.current) {
1775
+ const currentMode = ctrlRef.current.getMode();
1776
+ if (currentMode === "simple_select") {
1777
+ mapInstance.getCanvas().style.cursor = "";
1778
+ }
1779
+ }
1780
+ };
1781
+ const handleCreate = (e) => {
1782
+ resetCursorIfNeeded();
1783
+ callbacksRef.current.onDrawCreate?.(e);
1784
+ };
1785
+ const handleUpdate = (e) => {
1786
+ resetCursorIfNeeded();
1787
+ callbacksRef.current.onDrawUpdate?.(e);
1788
+ };
1789
+ const handleDelete = (e) => {
1790
+ resetCursorIfNeeded();
1791
+ callbacksRef.current.onDrawDelete?.(e);
1792
+ };
1793
+ const handleSelectionChange = (e) => {
1794
+ resetCursorIfNeeded();
1795
+ callbacksRef.current.onDrawSelectionChange?.(e);
1796
+ };
1797
+ const handleModeChange = (e) => {
1798
+ resetCursorIfNeeded();
1799
+ callbacksRef.current.onDrawModeChange?.(e);
1800
+ };
1801
+ const handleCombine = (e) => {
1802
+ callbacksRef.current.onDrawCombine?.(e);
1803
+ };
1804
+ const handleUncombine = (e) => {
1805
+ callbacksRef.current.onDrawUncombine?.(e);
1806
+ };
1807
+ const handleRender = (e) => {
1808
+ callbacksRef.current.onDrawRender?.(e);
1809
+ };
1810
+ const ctrl = new DrawClass(options);
1811
+ ctrlRef.current = ctrl;
1812
+ map.addControl(ctrl, position);
1813
+ listenersRef.current = {
1814
+ handleCreate,
1815
+ handleUpdate,
1816
+ handleDelete,
1817
+ handleSelectionChange,
1818
+ handleModeChange,
1819
+ handleCombine,
1820
+ handleUncombine,
1821
+ handleRender
1822
+ };
1823
+ mapInstance.on("draw.create", handleCreate);
1824
+ mapInstance.on("draw.update", handleUpdate);
1825
+ mapInstance.on("draw.delete", handleDelete);
1826
+ mapInstance.on("draw.selectionchange", handleSelectionChange);
1827
+ mapInstance.on("draw.modechange", handleModeChange);
1828
+ mapInstance.on("draw.combine", handleCombine);
1829
+ mapInstance.on("draw.uncombine", handleUncombine);
1830
+ mapInstance.on("draw.render", handleRender);
1831
+ return () => {
1832
+ if (listenersRef.current.handleCreate) {
1833
+ mapInstance.off("draw.create", listenersRef.current.handleCreate);
1834
+ }
1835
+ if (listenersRef.current.handleUpdate) {
1836
+ mapInstance.off("draw.update", listenersRef.current.handleUpdate);
1837
+ }
1838
+ if (listenersRef.current.handleDelete) {
1839
+ mapInstance.off("draw.delete", listenersRef.current.handleDelete);
1840
+ }
1841
+ if (listenersRef.current.handleSelectionChange) {
1842
+ mapInstance.off("draw.selectionchange", listenersRef.current.handleSelectionChange);
1843
+ }
1844
+ if (listenersRef.current.handleModeChange) {
1845
+ mapInstance.off("draw.modechange", listenersRef.current.handleModeChange);
1846
+ }
1847
+ if (listenersRef.current.handleCombine) {
1848
+ mapInstance.off("draw.combine", listenersRef.current.handleCombine);
1849
+ }
1850
+ if (listenersRef.current.handleUncombine) {
1851
+ mapInstance.off("draw.uncombine", listenersRef.current.handleUncombine);
1852
+ }
1853
+ if (listenersRef.current.handleRender) {
1854
+ mapInstance.off("draw.render", listenersRef.current.handleRender);
1855
+ }
1856
+ if (ctrlRef.current && map.hasControl(ctrlRef.current)) {
1857
+ map.removeControl(ctrlRef.current);
1858
+ }
1859
+ ctrlRef.current = null;
1860
+ };
1861
+ }, [context, optionsKey, position]);
1862
+ return null;
1863
+ }
1864
+ var DrawControl = (0, import_react17.memo)(_DrawControl);
1865
+
1866
+ // src/components/globe-control.ts
1867
+ var import_react18 = require("react");
1868
+ var GLOBE_SVG = `<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2">
1869
+ <circle cx="12" cy="12" r="9" fill="none"/>
1870
+ <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"/>
1871
+ <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"/>
1872
+ </svg>`;
1873
+ var MAP_SVG = `<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2">
1874
+ <rect x="3" y="3" width="18" height="18" rx="2" fill="none"/>
1875
+ <path d="M3 9h18M3 15h18M9 3v18M15 3v18"/>
1876
+ </svg>`;
1877
+ var GlobeControlImpl = class {
1878
+ constructor(options, callbacks) {
1879
+ this._map = null;
1880
+ this._isGlobe = false;
1881
+ this._options = options;
1882
+ this._onProjectionChange = callbacks.onProjectionChange;
1883
+ this._container = document.createElement("div");
1884
+ this._container.className = "maplibregl-ctrl maplibregl-ctrl-group";
1885
+ this._button = this._createButton();
1886
+ this._container.appendChild(this._button);
1887
+ }
1888
+ _createButton() {
1889
+ const button = this._options.buttonElement || document.createElement("button");
1890
+ if (!this._options.buttonElement) {
1891
+ button.className = this._options.buttonClassName || "maplibregl-ctrl-globe";
1892
+ button.type = "button";
1893
+ button.title = this._options.buttonTitle || "Toggle Globe View";
1894
+ button.setAttribute("aria-label", "Toggle Globe View");
1895
+ button.innerHTML = this._isGlobe ? MAP_SVG : GLOBE_SVG;
1896
+ Object.assign(button.style, {
1897
+ padding: "5px",
1898
+ border: "none",
1899
+ background: "white",
1900
+ cursor: "pointer",
1901
+ borderRadius: "4px",
1902
+ display: "flex",
1903
+ alignItems: "center",
1904
+ justifyContent: "center",
1905
+ ...this._options.buttonStyle
1906
+ });
1907
+ }
1908
+ button.addEventListener("click", () => this._toggleGlobe());
1909
+ return button;
1910
+ }
1911
+ _toggleGlobe() {
1912
+ if (!this._map) return;
1913
+ this._isGlobe = !this._isGlobe;
1914
+ this._button.innerHTML = this._isGlobe ? MAP_SVG : GLOBE_SVG;
1915
+ this._button.title = this._isGlobe ? "Switch to Map View" : "Switch to Globe View";
1916
+ try {
1917
+ const projection = this._isGlobe ? { type: "globe" } : { type: "mercator" };
1918
+ this._map.setProjection(projection);
1919
+ this._onProjectionChange?.(this._isGlobe);
1920
+ } catch (error) {
1921
+ console.warn("GlobeControl: setProjection not available", error);
1922
+ }
1923
+ }
1924
+ onAdd(map) {
1925
+ this._map = map;
1926
+ try {
1927
+ const currentProjection = map.getProjection?.();
1928
+ this._isGlobe = currentProjection?.type === "globe";
1929
+ this._button.innerHTML = this._isGlobe ? MAP_SVG : GLOBE_SVG;
1930
+ } catch {
1931
+ this._isGlobe = false;
1932
+ }
1933
+ return this._container;
1934
+ }
1935
+ onRemove() {
1936
+ this._container.parentNode?.removeChild(this._container);
1937
+ this._map = null;
1938
+ }
1939
+ /**
1940
+ * Check if currently in globe view
1941
+ */
1942
+ isGlobe() {
1943
+ return this._isGlobe;
1944
+ }
1945
+ /**
1946
+ * Set the projection programmatically
1947
+ */
1948
+ setGlobe(isGlobe) {
1949
+ if (this._isGlobe !== isGlobe) {
1950
+ this._toggleGlobe();
1951
+ }
1952
+ }
1953
+ };
1954
+ function _GlobeControl(props) {
1955
+ const { position, onProjectionChange, ...options } = props;
1956
+ const callbacksRef = (0, import_react18.useRef)({ onProjectionChange });
1957
+ (0, import_react18.useEffect)(() => {
1958
+ callbacksRef.current = { onProjectionChange };
1959
+ }, [onProjectionChange]);
1960
+ useControl(
1961
+ () => {
1962
+ return new GlobeControlImpl(options, {
1963
+ onProjectionChange: (isGlobe) => callbacksRef.current.onProjectionChange?.(isGlobe)
1964
+ });
1965
+ },
1966
+ { position }
1967
+ );
1968
+ return null;
1969
+ }
1970
+ var GlobeControl = (0, import_react18.memo)(_GlobeControl);
1971
+
1972
+ // src/components/minimap-control.ts
1973
+ var import_react19 = require("react");
1974
+ var import_maplibre_gl = require("maplibre-gl");
1975
+ var DEFAULT_ZOOM_ADJUST = -4;
1976
+ var DEFAULT_COLLAPSED_SIZE = "29px";
1977
+ var DEFAULT_BORDER_RADIUS = "3px";
1978
+ var TRANSITION_DURATION_MS = 600;
1979
+ var RESIZE_DEBOUNCE_MS = 100;
1980
+ var DEFAULT_WIDTH = "400px";
1981
+ var DEFAULT_HEIGHT = "300px";
1982
+ var defaultInteractions = {
1983
+ dragPan: true,
1984
+ scrollZoom: false,
1985
+ boxZoom: false,
1986
+ dragRotate: false,
1987
+ keyboard: false,
1988
+ doubleClickZoom: false,
1989
+ touchZoomRotate: false
1990
+ };
1991
+ 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>`;
1992
+ function getRandomUUID() {
1993
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
1994
+ return crypto.randomUUID();
1995
+ }
1996
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
1997
+ const array = new Uint8Array(1);
1998
+ crypto.getRandomValues(array);
1999
+ const r = array[0] % 16;
2000
+ const v = c === "x" ? r : r & 3 | 8;
2001
+ return v.toString(16);
2002
+ });
2003
+ }
2004
+ function sanitizeSVG(svgString) {
2005
+ const svgPattern = /^<svg[^>]*>[\s\S]*<\/svg>$/i;
2006
+ if (!svgPattern.test(svgString)) {
2007
+ console.warn("Invalid SVG format, using default icon");
2008
+ return DEFAULT_ICON;
2009
+ }
2010
+ return svgString.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi, "").replace(/javascript:/gi, "");
2011
+ }
2012
+ var Minimap = class {
2013
+ constructor(options = {}) {
2014
+ this.differentStyle = false;
2015
+ this.isMinimized = false;
2016
+ this.id = `minimap-${getRandomUUID()}`;
2017
+ if (options.style !== void 0) {
2018
+ this.differentStyle = true;
2019
+ }
2020
+ const interactions = { ...defaultInteractions, ...options.interactions ?? {} };
2021
+ const containerStyle = this.validateContainerStyle(options.containerStyle);
2022
+ this.options = {
2023
+ zoomAdjust: DEFAULT_ZOOM_ADJUST,
2024
+ position: "top-right",
2025
+ pitchAdjust: false,
2026
+ attributionControl: false,
2027
+ logoPosition: "bottom-left",
2028
+ toggleable: true,
2029
+ initialMinimized: false,
2030
+ collapsedWidth: DEFAULT_COLLAPSED_SIZE,
2031
+ collapsedHeight: DEFAULT_COLLAPSED_SIZE,
2032
+ borderRadius: DEFAULT_BORDER_RADIUS,
2033
+ hideText: "Hide minimap",
2034
+ showText: "Show minimap",
2035
+ responsive: true,
2036
+ responsiveWidth: "20vw",
2037
+ responsiveHeight: "20vh",
2038
+ minWidth: "200px",
2039
+ minHeight: "150px",
2040
+ maxWidth: DEFAULT_WIDTH,
2041
+ maxHeight: DEFAULT_HEIGHT,
2042
+ interactions,
2043
+ ...options,
2044
+ containerStyle
2045
+ };
2046
+ if (options.lockZoom !== void 0) {
2047
+ this.options.minZoom = options.lockZoom;
2048
+ this.options.maxZoom = options.lockZoom;
2049
+ }
2050
+ this.isMinimized = this.options.initialMinimized ?? false;
2051
+ }
2052
+ onAdd(parentMap) {
2053
+ this.parentMap = parentMap;
2054
+ this.container = this.createContainer();
2055
+ this.options.container = this.container;
2056
+ this.options.zoom = parentMap.getZoom() + (this.options.zoomAdjust ?? DEFAULT_ZOOM_ADJUST);
2057
+ this.options.center ??= parentMap.getCenter().toArray();
2058
+ this.options.bearing = parentMap.getBearing();
2059
+ this.options.pitch = this.options.pitchAdjust ? parentMap.getPitch() : 0;
2060
+ if (!this.differentStyle) {
2061
+ this.options.style = parentMap.getStyle();
2062
+ }
2063
+ this.map = new import_maplibre_gl.Map(this.options);
2064
+ this.map.once("style.load", () => {
2065
+ this.map.resize();
2066
+ });
2067
+ this.map.once("load", () => {
2068
+ this.configureInteractions();
2069
+ this.addParentRect(this.options.parentRect);
2070
+ this.desync = this.syncMaps();
2071
+ this.setupToggleButton();
2072
+ this.setupResponsiveSizing();
2073
+ });
2074
+ return this.container;
2075
+ }
2076
+ onRemove() {
2077
+ if (this.resizeHandler) {
2078
+ window.removeEventListener("resize", this.resizeHandler);
2079
+ this.resizeHandler = void 0;
2080
+ }
2081
+ this.toggleButtonCleanup?.();
2082
+ this.desync?.();
2083
+ this.container.remove();
2084
+ }
2085
+ createContainer() {
2086
+ const container = document.createElement("div");
2087
+ container.id = this.id;
2088
+ container.className = "maplibregl-ctrl maplibregl-ctrl-group maplibregl-ctrl-minimap custom-ctrl-minimap";
2089
+ if (this.isMinimized) {
2090
+ container.classList.add("minimized");
2091
+ }
2092
+ const styleEl = document.createElement("style");
2093
+ styleEl.innerHTML = this.getContainerStyles();
2094
+ container.appendChild(styleEl);
2095
+ if (this.options.containerStyle) {
2096
+ for (const [key, value] of Object.entries(this.options.containerStyle)) {
2097
+ container.style.setProperty(key, value);
2098
+ }
2099
+ }
2100
+ if (this.isMinimized) {
2101
+ container.style.width = this.options.collapsedWidth || DEFAULT_COLLAPSED_SIZE;
2102
+ container.style.height = this.options.collapsedHeight || DEFAULT_COLLAPSED_SIZE;
2103
+ }
2104
+ const preventDefault = (e) => e.preventDefault();
2105
+ container.addEventListener("contextmenu", preventDefault);
2106
+ return container;
2107
+ }
2108
+ getContainerStyles() {
2109
+ const width = this.options.containerStyle?.width || DEFAULT_WIDTH;
2110
+ const height = this.options.containerStyle?.height || DEFAULT_HEIGHT;
2111
+ const collapsedWidth = this.options.collapsedWidth || DEFAULT_COLLAPSED_SIZE;
2112
+ const collapsedHeight = this.options.collapsedHeight || DEFAULT_COLLAPSED_SIZE;
2113
+ const borderRadius = this.options.borderRadius || DEFAULT_BORDER_RADIUS;
2114
+ return `
2115
+ #${this.id}.custom-ctrl-minimap {
2116
+ cursor: default !important;
2117
+ box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
2118
+ transition: width 0.6s ease-in, height 0.6s ease-in, border-color 0s ease-in;
2119
+ border-style: solid;
2120
+ border-radius: ${borderRadius};
2121
+ border-width: 4px;
2122
+ border-color: white;
2123
+ width: ${width};
2124
+ height: ${height};
2125
+ overflow: hidden;
2126
+ background: #fff;
2127
+ position: relative;
2128
+ }
2129
+ #${this.id}.minimized {
2130
+ border-radius: 3px !important;
2131
+ width: ${collapsedWidth};
2132
+ height: ${collapsedHeight};
2133
+ }
2134
+ #${this.id} canvas {
2135
+ width: 100% !important;
2136
+ height: 100% !important;
2137
+ display: block;
2138
+ }
2139
+ @media (prefers-color-scheme: dark) {
2140
+ #${this.id}.custom-ctrl-minimap {
2141
+ border-color: hsl(0, 0%, 15.2%);
2142
+ }
2143
+ }
2144
+ `;
2145
+ }
2146
+ validateContainerStyle(style) {
2147
+ const defaults = { border: "1px solid #000", width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
2148
+ if (!style) return defaults;
2149
+ const validated = {};
2150
+ if (style.width) {
2151
+ validated.width = CSS.supports("width", style.width) ? style.width : defaults.width;
2152
+ } else {
2153
+ validated.width = defaults.width;
2154
+ }
2155
+ if (style.height) {
2156
+ validated.height = CSS.supports("height", style.height) ? style.height : defaults.height;
2157
+ } else {
2158
+ validated.height = defaults.height;
2159
+ }
2160
+ for (const [key, value] of Object.entries(style)) {
2161
+ if (key !== "width" && key !== "height") {
2162
+ validated[key] = value;
2163
+ }
2164
+ }
2165
+ return validated;
2166
+ }
2167
+ configureInteractions() {
2168
+ const interactions = this.options.interactions || defaultInteractions;
2169
+ for (const [interaction, enabled] of Object.entries(interactions)) {
2170
+ if (!enabled) {
2171
+ const interactionMethod = interaction;
2172
+ const interactionObj = this.map[interactionMethod];
2173
+ interactionObj?.disable();
2174
+ }
2175
+ }
2176
+ }
2177
+ setupToggleButton() {
2178
+ if (!this.options.toggleable) return;
2179
+ const el = document.createElement("button");
2180
+ const elId = "btn-" + getRandomUUID();
2181
+ el.innerHTML = sanitizeSVG(this.options.toggleButton?.icon || DEFAULT_ICON);
2182
+ el.setAttribute("id", elId);
2183
+ el.setAttribute("type", "button");
2184
+ el.setAttribute("aria-label", this.options.hideText || "Hide minimap");
2185
+ el.setAttribute("title", this.options.hideText || "Hide minimap");
2186
+ if (this.options.toggleButton?.className) {
2187
+ const classes = this.options.toggleButton.className.split(" ");
2188
+ classes.forEach((cls) => el.classList.add(cls));
2189
+ }
2190
+ const iconBackgroundColor = this.options.toggleButton?.iconBackgroundColor || "black";
2191
+ const hoverColor = this.options.toggleButton?.hoverColor || "#e5e7e3";
2192
+ const styleEl = document.createElement("style");
2193
+ styleEl.innerHTML = `
2194
+ button#${elId} {
2195
+ border-radius: 0 !important;
2196
+ color: black;
2197
+ background-color: ${iconBackgroundColor};
2198
+ border: none;
2199
+ display: flex;
2200
+ align-items: center;
2201
+ justify-content: center;
2202
+ cursor: pointer;
2203
+ transition: all 0.2s ease-in;
2204
+ position: absolute;
2205
+ width: 24px;
2206
+ height: 24px;
2207
+ z-index: 2;
2208
+ padding: 0;
2209
+ left: 0;
2210
+ top: 0;
2211
+ }
2212
+ button#${elId}:hover {
2213
+ background-color: ${hoverColor} !important;
2214
+ }
2215
+ button#${elId} svg {
2216
+ fill: white;
2217
+ width: 16px;
2218
+ height: 16px;
2219
+ }
2220
+ .minimized > button#${elId} > * {
2221
+ transform: rotate(-180deg);
2222
+ }
2223
+ `;
2224
+ const clickHandler = () => {
2225
+ this.toggle();
2226
+ const minimized = this.container.classList.contains("minimized");
2227
+ const text = minimized ? this.options.showText || "Show minimap" : this.options.hideText || "Hide minimap";
2228
+ el.setAttribute("aria-label", text);
2229
+ el.setAttribute("title", text);
2230
+ };
2231
+ el.addEventListener("click", clickHandler);
2232
+ document.head.appendChild(styleEl);
2233
+ this.container.appendChild(el);
2234
+ this.toggleButtonCleanup = () => {
2235
+ el.removeEventListener("click", clickHandler);
2236
+ styleEl.remove();
2237
+ this.container.removeChild(el);
2238
+ };
2239
+ }
2240
+ setupResponsiveSizing() {
2241
+ if (!this.options.responsive) return;
2242
+ const updateSize = () => {
2243
+ if (this.isMinimized) return;
2244
+ const vw = window.innerWidth / 100;
2245
+ const vh = window.innerHeight / 100;
2246
+ const responsiveWidth = this.options.responsiveWidth || "20vw";
2247
+ const responsiveHeight = this.options.responsiveHeight || "20vh";
2248
+ let width;
2249
+ let height;
2250
+ if (responsiveWidth.endsWith("vw")) {
2251
+ width = parseFloat(responsiveWidth) * vw;
2252
+ } else if (responsiveWidth.endsWith("%")) {
2253
+ width = parseFloat(responsiveWidth) / 100 * window.innerWidth;
2254
+ } else {
2255
+ width = parseFloat(responsiveWidth);
2256
+ }
2257
+ if (responsiveHeight.endsWith("vh")) {
2258
+ height = parseFloat(responsiveHeight) * vh;
2259
+ } else if (responsiveHeight.endsWith("%")) {
2260
+ height = parseFloat(responsiveHeight) / 100 * window.innerHeight;
2261
+ } else {
2262
+ height = parseFloat(responsiveHeight);
2263
+ }
2264
+ const minW = parseFloat(this.options.minWidth || "200px");
2265
+ const minH = parseFloat(this.options.minHeight || "150px");
2266
+ const maxW = parseFloat(this.options.maxWidth || DEFAULT_WIDTH);
2267
+ const maxH = parseFloat(this.options.maxHeight || DEFAULT_HEIGHT);
2268
+ width = Math.max(minW, Math.min(maxW, width));
2269
+ height = Math.max(minH, Math.min(maxH, height));
2270
+ this.container.style.width = `${width}px`;
2271
+ this.container.style.height = `${height}px`;
2272
+ this.map.resize();
2273
+ this.setParentBounds();
2274
+ };
2275
+ updateSize();
2276
+ let resizeTimeout;
2277
+ this.resizeHandler = () => {
2278
+ clearTimeout(resizeTimeout);
2279
+ resizeTimeout = setTimeout(updateSize, RESIZE_DEBOUNCE_MS);
2280
+ };
2281
+ window.addEventListener("resize", this.resizeHandler);
2282
+ }
2283
+ toggle() {
2284
+ this.isMinimized = !this.isMinimized;
2285
+ const collapsedWidth = this.options.collapsedWidth || DEFAULT_COLLAPSED_SIZE;
2286
+ const collapsedHeight = this.options.collapsedHeight || DEFAULT_COLLAPSED_SIZE;
2287
+ if (this.isMinimized) {
2288
+ this.container.classList.add("minimized");
2289
+ this.container.style.width = collapsedWidth;
2290
+ this.container.style.height = collapsedHeight;
2291
+ } else {
2292
+ this.container.classList.remove("minimized");
2293
+ if (this.options.responsive && this.resizeHandler) {
2294
+ this.resizeHandler();
2295
+ } else {
2296
+ const expandedWidth = this.options.containerStyle?.width || DEFAULT_WIDTH;
2297
+ const expandedHeight = this.options.containerStyle?.height || DEFAULT_HEIGHT;
2298
+ this.container.style.width = expandedWidth;
2299
+ this.container.style.height = expandedHeight;
2300
+ }
2301
+ }
2302
+ this.options.onToggle?.(this.isMinimized);
2303
+ setTimeout(() => {
2304
+ this.map.resize();
2305
+ this.setParentBounds();
2306
+ }, TRANSITION_DURATION_MS);
2307
+ }
2308
+ isMinimizedState() {
2309
+ return this.isMinimized;
2310
+ }
2311
+ addParentRect(rect) {
2312
+ if (rect === void 0 || rect.linePaint === void 0 && rect.fillPaint === void 0) {
2313
+ return;
2314
+ }
2315
+ this.parentRect = {
2316
+ type: "Feature",
2317
+ properties: { name: "parentRect" },
2318
+ geometry: {
2319
+ type: "Polygon",
2320
+ coordinates: [[[], [], [], [], []]]
2321
+ }
2322
+ };
2323
+ this.map.addSource("parentRect", {
2324
+ type: "geojson",
2325
+ data: this.parentRect
2326
+ });
2327
+ if (rect.lineLayout !== void 0 || rect.linePaint !== void 0) {
2328
+ this.map.addLayer({
2329
+ id: "parentRectOutline",
2330
+ type: "line",
2331
+ source: "parentRect",
2332
+ layout: { ...rect.lineLayout || {} },
2333
+ paint: {
2334
+ "line-color": "#FFF",
2335
+ "line-width": 1,
2336
+ "line-opacity": 0.85,
2337
+ ...rect.linePaint || {}
2338
+ }
2339
+ });
2340
+ }
2341
+ if (rect.fillPaint !== void 0) {
2342
+ this.map.addLayer({
2343
+ id: "parentRectFill",
2344
+ type: "fill",
2345
+ source: "parentRect",
2346
+ layout: {},
2347
+ paint: {
2348
+ "fill-color": "#08F",
2349
+ "fill-opacity": 0.135,
2350
+ ...rect.fillPaint || {}
2351
+ }
2352
+ });
2353
+ }
2354
+ this.setParentBounds();
2355
+ }
2356
+ setParentBounds() {
2357
+ if (this.parentRect === void 0 || this.isMinimized) return;
2358
+ const { devicePixelRatio } = window;
2359
+ const canvas = this.parentMap.getCanvas();
2360
+ const width = canvas.width / devicePixelRatio;
2361
+ const height = canvas.height / devicePixelRatio;
2362
+ const unproject = this.parentMap.unproject.bind(this.parentMap);
2363
+ const northWest = unproject([0, 0]);
2364
+ const northEast = unproject([width, 0]);
2365
+ const southWest = unproject([0, height]);
2366
+ const southEast = unproject([width, height]);
2367
+ this.parentRect.geometry.coordinates = [
2368
+ [
2369
+ southWest.toArray(),
2370
+ southEast.toArray(),
2371
+ northEast.toArray(),
2372
+ northWest.toArray(),
2373
+ southWest.toArray()
2374
+ ]
2375
+ ];
2376
+ const source = this.map.getSource("parentRect");
2377
+ if (source !== void 0) {
2378
+ source.setData(this.parentRect);
2379
+ }
2380
+ }
2381
+ syncMaps() {
2382
+ const { pitchAdjust } = this.options;
2383
+ const parentCallback = () => {
2384
+ if (!this.isMinimized) {
2385
+ sync("parent");
2386
+ }
2387
+ };
2388
+ const minimapCallback = () => {
2389
+ if (!this.isMinimized) {
2390
+ sync("minimap");
2391
+ }
2392
+ };
2393
+ const on = () => {
2394
+ this.parentMap.on("move", parentCallback);
2395
+ this.map.on("move", minimapCallback);
2396
+ };
2397
+ const off = () => {
2398
+ this.parentMap.off("move", parentCallback);
2399
+ this.map.off("move", minimapCallback);
2400
+ };
2401
+ const sync = (which) => {
2402
+ off();
2403
+ const from = which === "parent" ? this.parentMap : this.map;
2404
+ const to = which === "parent" ? this.map : this.parentMap;
2405
+ const center = from.getCenter();
2406
+ const zoom = from.getZoom() + (this.options.zoomAdjust ?? DEFAULT_ZOOM_ADJUST) * (which === "parent" ? 1 : -1);
2407
+ const bearing = from.getBearing();
2408
+ const pitch = from.getPitch();
2409
+ to.jumpTo({
2410
+ center,
2411
+ zoom,
2412
+ bearing,
2413
+ pitch: pitchAdjust ? pitch : 0
2414
+ });
2415
+ this.setParentBounds();
2416
+ on();
2417
+ };
2418
+ on();
2419
+ return () => {
2420
+ off();
2421
+ };
2422
+ }
2423
+ };
2424
+ function _MinimapControl(props) {
2425
+ const { position, ...options } = props;
2426
+ useControl(() => new Minimap(options), { position });
2427
+ return null;
2428
+ }
2429
+ var MinimapControl = (0, import_react19.memo)(_MinimapControl);
1428
2430
 
1429
2431
  // src/exports-maplibre-gl.ts
1430
2432
  var exports_maplibre_gl_default = Map;
1431
2433
  // Annotate the CommonJS export names for ESM import in node:
1432
2434
  0 && (module.exports = {
1433
2435
  AttributionControl,
2436
+ CanvasSource,
2437
+ DrawControl,
1434
2438
  FullscreenControl,
1435
2439
  GeolocateControl,
2440
+ GlobeControl,
1436
2441
  Layer,
1437
2442
  LogoControl,
1438
2443
  Map,
1439
2444
  MapProvider,
1440
2445
  Marker,
2446
+ Minimap,
2447
+ MinimapControl,
1441
2448
  NavigationControl,
1442
2449
  Popup,
1443
2450
  ScaleControl,