maplibre-react-components
Version:
React components for MapLibre GL JS
1,422 lines (1,400 loc) • 61.5 kB
JavaScript
"use client";
//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
const react = __toESM(require("react"));
const maplibre_gl = __toESM(require("maplibre-gl"));
const react_jsx_runtime = __toESM(require("react/jsx-runtime"));
const react_dom = __toESM(require("react-dom"));
//#region src/lib/util.ts
function filterMapProps(options) {
const callbacks = {};
const mapHandlerOptions = {};
const mapReactiveOptions = {};
for (const key in options) if (key.startsWith("on")) callbacks[key] = options[key];
else if (mapHandlerNames.includes(key)) mapHandlerOptions[key] = options[key];
else if (mapReactiveOptionNames.includes(key)) mapReactiveOptions[key] = options[key];
else if (!key.startsWith("initial") && key !== "container" && key !== "style") throw Error(`unknown map option key ${key}`);
return [
mapReactiveOptions,
callbacks,
mapHandlerOptions
];
}
function transformPropsToOptions(props, optionKeyWhiteList) {
const callbacks = {};
const options = {};
for (const key in props) {
if (optionKeyWhiteList?.includes(key)) {
options[key] = props[key];
continue;
}
if (key.startsWith("on")) callbacks[key] = props[key];
else {
const definitiveKey = key.startsWith("initial") ? key[7].toLowerCase() + key.substring(8) : key;
if (options[definitiveKey]) throw new Error(`duplicate key ${definitiveKey}`);
else options[definitiveKey] = props[key];
}
}
return [options, callbacks];
}
function prepareEventDep(eventNameToCallbackName$5, callbacks) {
const activeEvents = Object.keys(eventNameToCallbackName$5).filter((eventName) => eventNameToCallbackName$5[eventName] in callbacks);
return activeEvents.sort();
}
/**
* from : react-map-gl/src/utils/deep-equal.ts
* Compare any two objects
* @param a
* @param b
* @returns true if the objects are deep equal
*/
function deepEqual(a, b) {
if (a === b) return true;
if (!a || !b) return false;
if (Array.isArray(a)) {
if (!Array.isArray(b) || a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;
return true;
} else if (Array.isArray(b)) return false;
if (typeof a === "object" && typeof b === "object") {
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) return false;
for (const key of aKeys) {
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
if (!deepEqual(a[key], b[key])) return false;
}
return true;
}
return false;
}
function areLngLatClose(lngLat1, lngLat2) {
if (!lngLat1 && !lngLat2) return true;
if (!lngLat1 || !lngLat2) return false;
return Math.round(lngLat1.lng * 1e5) === Math.round(lngLat2.lng * 1e5) && Math.round(lngLat1.lat * 1e5) === Math.round(lngLat2.lat * 1e5);
}
function areCoordsClose(coords1, coords2) {
if (!coords1 && !coords2) return true;
if (!coords1 || !coords2) return false;
const lngLat1 = maplibre_gl.default.LngLat.convert(coords1);
const lngLat2 = maplibre_gl.default.LngLat.convert(coords2);
return Math.round(lngLat1.lng * 1e5) === Math.round(lngLat2.lng * 1e5) && Math.round(lngLat1.lat * 1e5) === Math.round(lngLat2.lat * 1e5);
}
function lngLatClassToObj(lngLat) {
return {
lng: lngLat.lng,
lat: lngLat.lat
};
}
function arePointsEqual(a, b) {
const ax = Array.isArray(a) ? a[0] : a ? a.x : 0;
const ay = Array.isArray(a) ? a[1] : a ? a.y : 0;
const bx = Array.isArray(b) ? b[0] : b ? b.x : 0;
const by = Array.isArray(b) ? b[1] : b ? b.y : 0;
return ax === bx && ay === by;
}
function updateClassNames(elt, prevClassNames, nextClassNames) {
prevClassNames.forEach((name) => {
if (name === "") return;
if (nextClassNames.indexOf(name) === -1) elt.classList.remove(name);
});
nextClassNames.forEach((name) => {
if (name === "") return;
if (prevClassNames.indexOf(name) === -1 || !elt.classList.contains(name)) elt.classList.add(name);
});
}
function updateListeners(prevEventTypes, nextEventTypes, onSubscribe, onUnsubscribe) {
prevEventTypes.forEach((eventName) => {
if (eventName !== "" && nextEventTypes.indexOf(eventName) === -1) onUnsubscribe(eventName);
});
nextEventTypes.forEach((eventName) => {
if (eventName !== "" && prevEventTypes.indexOf(eventName) === -1) onSubscribe(eventName);
});
}
const markerHeight = 41 - 5.8 / 2;
const markerRadius = 13.5;
const linearOffset = Math.abs(markerRadius) / Math.SQRT2;
const markerPopupOffset = {
top: [0, 0],
"top-left": [0, 0],
"top-right": [0, 0],
bottom: [0, -markerHeight],
"bottom-left": [linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
"bottom-right": [-linearOffset, (markerHeight - markerRadius + linearOffset) * -1],
left: [markerRadius, (markerHeight - markerRadius) * -1],
right: [-markerRadius, (markerHeight - markerRadius) * -1]
};
const gradientMarkerHeight = 50;
const gradientMarkerPopupOffset = {
top: [0, 0],
"top-left": [0, 0],
"top-right": [0, 0],
bottom: [0, -gradientMarkerHeight],
"bottom-left": [linearOffset, (gradientMarkerHeight - markerRadius + linearOffset) * -1],
"bottom-right": [-linearOffset, (gradientMarkerHeight - markerRadius + linearOffset) * -1],
left: [markerRadius, (gradientMarkerHeight - markerRadius) * -1],
right: [-markerRadius, (gradientMarkerHeight - markerRadius) * -1]
};
const emptyStyle = {
version: 8,
name: "Empty",
sources: {},
layers: []
};
function uniqueId() {
const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < 8; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
result += characters[randomIndex];
}
return result;
}
//#endregion
//#region src/lib/MapManager.ts
const eventNameToCallbackName$4 = {
mousedown: "onMouseDown",
mouseup: "onMouseUp",
mouseover: "onMouseOver",
mouseout: "onMouseOut",
mousemove: "onMouseMove",
mouseenter: "onMouseEnter",
mouseleave: "onMouseLeave",
click: "onClick",
dblclick: "onDblClick",
contextmenu: "onContextMenu",
touchstart: "onTouchStart",
touchend: "onTouchEnd",
touchcancel: "onTouchCancel",
touchmove: "onTouchMove",
movestart: "onMoveStart",
move: "onMove",
moveend: "onMoveEnd",
dragstart: "onDragStart",
drag: "onDrag",
dragend: "onDragEnd",
zoomstart: "onZoomStart",
zoom: "onZoom",
zoomend: "onZoomEnd",
rotatestart: "onRotateStart",
rotate: "onRotate",
rotateend: "onRotateEnd",
pitchstart: "onPitchStart",
pitch: "onPitch",
pitchend: "onPitchEnd",
wheel: "onWheel",
resize: "onResize",
remove: "onRemove",
boxzoomstart: "onBoxZoomStart",
boxzoomend: "onBoxZoomEnd",
boxzoomcancel: "onBoxZoomCancel",
webglcontextlost: "onWebglContextLost",
webglcontextrestored: "onWebglContextRestored",
load: "onLoad",
render: "onRender",
idle: "onIdle",
error: "onError",
data: "onData",
styledata: "onStyleData",
sourcedata: "onSourceData",
dataloading: "onDataLoading",
styledataloading: "onStyleDataLoading",
sourcedataloading: "onSourceDataLoading",
tiledataloading: "onTileDataLoading",
styleimagemissing: "onStyleImageMissing",
dataabort: "onDataAbort",
sourcedataabort: "onSourceDataAbort",
terrain: "onTerrain"
};
const mapReactiveOptionNames = [
"maxBounds",
"minZoom",
"maxZoom",
"minPitch",
"maxPitch",
"renderWorldCopies",
"pixelRatio",
"centerClampedToGround"
];
const mapHandlerNames = [
"scrollZoom",
"boxZoom",
"dragRotate",
"dragPan",
"keyboard",
"doubleClickZoom",
"touchZoomRotate",
"touchPitch",
"cooperativeGestures"
];
const DEFAULT_STYLE = "https://demotiles.maplibre.org/style.json";
var MapManager = class {
reactiveOptions = {};
handlerOptions = {};
eventNames = [];
callbacks;
_map;
padding;
mapStyle;
controlledSources = {};
controlledLayers = {};
controlledTerrain = null;
constructor({ mapStyle = DEFAULT_STYLE, padding }, mapProps, container) {
this.mapStyle = mapStyle;
this.padding = padding;
const [mapBaseOptions, callbacks] = transformPropsToOptions(mapProps);
this.callbacks = callbacks;
const mapOptions = {
...mapBaseOptions,
container,
style: mapStyle
};
const map = new maplibre_gl.default.Map(mapOptions);
map.style.on("error", this._onStyleError);
if (padding) map.setPadding(padding);
this._map = map;
this._updateCallbacks(callbacks);
}
setProps({ mapStyle = DEFAULT_STYLE, styleDiffing = true, styleTransformStyle, padding }, mapProps) {
const [reactiveOptions, callbacks, handlerOptions] = filterMapProps(mapProps);
this._updateCallbacks(callbacks);
this._updateStyle(mapStyle, {
diff: styleDiffing,
transformStyle: styleTransformStyle
});
this._updateReactiveOptions(reactiveOptions, { padding });
this._updateHandlers(handlerOptions);
}
getControlledTerrain() {
return this.controlledTerrain;
}
setControlledTerrain(terrainProps) {
this.controlledTerrain = terrainProps;
}
getControlledLayer(id) {
return this.controlledLayers[id] ?? null;
}
setControlledLayer(id, layerProps) {
if (!layerProps) delete this.controlledLayers[id];
else this.controlledLayers[id] = layerProps;
}
getControlledSource(id) {
return this.controlledSources[id] ?? null;
}
setControlledSource(id, layerProps) {
if (!layerProps) delete this.controlledSources[id];
else this.controlledSources[id] = layerProps;
}
_updateStyle(nextStyle, options) {
const curStyle = this.mapStyle;
if (nextStyle !== curStyle) {
this.mapStyle = nextStyle;
this._map.setStyle(nextStyle, {
diff: options.diff,
transformStyle: (prevStyle, nextStyle$1) => {
const prevControlledSources = prevStyle ? Object.fromEntries(Object.entries(prevStyle?.sources).filter(([sourceId]) => sourceId in this.controlledSources)) : {};
const prevControlledLayers = prevStyle ? prevStyle.layers.filter((layer) => layer.id in this.controlledLayers) : [];
const result = {
...nextStyle$1,
sources: {
...nextStyle$1.sources,
...prevControlledSources
},
layers: [...nextStyle$1.layers, ...prevControlledLayers],
terrain: this.controlledTerrain ? prevStyle?.terrain : nextStyle$1.terrain
};
return options.transformStyle ? options.transformStyle(prevStyle, result) : result;
}
});
}
}
_updateReactiveOptions(nextReactiveOptions, { padding }) {
const currReactiveOptions = this.reactiveOptions;
this.reactiveOptions = nextReactiveOptions;
for (const optionName of mapReactiveOptionNames) if (optionName in nextReactiveOptions && !deepEqual(currReactiveOptions[optionName], nextReactiveOptions[optionName])) {
const setterName = `set${optionName[0].toUpperCase()}${optionName.substring(1)}`;
this._map[setterName](nextReactiveOptions[optionName]);
}
if (padding && !deepEqual(this.padding, padding)) this._map.setPadding(padding);
this.padding = padding;
}
_updateCallbacks(callbacks = {}) {
this.callbacks = callbacks;
const nextEventNames = prepareEventDep(eventNameToCallbackName$4, callbacks);
if (this.eventNames.join("-") === nextEventNames.join("-")) return;
updateListeners(this.eventNames, nextEventNames, (eventName) => this._map.on(eventName, this._onMapEvent), (eventName) => this._map.off(eventName, this._onMapEvent));
this.eventNames = nextEventNames;
}
_updateHandlers(nextHandlers) {
const currHandlers = this.handlerOptions;
this.handlerOptions = nextHandlers;
for (const propName of mapHandlerNames) {
const nextValue = nextHandlers[propName] ?? true;
const currValue = currHandlers[propName] ?? true;
if (!deepEqual(nextValue, currValue)) if (nextValue) this._map[propName].enable(nextValue);
else this._map[propName].disable();
}
}
_onStyleError = (event) => {
if (event.error.name !== "AbortError") console.error(event.error);
};
_onMapEvent = (e) => {
const eventType = e.type;
const callbackName = eventNameToCallbackName$4[eventType];
if (this.callbacks[callbackName]) this.callbacks[callbackName]?.(e);
else console.info("not managed RMap event", eventType, e);
};
get map() {
return this._map;
}
destroy() {
this._updateCallbacks();
this._map.remove();
}
};
//#endregion
//#region src/hooks/useIsomorphicLayoutEffect.ts
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
//#endregion
//#region src/lib/MapManagers.ts
var MapManagers = class {
_maps = {};
_listeners = {};
add(id, mapManager) {
this._maps[id] = mapManager;
this._listeners[id]?.forEach(([mounted, setMounted]) => {
if (!mounted) setMounted(true);
});
}
remove(id) {
delete this._maps[id];
this._listeners[id]?.forEach(([mounted, setMounted]) => {
if (mounted) setMounted(false);
});
}
get(id) {
if (!id) return null;
return this._maps[id] ?? null;
}
addListener(id, mountedState) {
if (this._listeners[id]) this._listeners[id].push(mountedState);
else this._listeners[id] = [mountedState];
const isMounted = !!this._maps[id];
if (mountedState[0] !== isMounted) mountedState[1](isMounted);
}
removeListener(id, [, callback]) {
this._listeners[id] = this._listeners[id].filter(([, cb]) => cb !== callback);
}
};
//#endregion
//#region src/contexts/RMapContextProvider.tsx
const RMapContext = (0, react.createContext)(null);
const RMapContextProvider = ({ children }) => {
const mapManagersRef = (0, react.useRef)(null);
if (!mapManagersRef.current) mapManagersRef.current = new MapManagers();
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RMapContext.Provider, {
value: mapManagersRef,
children
});
};
//#endregion
//#region src/contexts/CurrentMapIdContext.ts
const CurrentMapIdContext = (0, react.createContext)(null);
//#endregion
//#region src/components/RMap/RMap.tsx
const childContainerStyle = { height: "100%" };
const RMap = (0, react.forwardRef)(function RMap$1({ children, style, id: propsId, className, onMounted, mapStyle, styleDiffing, styleTransformStyle, padding,...mapProps }, ref) {
const containerRef = (0, react.useRef)(null);
const needPropsUpdate = (0, react.useRef)(true);
const idRef = (0, react.useRef)(propsId ?? uniqueId());
if (propsId && propsId !== idRef.current) throw new Error(`RMap id should not change. "${propsId}" "${idRef.current}". If you defined id as const string add a "key" prop to your RMap component`);
const id = idRef.current;
const externalMapManagersRef = (0, react.useContext)(RMapContext);
const localMapManagersRef = (0, react.useRef)(null);
if (!externalMapManagersRef && !localMapManagersRef.current) localMapManagersRef.current = new MapManagers();
const mapManagers = externalMapManagersRef ? externalMapManagersRef.current : localMapManagersRef.current;
const [, reRender] = (0, react.useState)(0);
/**
* we need to init mapManager before useImperativeHandle call
* so necessary inside useLayoutEffect
* (useLayoutEffect and useImperativeHandle are called in same priority)
* parent component will have access to reference in useLayoutEffect / useEffect hooks
*/
useIsomorphicLayoutEffect(() => {
const mapManager = mapManagers.get(id);
if (!mapManager) {
const instance = new MapManager({
mapStyle,
styleDiffing,
padding
}, mapProps, containerRef.current);
mapManagers.add(id, instance);
onMounted && onMounted(instance.map);
reRender((v) => v + 1);
needPropsUpdate.current = false;
} else if (needPropsUpdate.current) mapManager.setProps({
mapStyle,
padding,
styleDiffing,
styleTransformStyle
}, mapProps);
else needPropsUpdate.current = true;
});
useIsomorphicLayoutEffect(() => {
return () => {
const mapManager = mapManagers.get(id);
if (mapManager) {
mapManager.destroy();
mapManagers.remove(id);
}
};
}, []);
(0, react.useImperativeHandle)(ref, () => mapManagers.get(id)?.map || null, [id, mapManagers]);
/**
* container class attribute must not be controlled by React
* - maplibre GL add : maplibregl-map
* - other plugins can add classes dynamically
*/
useIsomorphicLayoutEffect(() => {
if (!className) return;
const container = containerRef.current;
className.split(" ").map((classItem) => container.classList.add(classItem));
return () => void className.split(" ").map((classItem) => container.classList.remove(classItem));
}, [className]);
const completeStyle = (0, react.useMemo)(() => ({
position: "relative",
width: "100%",
height: "100%",
...style
}), [style]);
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
ref: containerRef,
id,
style: completeStyle,
children: mapManagers.get(id) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CurrentMapIdContext.Provider, {
value: id,
children: externalMapManagersRef ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
className: "maplibregl-children",
style: childContainerStyle,
children
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RMapContext.Provider, {
value: localMapManagersRef,
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
className: "maplibregl-children",
style: childContainerStyle,
children
})
})
})
});
});
//#endregion
//#region src/hooks/useMapManager.ts
function useMapManager(optionalId) {
const mapManagersRef = (0, react.useContext)(RMapContext);
const currentMapId = (0, react.useContext)(CurrentMapIdContext);
const id = optionalId ?? currentMapId;
const mapManager = mapManagersRef?.current.get(id) ?? null;
const mountedState = (0, react.useState)(mapManager !== null);
if (!mapManagersRef?.current) throw new Error("use useMapManager in components inside <RMap /> or inside <RMapContextProvider />");
if (!id) throw new Error("provide an id to useMap or use inside <RMap />");
(0, react.useEffect)(() => {
const mapManagers = mapManagersRef.current;
if (!mapManagers) throw new Error("mapManagers can't disappear");
mapManagers.addListener(id, mountedState);
return () => {
mapManagers.removeListener(id, mountedState);
};
}, [
id,
mapManagersRef,
mountedState,
mapManager
]);
return mapManager;
}
//#endregion
//#region src/hooks/useMap.ts
function useMap(optionalId) {
return useMapManager(optionalId)?.map ?? null;
}
//#endregion
//#region src/components/RMarker/RMarker.tsx
const eventNameToCallbackName$3 = {
dragstart: "onDragStart",
drag: "onDrag",
dragend: "onDragEnd",
click: "onClick"
};
const RMarker = (0, react.memo)((0, react.forwardRef)(function RMarker$1(props, ref) {
const { longitude, latitude, children,...markerProps } = props;
const map = useMap();
const [options, callbacks] = transformPropsToOptions(markerProps);
const prevOptionsRef = (0, react.useRef)(options);
const callbacksRef = (0, react.useRef)(null);
callbacksRef.current = callbacks;
const marker = (0, react.useMemo)(() => {
const completeOptions = {
...options,
element: children ? document.createElement("div") : void 0
};
const mk = new maplibre_gl.default.Marker(completeOptions);
mk.setLngLat([longitude, latitude]);
return mk;
}, []);
const nextEventsStr = prepareEventDep(eventNameToCallbackName$3, callbacks).join("-");
(0, react.useEffect)(() => {
function onMarkerEvent(e) {
const eventType = e.type;
const callbackName = eventNameToCallbackName$3[eventType];
if (callbacksRef.current?.[callbackName]) callbacksRef.current[callbackName]?.(e);
else console.info("not managed RMarker event", eventType, e);
}
const eventNames = nextEventsStr.split("-");
eventNames.forEach((eventName) => {
if (eventName === "click") marker.getElement().addEventListener("click", onMarkerEvent);
else marker.on(eventName, onMarkerEvent);
});
return () => {
eventNames.forEach((eventName) => {
if (eventName === "click") marker.getElement().removeEventListener("click", onMarkerEvent);
else marker.off(eventName, onMarkerEvent);
});
};
}, [nextEventsStr, marker]);
(0, react.useEffect)(() => {
marker.addTo(map);
return () => void marker.remove();
}, []);
const { className, offset, draggable, clickTolerance = 0, rotation, rotationAlignment, subpixelPositioning = false, pitchAlignment, opacity, opacityWhenCovered } = options;
(0, react.useImperativeHandle)(ref, () => marker, [marker]);
if (prevOptionsRef.current.className !== className) updateClassNames(marker._element, prevOptionsRef.current.className?.split(" ") || [], className?.split(" ") || []);
if (marker.getLngLat().lng !== longitude || marker.getLngLat().lat !== latitude) marker.setLngLat([longitude, latitude]);
if (offset && !arePointsEqual(marker.getOffset(), offset)) marker.setOffset(offset);
if (marker.isDraggable() !== draggable) marker.setDraggable(draggable);
if (marker._clickTolerance !== clickTolerance) marker._clickTolerance = clickTolerance;
if (marker.getRotation() !== rotation) marker.setRotation(rotation);
if (marker.getRotationAlignment() !== rotationAlignment) marker.setRotationAlignment(rotationAlignment);
if (marker.getPitchAlignment() !== pitchAlignment) marker.setPitchAlignment(pitchAlignment);
if (marker._opacity !== opacity || marker._opacityWhenCovered !== opacityWhenCovered) marker.setOpacity(opacity, opacityWhenCovered);
if (marker.setSubpixelPositioning && marker._subpixelPositioning !== subpixelPositioning) marker.setSubpixelPositioning(subpixelPositioning);
prevOptionsRef.current = options;
return children ? (0, react_dom.createPortal)(children, marker.getElement()) : null;
}));
//#endregion
//#region src/components/RPopup/RPopup.tsx
const eventNameToCallbackName$2 = {
map_click: "onMapClick",
map_move: "onMapMove"
};
const RPopup = (0, react.memo)((0, react.forwardRef)(function RPopup$1(props, ref) {
const { longitude, latitude, children,...popupProps } = props;
const map = useMap();
const [options, callbacks] = transformPropsToOptions(popupProps);
const popupRef = (0, react.useRef)(null);
const prevOptionsRef = (0, react.useRef)(options);
const currCallbacksRef = (0, react.useRef)(null);
currCallbacksRef.current = callbacks;
const container = (0, react.useMemo)(() => {
return document.createElement("div");
}, []);
if (!popupRef.current) {
popupRef.current = new maplibre_gl.default.Popup({
...options,
closeButton: false,
closeOnClick: false,
closeOnMove: false
});
if (longitude !== void 0 && latitude !== void 0) popupRef.current.setLngLat([longitude, latitude]);
}
const nextEventsStr = prepareEventDep(eventNameToCallbackName$2, callbacks).join("-");
(0, react.useEffect)(() => {
function onPopupEvent(e) {
const eventType = e.type;
const callbackName = eventNameToCallbackName$2[eventType] || eventNameToCallbackName$2[`map_${eventType}`];
if (currCallbacksRef.current?.[callbackName]) currCallbacksRef.current[callbackName]?.(e);
else console.info("not managed RPopup event", eventType, e);
}
if (nextEventsStr === "") return;
const eventNames = nextEventsStr.split("-");
const popupStable = popupRef.current;
eventNames.forEach((eventName) => {
if (eventName.startsWith("map_")) map.on(eventName.substring(4), onPopupEvent);
else popupStable.on(eventName, onPopupEvent);
});
return () => {
eventNames.forEach((eventName) => {
if (eventName.startsWith("map_")) map.off(eventName.substring(4), onPopupEvent);
else popupStable.off(eventName, onPopupEvent);
});
};
}, [nextEventsStr, map]);
(0, react.useEffect)(() => {
popupRef.current.setDOMContent(container).addTo(map);
return () => void popupRef.current.remove();
}, [container, map]);
const { offset, maxWidth = "240px", className } = options;
(0, react.useImperativeHandle)(ref, () => popupRef.current, [popupRef]);
if (popupRef.current.isOpen()) {
if (longitude !== void 0 && latitude !== void 0 && (popupRef.current.getLngLat().lng !== longitude || popupRef.current.getLngLat().lat !== latitude)) popupRef.current.setLngLat([longitude, latitude]);
if (offset && !deepEqual(popupRef.current.options.offset, offset)) popupRef.current.setOffset(offset);
if (prevOptionsRef.current.className !== className) updateClassNames(container, prevOptionsRef.current.className?.split(" ") || [], className?.split(" ") || []);
if (popupRef.current.getMaxWidth() !== maxWidth) popupRef.current.setMaxWidth(maxWidth);
}
prevOptionsRef.current = options;
return (0, react_dom.createPortal)(children, container);
}));
//#endregion
//#region src/components/RLayer/RLayer.tsx
const eventNameToCallbackName$1 = {
mousedown: "onMouseDown",
mouseup: "onMouseUp",
mouseover: "onMouseOver",
mouseout: "onMouseOut",
mousemove: "onMouseMove",
mouseenter: "onMouseEnter",
mouseleave: "onMouseLeave",
click: "onClick",
dblclick: "onDblClick",
contextmenu: "onContextMenu",
touchstart: "onTouchStart",
touchend: "onTouchEnd",
touchcancel: "onTouchCancel",
touchmove: "onTouchMove"
};
function createLayer(map, layerOptions, beforeId) {
if (map.style?._loaded) {
if (layerOptions.type === "background" || layerOptions.type === "custom" || layerOptions.source && map.getSource(layerOptions.source)) {
map.addLayer(layerOptions, beforeId && map.getLayer(beforeId) ? beforeId : void 0);
return map.getLayer(layerOptions.id);
}
}
return void 0;
}
function updateLayer(map, { beforeId: nextBeforeId,...nextOptions }, { beforeId: prevBeforeId,...prevOptions }) {
if (prevOptions.type === "custom" || nextOptions.type === "custom") return;
if (prevBeforeId !== nextBeforeId) map.moveLayer(nextOptions.id, nextBeforeId);
/**
* we take random LayerSpecification to simulate same specification.
* here FillLayerSpecification
*/
if (nextOptions.type !== "background" && nextOptions.type !== "custom" && prevOptions.filter !== nextOptions.filter) map.setFilter(nextOptions.id, nextOptions.filter);
const prevO = prevOptions;
const nextO = nextOptions;
if (prevO.layout !== nextO.layout) {
if (nextO.layout) {
for (const key of Object.keys(nextO.layout)) if (nextO.layout[key] !== prevO.layout?.[key]) map.setLayoutProperty(nextOptions.id, key, nextO.layout[key]);
}
for (const key in prevO.layout) if (!Object.prototype.hasOwnProperty.call(nextO.layout, key)) map.setLayoutProperty(nextOptions.id, key, void 0);
}
if (prevO.paint !== nextO.paint) {
if (nextO.paint) {
for (const key of Object.keys(nextO.paint)) if (nextO.paint[key] !== prevO.paint?.[key]) map.setPaintProperty(nextOptions.id, key, nextO.paint[key]);
}
for (const key in prevO.paint) if (!Object.prototype.hasOwnProperty.call(nextO.paint, key)) map.setPaintProperty(nextOptions.id, key, void 0);
}
if (prevO.minzoom !== nextO.minzoom || prevO.maxzoom !== nextO.maxzoom) {
if (nextO.minzoom && nextO.maxzoom) map.setLayerZoomRange(nextOptions.id, nextO.minzoom, nextO.maxzoom);
}
}
const RLayer = (0, react.memo)((0, react.forwardRef)(function RLayer$1(props, ref) {
const { beforeId,...layerProps } = props;
const [layerOptions, callbacks] = transformPropsToOptions(layerProps, ["onAdd"]);
const id = layerOptions.id;
const mapManager = useMapManager();
if (!mapManager) throw new Error("use <RLayer /> component inside <RMap />");
const map = mapManager.map;
const initialLayerId = (0, react.useRef)(id);
if (id !== initialLayerId.current) throw new Error(`RLayer id should not change. "${id}" "${initialLayerId.current}". If you defined id as const string add a "key" prop to your RLayer component`);
const prevProps = mapManager.getControlledLayer(id) ?? props;
const [, setVersion] = (0, react.useState)(0);
const reRender = (0, react.useCallback)(() => setVersion((v) => v + 1), []);
if (props.type !== prevProps.type) throw new Error(`RLayer type should not change. "${props.type}" "${prevProps.type}"`);
const callbacksRef = (0, react.useRef)(null);
callbacksRef.current = callbacks;
(0, react.useEffect)(() => {
map.on("styledata", reRender);
if (map.style && map.style._loaded) reRender();
return () => {
map.off("styledata", reRender);
if (map.style && map.style._loaded && map.getLayer(id)) map.removeLayer(id);
mapManager?.setControlledLayer(id, null);
};
}, [
map,
id,
mapManager,
reRender
]);
const nextEventsStr = prepareEventDep(eventNameToCallbackName$1, callbacks).join("-");
(0, react.useEffect)(() => {
function onLayerEvent(e) {
const eventType = e.type;
const callbackName = eventNameToCallbackName$1[eventType];
if (callbacksRef.current?.[callbackName]) callbacksRef.current[callbackName]?.(e);
else console.info("not managed RLayer event", eventType, e);
}
const eventNames = nextEventsStr.split("-");
eventNames.forEach((eventName) => {
map.on(eventName, id, onLayerEvent);
});
return () => {
eventNames.forEach((eventName) => {
map.off(eventName, id, onLayerEvent);
});
};
}, [
nextEventsStr,
id,
map
]);
let layer = map.style?._loaded && map.getLayer(id);
if (layer) updateLayer(map, props, prevProps);
else {
layer = createLayer(map, layerOptions, beforeId);
if (layer) map.off("styledata", reRender);
}
(0, react.useImperativeHandle)(ref, () => layer || null, [layer]);
mapManager.setControlledLayer(id, props);
return null;
}));
//#endregion
//#region src/components/RSource/RSource.tsx
function createSource(map, id, sourceOptions) {
if (map.style?._loaded) {
map.addSource(id, sourceOptions);
return map.getSource(id);
}
return void 0;
}
function updateSource(source, nextOptions, prevOptions) {
switch (nextOptions.type) {
case "image": {
const prevO = prevOptions;
const nextO = nextOptions;
if (prevO.url !== nextO.url) source.updateImage({
url: nextO.url,
coordinates: nextO.coordinates
});
if (prevO.coordinates !== nextO.coordinates) source.setCoordinates(nextO.coordinates);
break;
}
case "video": {
const prevO = prevOptions;
const nextO = nextOptions;
if (prevO.coordinates !== nextO.coordinates) source.setCoordinates(nextO.coordinates);
break;
}
case "geojson": {
const prevO = prevOptions;
const nextO = nextOptions;
if (prevO.data !== nextO.data) source.setData(nextO.data);
if (prevO.cluster !== nextO.cluster || prevO.clusterMaxZoom !== nextO.clusterMaxZoom || prevO.clusterRadius !== nextO.clusterRadius) source.setClusterOptions({
cluster: nextO.cluster,
clusterMaxZoom: nextO.clusterMaxZoom,
clusterRadius: nextO.clusterRadius
});
break;
}
case "raster":
case "raster-dem":
case "vector": {
const prevO = prevOptions;
const nextO = nextOptions;
if (prevO.tiles !== nextO.tiles && nextO.tiles) source.setTiles(nextO.tiles);
if (prevO.url !== nextO.url && nextO.url) source.setUrl(nextO.url);
break;
}
}
}
const RSource = (0, react.memo)((0, react.forwardRef)(function RSource$1(props, ref) {
const { id,...sourceOptions } = props;
const mapManager = useMapManager();
const map = mapManager.map;
const initialId = (0, react.useRef)(id);
if (id !== initialId.current) throw new Error(`RSource id should not change. "${id}" "${initialId.current}". If you defined id as const string add a "key" prop to your RSource component`);
const { id: _,...prevOptions } = mapManager.getControlledSource(id) ?? props;
if (sourceOptions.type !== prevOptions.type) throw new Error(`RSource type should not change. "${sourceOptions.type}" "${prevOptions.type}"`);
const [, setVersion] = (0, react.useState)(0);
const reRender = (0, react.useCallback)(() => void setTimeout(() => setVersion((v) => v + 1), 0), []);
(0, react.useEffect)(() => {
/**
* fired when
* - new source added/removed
* - new layer added/removed
* when event is fired map.style._loaded is always true
*/
map.on("styledata", reRender);
if (map.style && map.style._loaded) reRender();
return () => {
map.off("styledata", reRender);
if (map.style && map.getSource(id)) {
const layers = map.getStyle()?.layers;
if (layers) {
for (const layer of layers) if (layer.type !== "background" && layer.type !== "custom" && layer.source === id) map.removeLayer(layer.id);
}
map.removeSource(id);
}
mapManager?.setControlledSource(id, null);
};
}, [
map,
id,
mapManager,
reRender
]);
let source = map.style?._loaded && map.getSource(id);
if (source) updateSource(source, sourceOptions, prevOptions);
else {
source = createSource(map, id, sourceOptions);
if (source) map.off("styledata", reRender);
}
(0, react.useImperativeHandle)(ref, () => source || null, [source]);
mapManager.setControlledSource(id, props);
return null;
}));
//#endregion
//#region src/components/RTerrain/RTerrain.tsx
const RTerrain = (props) => {
const terrainOptions = props;
const mapManager = useMapManager();
const map = mapManager.map;
const prevOptions = mapManager.getControlledTerrain() ?? props;
const [, setVersion] = (0, react.useState)(0);
const reRender = (0, react.useCallback)(() => setVersion((v) => v + 1), []);
(0, react.useEffect)(() => {
map.on("styledata", reRender);
if (map.style && map.style._loaded) reRender();
return () => {
map.off("styledata", reRender);
if (map.style?._loaded && map.getTerrain()) map.setTerrain(null);
mapManager?.setControlledTerrain(null);
};
}, [
map,
mapManager,
reRender
]);
const terrain = map.style?._loaded && (map.getSource(terrainOptions.source) ? map.getTerrain() : false);
if (terrain) {
if (prevOptions.exaggeration !== terrainOptions.exaggeration || prevOptions.source !== terrainOptions.source) map.setTerrain(terrainOptions);
} else if (map.style?._loaded) {
if (map.getSource(terrainOptions.source)) {
map.setTerrain(terrainOptions);
map.off("styledata", reRender);
}
}
mapManager.setControlledTerrain(props);
return null;
};
//#endregion
//#region ../../node_modules/.pnpm/@mapbox+point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.js
/**
* A standalone point geometry with useful accessor, comparison, and
* modification methods.
*
* @class
* @param {number} x the x-coordinate. This could be longitude or screen pixels, or any other sort of unit.
* @param {number} y the y-coordinate. This could be latitude or screen pixels, or any other sort of unit.
*
* @example
* const point = new Point(-77, 38);
*/
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype = {
clone() {
return new Point(this.x, this.y);
},
add(p) {
return this.clone()._add(p);
},
sub(p) {
return this.clone()._sub(p);
},
multByPoint(p) {
return this.clone()._multByPoint(p);
},
divByPoint(p) {
return this.clone()._divByPoint(p);
},
mult(k) {
return this.clone()._mult(k);
},
div(k) {
return this.clone()._div(k);
},
rotate(a) {
return this.clone()._rotate(a);
},
rotateAround(a, p) {
return this.clone()._rotateAround(a, p);
},
matMult(m) {
return this.clone()._matMult(m);
},
unit() {
return this.clone()._unit();
},
perp() {
return this.clone()._perp();
},
round() {
return this.clone()._round();
},
mag() {
return Math.sqrt(this.x * this.x + this.y * this.y);
},
equals(other) {
return this.x === other.x && this.y === other.y;
},
dist(p) {
return Math.sqrt(this.distSqr(p));
},
distSqr(p) {
const dx = p.x - this.x, dy = p.y - this.y;
return dx * dx + dy * dy;
},
angle() {
return Math.atan2(this.y, this.x);
},
angleTo(b) {
return Math.atan2(this.y - b.y, this.x - b.x);
},
angleWith(b) {
return this.angleWithSep(b.x, b.y);
},
angleWithSep(x, y) {
return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
},
_matMult(m) {
const x = m[0] * this.x + m[1] * this.y, y = m[2] * this.x + m[3] * this.y;
this.x = x;
this.y = y;
return this;
},
_add(p) {
this.x += p.x;
this.y += p.y;
return this;
},
_sub(p) {
this.x -= p.x;
this.y -= p.y;
return this;
},
_mult(k) {
this.x *= k;
this.y *= k;
return this;
},
_div(k) {
this.x /= k;
this.y /= k;
return this;
},
_multByPoint(p) {
this.x *= p.x;
this.y *= p.y;
return this;
},
_divByPoint(p) {
this.x /= p.x;
this.y /= p.y;
return this;
},
_unit() {
this._div(this.mag());
return this;
},
_perp() {
const y = this.y;
this.y = this.x;
this.x = -y;
return this;
},
_rotate(angle) {
const cos = Math.cos(angle), sin = Math.sin(angle), x = cos * this.x - sin * this.y, y = sin * this.x + cos * this.y;
this.x = x;
this.y = y;
return this;
},
_rotateAround(angle, p) {
const cos = Math.cos(angle), sin = Math.sin(angle), x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
this.x = x;
this.y = y;
return this;
},
_round() {
this.x = Math.round(this.x);
this.y = Math.round(this.y);
return this;
},
constructor: Point
};
/**
* Construct a point from an array if necessary, otherwise if the input
* is already a Point, return it unchanged.
* @param {Point | [number, number] | {x: number, y: number}} p input value
* @return {Point} constructed point.
* @example
* // this
* var point = Point.convert([0, 1]);
* // is equivalent to
* var point = new Point(0, 1);
*/
Point.convert = function(p) {
if (p instanceof Point) return p;
if (Array.isArray(p)) return new Point(+p[0], +p[1]);
if (p.x !== void 0 && p.y !== void 0) return new Point(+p.x, +p.y);
throw new Error("Expected [x, y] or {x, y} point format");
};
//#endregion
//#region src/maplibre-core/util/dom.ts
var DOM = class DOM {
static docStyle = typeof window !== "undefined" && window.document && window.document.documentElement.style;
static userSelect;
static selectProp = DOM.testProp([
"userSelect",
"MozUserSelect",
"WebkitUserSelect",
"msUserSelect"
]);
static transformProp = DOM.testProp(["transform", "WebkitTransform"]);
static testProp(props) {
if (!DOM.docStyle) return props[0];
for (let i = 0; i < props.length; i++) if (props[i] in DOM.docStyle) return props[i];
return props[0];
}
static create(tagName, className, container) {
const el = window.document.createElement(tagName);
if (className !== void 0) el.className = className;
if (container) container.appendChild(el);
return el;
}
static createNS(namespaceURI, tagName) {
const el = window.document.createElementNS(namespaceURI, tagName);
return el;
}
static disableDrag() {
if (DOM.docStyle && DOM.selectProp) {
DOM.userSelect = DOM.docStyle[DOM.selectProp];
DOM.docStyle[DOM.selectProp] = "none";
}
}
static enableDrag() {
if (DOM.docStyle && DOM.selectProp) DOM.docStyle[DOM.selectProp] = DOM.userSelect;
}
static setTransform(el, value) {
el.style[DOM.transformProp] = value;
}
static addEventListener(target, type, callback, options = {}) {
if ("passive" in options) target.addEventListener(type, callback, options);
else target.addEventListener(type, callback, options.capture);
}
static removeEventListener(target, type, callback, options = {}) {
if ("passive" in options) target.removeEventListener(type, callback, options);
else target.removeEventListener(type, callback, options.capture);
}
static suppressClickInternal(e) {
e.preventDefault();
e.stopPropagation();
window.removeEventListener("click", DOM.suppressClickInternal, true);
}
static suppressClick() {
window.addEventListener("click", DOM.suppressClickInternal, true);
window.setTimeout(() => {
window.removeEventListener("click", DOM.suppressClickInternal, true);
}, 0);
}
static getScale(element) {
const rect = element.getBoundingClientRect();
return {
x: rect.width / element.offsetWidth || 1,
y: rect.height / element.offsetHeight || 1,
boundingClientRect: rect
};
}
static getPoint(el, scale, e) {
const rect = scale.boundingClientRect;
return new Point((e.clientX - rect.left) / scale.x - el.clientLeft, (e.clientY - rect.top) / scale.y - el.clientTop);
}
static mousePos(el, e) {
const scale = DOM.getScale(el);
return DOM.getPoint(el, scale, e);
}
static touchPos(el, touches) {
const points = [];
const scale = DOM.getScale(el);
for (let i = 0; i < touches.length; i++) points.push(DOM.getPoint(el, scale, touches[i]));
return points;
}
static mouseButton(e) {
return e.button;
}
static remove(node) {
if (node.parentNode) node.parentNode.removeChild(node);
}
};
//#endregion
//#region src/components/RGradientMarker/GradientMarker.ts
const defaultColor = "#ffe64b";
const defaultHeight = 50;
var GradientMarker = class extends maplibre_gl.default.Marker {
_interactive;
_shape;
_icon;
_height = defaultHeight;
_text;
_circleElement = null;
_iconElement = null;
_textElement = null;
_markerElement;
constructor(options) {
options ??= {};
options.element = DOM.create("div", "maplibregl-gradient-marker");
if (options.className) options.element.classList.add(options.className);
super(options);
if (this._draggable) this._element.classList.add("draggable");
this._interactive = options && options.interactive === false ? false : "pending";
this._shape = (options && options.shape) ?? "pin";
this._color = (options && options.color) ?? defaultColor;
this._icon = options && options.icon;
this._text = options && options.text;
this._defaultMarker = true;
this._element.setAttribute("aria-label", "Map marker");
this._element.setAttribute("tabindex", "0");
this.setScale(this._scale);
this.setColor(this._color);
this._markerElement = DOM.create("div", `marker`);
this.setShape(this._shape);
if (this._text) this.setText(this._text);
else if (this._icon) this.setIcon(this._icon);
const target = DOM.create("div", "target");
this._element.appendChild(this._markerElement);
this._element.appendChild(target);
}
_onActive = () => {
/**
* draggable marker are pointer-events: none when dragging. we can't listen this._element.
* when listening this._map.getContainer() we don't have this issue
*/
this._map.getContainer().addEventListener("mouseup", this._onInactive, { once: true });
this._map.getContainer().addEventListener("touchend", this._onInactive, { once: true });
this._element.classList.add("active");
};
_onInactive = () => {
this._element.classList.remove("active");
};
addTo(map) {
maplibre_gl.default.Marker.prototype.addTo.apply(this, [map]);
if (this._interactive === "pending") this.setInteractive(true);
return this;
}
setInteractive(interactive = true) {
if (this._interactive === interactive) return;
this._interactive = interactive;
if (interactive) this._element.dataset.interactive = "";
else delete this._element.dataset.interactive;
if (interactive) {
this._element.addEventListener("mousedown", this._onActive);
this._element.addEventListener("touchstart", this._onActive);
} else {
this._element.removeEventListener("mousedown", this._onInactive);
this._element.removeEventListener("touchstart", this._onInactive);
}
}
getInteractive() {
return this._interactive;
}
remove() {
if (this._map) this.setInteractive(false);
maplibre_gl.default.Marker.prototype.remove.apply(this);
return this;
}
setIcon(icon) {
this.resetIconText();
this._icon = icon;
if (!icon) return this;
this._circleElement = DOM.create("div", "circle", this._markerElement);
if (typeof icon === "string") {
this._iconElement = DOM.create("i", icon, this._markerElement);
this._iconElement.className = icon || "";
} else if (typeof icon === "function") {
this._iconElement = icon();
this._markerElement?.append(this._iconElement);
} else {
this._iconElement = icon;
this._markerElement?.append(icon);
}
return this;
}
getIcon() {
return this._icon;
}
resetIconText() {
this._circleElement?.remove();
this._iconElement?.remove();
this._textElement?.remove();
this._circleElement = null;
this._iconElement = null;
this._textElement = null;
}
setText(text) {
this.resetIconText();
this._text = text;
if (!text) return this;
this._circleElement = DOM.create("div", "circle", this._markerElement);
this._textElement = DOM.create("div", "text", this._markerElement);
this._textElement.innerText = text;
return this;
}
getText() {
return this._text;
}
setColor(color) {
this._color = color || defaultColor;
this._element.style.setProperty("--marker-color", this._color);
return this;
}
getColor() {
return this._color;
}
setScale(scale = 1, markerHeight$1 = defaultHeight) {
this._scale = scale;
this._height = markerHeight$1 * this._scale;
this._element.style.setProperty("--marker-scale", scale.toString());
return this;
}
getScale() {
return this._scale;
}
setShape(shape) {
this._shape = shape || "pin";
this._anchor = this._shape === "circle" ? "center" : "bottom";
this._element.dataset.shape = this._shape;
this._update();
return this;
}
getShape() {
return this._shape;
}
setDraggable(shouldBeDraggable) {
maplibre_gl.default.Marker.prototype.setDraggable.apply(this, [shouldBeDraggable]);
this._element.classList.toggle("draggable", shouldBeDraggable);
return this;
}
};
//#endregion
//#region src/components/RGradientMarker/RGradientMarker.tsx
const eventNameToCallbackName = {
dragstart: "onDragStart",
drag: "onDrag",
dragend: "onDragEnd",
click: "onClick"
};
const RGradientMarker = (0, react.memo)((0, react.forwardRef)(function RGradientMarker$1(props, ref) {
const { longitude, latitude,...markerProps } = props;
const map = useMap();
const [options, markerCallbacks] = transformPropsToOptions(markerProps);
const prevOptionsRef = (0, react.useRef)(options);
const currCallbacksRef = (0, react.useRef)(null);
currCallbacksRef.current = markerCallbacks;
const marker = (0, react.useMemo)(() => {
const mk = new GradientMarker({
...options,
anchor: "bottom"
});
mk.setLngLat([longitude, latitude]);
return mk;
}, []);
const eventDepStr = prepareEventDep(eventNameToCallbackName, markerCallbacks).join("-");
(0, react.useEffect)(() => {
function onGradientMarkerEvent(e) {
const eventType = e.type;
const callbackName = eventNameToCallbackName[eventType];
if (currCallbacksRef.current?.[callbackName]) currCallbacksRef.current[callbackName]?.(e);
else console.info("not managed RGradientMarker event", eventType, e);
}
const eventNames = eventDepStr.split("-");
eventNames.forEach((eventName) => {
if (eventName === "click") marker.getElement().addEventListener("click", onGradientMarkerEvent);
else marker.on(eventName, onGradientMarkerEvent);
});
return () => {
eventNames.forEach((eventName) => {
if (eventName === "click") marker.getElement().removeEventListener("click", onGradientMarkerEvent);
else marker.off(eventName, onGradientMarkerEvent);
});
};
}, [eventDepStr, marker]);
(0, react.useEffect)(() => {
marker.addTo(map);
return () => void marker.remove();
}, []);
const { scale, color, text, icon, interactive, className, draggable, clickTolerance = 0, rotation, rotationAlignment, subpixelPositioning = false, pitchAlignment, shape, opacity, opacityWhenCovered } = options;
(0, react.useImperativeHandle)(ref, () => marker, [marker]);
if (prevOptionsRef.current.className !== className) updateClassNames(marker._element, prevOptionsRef.current.className?.split(" ") || [], className?.split(" ") || []);
if (marker.getInteractive() !== interactive) marker.setInteractive(interactive);
if (marker.getShape() !== shape) marker.setShape(shape);
if (marker.getLngLat().lng !== longitude || marker.getLngLat().lat !== latitude) marker.setLngLat([longitude, latitude]);
if (marker.isDraggable() !== draggable) marker.setDraggable(draggable);
if (marker._clickTolerance !== clickTolerance) marker._clickTolerance = clickTolerance;
if (marker.getRotation() !== rotation) marker.setRotation(rotation);
if (marker.getRotationAlignment() !== rotationAlignment) marker.setRotationAlignment(rotationAlignment);
if (marker.getPitchAlignment() !== pitchAlignment) marker.setPitchAlignment(pitchAlignment);
if (marker._opacity !== opacity || marker._opacityWhenCovered !== opacityWhenCovered) marker.setOpacity(opacity, opacityWhenCovered);
if (marker.setSubpixelPositioning && marker._subpixelPositioning !== subpixelPositioning) marker.setSubpixelPositioning(subpixelPositioning);
if (marker.getColor() !== color) marker.setColor(color);
if (marker.getScale() !== scale) marker.setScale(scale);
if (marker.getText() !== text) marker.setText(text);
/**
* getIcon return the option (string, HTMLElement, factory) not
* the HTMLElement created.
*/
if (marker.getIcon() !== icon) marker.setIcon(icon);
prevOptionsRef.current = options;
return null;
}));
//#endregion
//#region src/components/ContextMenuEventAdapter.ts
function ContextMenuEventAdapter({ customEventName = "contextmenu-maplibre", enabled = true }) {
const map = useMap();
(0, react.useEffect)(() => {
if (!enabled) return;
/**
* related issue: contextmenu not managed by Touch devices
* https://github.com/maplibre/maplibre-gl-js/issues/373
*
* we use click for touch device because touchend/mouseup can conflict with handlers.
*/
const eventName = window.matchMedia("(pointer: coarse)").matches ? "click" : "contextmenu";
function handleContextMenu(evt) {
/**
* we put a setTimeout to give time for the event to propagate and possibly cancel it
*/
setTimeout(() => {
if (evt.defaultPrevented) return;
const { originalEvent, poin