@mapka/react-maplibre-map
Version:
MapLibre react web component
102 lines (101 loc) • 3.61 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import * as maplibre from "maplibre-gl";
import { isEqual } from "es-toolkit";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { MapLibreContainer } from "./MapLibreContainer.js";
import { isEmpty } from "es-toolkit/compat";
import { MapLibreStyles } from "./MapLibreStyles.js";
const noopTransformRequest = (url) => {
return {
url,
};
};
const createTransformRequest = (apiKey, transformRequest) => (url) => {
if ((!isEmpty(apiKey) && url.includes("mapka.dev")) || url.includes("mapka.localhost")) {
return {
url,
headers: {
Authorization: `Bearer ${apiKey}`,
},
};
}
return transformRequest ? transformRequest(url) : noopTransformRequest(url);
};
export function MapLibreMap(props) {
const { BaseMap, width = "100%", height = "100%", center, zoom, style, transformRequest, onMapLoaded, apiKey, injectMaplibreStyles, } = props;
const container = useRef(null);
const map = useRef(null);
/*
* We want to this callback ref to be created only once. Deps update will be handled in dedicated useEffect
* biome-ignore lint/correctness/useExhaustiveDependencies: ref callback is created only once
*/
const initMap = useCallback((element) => {
if (!map.current && element) {
const mapOption = {
container: element,
style,
center,
zoom,
transformRequest: createTransformRequest(apiKey, transformRequest),
};
if (BaseMap) {
mapOption.apiKey = apiKey;
}
const mapInstance = BaseMap
? new BaseMap(mapOption)
: new maplibre.Map(mapOption);
container.current = element;
map.current = mapInstance;
if (onMapLoaded) {
mapInstance.once("load", () => {
onMapLoaded(mapInstance);
});
}
}
return () => {
if (map.current) {
map.current.remove();
map.current = null;
}
};
}, [apiKey]);
const currentMap = map.current;
useEffect(() => {
if (!currentMap)
return;
if (!Number.isInteger(zoom))
return;
const currentZoom = currentMap.getZoom();
if (!isEqual(currentZoom, zoom)) {
currentMap.setZoom(zoom);
}
}, [currentMap, zoom]);
useEffect(() => {
if (!currentMap)
return;
if (!Array.isArray(center))
return;
const currentCenter = currentMap.getCenter().toArray();
if (!isEqual(currentCenter, center)) {
currentMap.setCenter(center);
}
}, [currentMap, center]);
useEffect(() => {
if (!currentMap)
return;
currentMap.setStyle(style ?? null);
}, [currentMap, style]);
const styles = useMemo(() => {
return {
width: typeof width === "number" ? `${width}px` : width,
height: typeof height === "number" ? `${height}px` : height,
};
}, [width, height]);
if (!injectMaplibreStyles) {
return _jsx(MapLibreContainer, { ref: initMap, style: styles });
}
else {
return (_jsxs(_Fragment, { children: [_jsx(MapLibreStyles, {}), _jsx(MapLibreContainer, { ref: initMap, style: styles })] }));
}
}
MapLibreMap.displayName = "MapLibreMap";