@page-speed/maps 0.1.1 → 0.1.3

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.
Files changed (45) hide show
  1. package/LICENSE +24 -17
  2. package/README.md +530 -12
  3. package/dist/core/MapLibre.cjs +19 -5
  4. package/dist/core/MapLibre.cjs.map +1 -1
  5. package/dist/core/MapLibre.js +19 -5
  6. package/dist/core/MapLibre.js.map +1 -1
  7. package/dist/core/index.cjs +19 -5
  8. package/dist/core/index.cjs.map +1 -1
  9. package/dist/core/index.js +19 -5
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/hooks/index.cjs +109 -0
  12. package/dist/hooks/index.cjs.map +1 -0
  13. package/dist/hooks/index.d.cts +2 -0
  14. package/dist/hooks/index.d.ts +2 -0
  15. package/dist/hooks/index.js +104 -0
  16. package/dist/hooks/index.js.map +1 -0
  17. package/dist/hooks/useDefaultZoom.cjs +78 -0
  18. package/dist/hooks/useDefaultZoom.cjs.map +1 -0
  19. package/dist/hooks/useDefaultZoom.d.cts +30 -0
  20. package/dist/hooks/useDefaultZoom.d.ts +30 -0
  21. package/dist/hooks/useDefaultZoom.js +75 -0
  22. package/dist/hooks/useDefaultZoom.js.map +1 -0
  23. package/dist/hooks/useGeoCenter.cjs +39 -0
  24. package/dist/hooks/useGeoCenter.cjs.map +1 -0
  25. package/dist/hooks/useGeoCenter.d.cts +22 -0
  26. package/dist/hooks/useGeoCenter.d.ts +22 -0
  27. package/dist/hooks/useGeoCenter.js +36 -0
  28. package/dist/hooks/useGeoCenter.js.map +1 -0
  29. package/dist/index.cjs +120 -5
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +2 -0
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +118 -7
  34. package/dist/index.js.map +1 -1
  35. package/dist/utils/getMapLibreStyleUrl.cjs +19 -5
  36. package/dist/utils/getMapLibreStyleUrl.cjs.map +1 -1
  37. package/dist/utils/getMapLibreStyleUrl.d.cts +1 -1
  38. package/dist/utils/getMapLibreStyleUrl.d.ts +1 -1
  39. package/dist/utils/getMapLibreStyleUrl.js +19 -5
  40. package/dist/utils/getMapLibreStyleUrl.js.map +1 -1
  41. package/dist/utils/index.cjs +19 -5
  42. package/dist/utils/index.cjs.map +1 -1
  43. package/dist/utils/index.js +19 -5
  44. package/dist/utils/index.js.map +1 -1
  45. package/package.json +17 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/getMapLibreStyleUrl.ts","../../src/core/MapLibre.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["const MAPLIBRE_DEFAULT_STYLE_URL = \"https://demotiles.maplibre.org/style.json\";\nconst DEFAULT_STADIA_STYLE_URL =\n \"https://tiles.stadiamaps.com/styles/osm_bright.json\";\n\nconst STYLE_MAP: Record<string, string> = {\n default: DEFAULT_STADIA_STYLE_URL,\n \"alidade-smooth\": \"https://tiles.stadiamaps.com/styles/alidade_smooth.json\",\n \"alidade-smooth-dark\": \"https://tiles.stadiamaps.com/styles/alidade_smooth_dark.json\",\n \"maplibre-default\": MAPLIBRE_DEFAULT_STYLE_URL,\n \"osm-bright\": \"https://tiles.stadiamaps.com/styles/osm_bright.json\",\n \"stadia-outdoors\": \"https://tiles.stadiamaps.com/styles/outdoors.json\",\n \"stamen-toner\": \"https://tiles.stadiamaps.com/styles/stamen_toner.json\",\n \"stamen-terrain\": \"https://tiles.stadiamaps.com/styles/stamen_terrain.json\",\n \"stamen-watercolor\": \"https://tiles.stadiamaps.com/styles/stamen_watercolor.json\"\n};\n\nconst HTTP_URL_REGEX = /^https?:\\/\\//i;\n\nexport type MapLibreBuiltInStyle = keyof typeof STYLE_MAP;\n\nfunction isStadiaMapsUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.hostname === \"tiles.stadiamaps.com\";\n } catch {\n return false;\n }\n}\n\nfunction assertStadiaApiKey(stadiaApiKey: string): void {\n if (!stadiaApiKey.trim()) {\n throw new Error(\n \"A non-empty stadiaApiKey is required for Stadia Maps style URLs.\"\n );\n }\n}\n\nexport function appendStadiaApiKey(\n styleUrl: string,\n stadiaApiKey: string\n): string {\n if (!isStadiaMapsUrl(styleUrl)) {\n return styleUrl;\n }\n\n assertStadiaApiKey(stadiaApiKey);\n\n const parsed = new URL(styleUrl);\n if (!parsed.searchParams.has(\"api_key\")) {\n parsed.searchParams.set(\"api_key\", stadiaApiKey);\n }\n\n return parsed.toString();\n}\n\nexport function getMapLibreStyleUrl(\n value: string | undefined,\n stadiaApiKey: string\n): string {\n if (!value || typeof value !== \"string\") {\n return appendStadiaApiKey(DEFAULT_STADIA_STYLE_URL, stadiaApiKey);\n }\n\n if (STYLE_MAP[value]) {\n return appendStadiaApiKey(STYLE_MAP[value], stadiaApiKey);\n }\n\n if (HTTP_URL_REGEX.test(value)) {\n return appendStadiaApiKey(value, stadiaApiKey);\n }\n\n return appendStadiaApiKey(DEFAULT_STADIA_STYLE_URL, stadiaApiKey);\n}\n\nexport { DEFAULT_STADIA_STYLE_URL, MAPLIBRE_DEFAULT_STYLE_URL };\n","import React from \"react\";\nimport {\n GeolocateControl,\n Map,\n Marker,\n NavigationControl,\n type MapRef,\n type ViewStateChangeEvent\n} from \"react-map-gl/maplibre\";\n\nimport type {\n BasicMarkerInput,\n MapLibreMarker,\n MapLibreProps,\n MapViewState\n} from \"../types\";\nimport { appendStadiaApiKey, getMapLibreStyleUrl } from \"../utils\";\n\nconst DEFAULT_MAPLIBRE_CSS_HREF =\n \"https://cdn.jsdelivr.net/npm/maplibre-gl@5.18.0/dist/maplibre-gl.css\";\nconst MAPLIBRE_STYLESHEET_ID = \"page-speed-maplibre-gl-css\";\n\nfunction joinClassNames(...classNames: Array<string | undefined>): string {\n return classNames.filter(Boolean).join(\" \");\n}\n\nfunction ensureMapLibreStylesheet(href: string): void {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const existingLink = document.getElementById(MAPLIBRE_STYLESHEET_ID);\n if (existingLink instanceof HTMLLinkElement) {\n if (existingLink.getAttribute(\"href\") !== href) {\n existingLink.setAttribute(\"href\", href);\n }\n return;\n }\n\n const matchingLink = Array.from(\n document.querySelectorAll(\"link[rel='stylesheet']\")\n ).find((link) => link.getAttribute(\"href\") === href);\n\n if (matchingLink instanceof HTMLLinkElement) {\n matchingLink.id = MAPLIBRE_STYLESHEET_ID;\n return;\n }\n\n const stylesheet = document.createElement(\"link\");\n stylesheet.id = MAPLIBRE_STYLESHEET_ID;\n stylesheet.rel = \"stylesheet\";\n stylesheet.href = href;\n stylesheet.dataset.pageSpeedMaps = \"maplibre-css\";\n document.head.appendChild(stylesheet);\n}\n\nfunction DefaultMarker({ marker }: { marker: MapLibreMarker }) {\n return (\n <div\n style={{\n cursor: marker.draggable ? \"grab\" : \"pointer\",\n transform: \"translate(-50%, -100%)\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"relative\"\n }}\n onClick={marker.onClick}\n >\n <svg\n aria-hidden=\"true\"\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill={marker.color || \"#3B82F6\"}\n style={{ filter: \"drop-shadow(0 2px 8px rgba(0,0,0,0.35))\" }}\n >\n <path d=\"M12 2C8.13 2 5 5.13 5 9c0 4.85 6.13 12.24 6.39 12.55a.75.75 0 0 0 1.16 0C12.87 21.24 19 13.85 19 9c0-3.87-3.13-7-7-7Zm0 9.75A2.75 2.75 0 1 1 12 6.25a2.75 2.75 0 0 1 0 5.5Z\" />\n </svg>\n {marker.label ? (\n <div\n style={{\n position: \"absolute\",\n bottom: -28,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n background: \"#FFFFFF\",\n borderRadius: 6,\n padding: \"2px 8px\",\n fontSize: 12,\n fontWeight: 500,\n whiteSpace: \"nowrap\",\n boxShadow: \"0 3px 10px rgba(0, 0, 0, 0.2)\"\n }}\n >\n {marker.label}\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction normalizeMarkers(\n markers: (MapLibreMarker | BasicMarkerInput)[]\n): MapLibreMarker[] {\n return markers.map((marker, index) => {\n if (\n (marker as MapLibreMarker).lat !== undefined &&\n (marker as MapLibreMarker).lng !== undefined\n ) {\n return marker as MapLibreMarker;\n }\n\n const basicMarker = marker as BasicMarkerInput;\n return {\n id: basicMarker.id ?? index,\n lat: basicMarker.latitude,\n lng: basicMarker.longitude,\n color: basicMarker.color,\n draggable: basicMarker.draggable,\n label: basicMarker.label,\n element: basicMarker.element,\n onClick: basicMarker.onClick\n };\n });\n}\n\nexport function MapLibre({\n stadiaApiKey,\n mapLibreCssHref,\n viewState,\n onViewStateChange,\n mapStyle,\n center = viewState\n ? { lat: viewState.latitude ?? 0, lng: viewState.longitude ?? 0 }\n : { lat: 0, lng: 0 },\n zoom = viewState?.zoom ?? 14,\n styleUrl,\n markers = [],\n onMoveEnd,\n onClick,\n onMarkerDrag,\n className,\n style,\n children,\n showNavigationControl = true,\n showGeolocateControl = false,\n navigationControlPosition = \"bottom-right\",\n geolocateControlPosition = \"top-left\",\n flyToOptions = {}\n}: MapLibreProps) {\n const mapRef = React.useRef<MapRef>(null);\n const resolvedMapLibreCssHref =\n mapLibreCssHref && mapLibreCssHref.trim().length > 0\n ? mapLibreCssHref\n : DEFAULT_MAPLIBRE_CSS_HREF;\n\n const [internalViewState, setInternalViewState] = React.useState<MapViewState>({\n latitude: viewState?.latitude ?? center.lat,\n longitude: viewState?.longitude ?? center.lng,\n zoom: viewState?.zoom ?? zoom\n });\n\n const isUserInteracting = React.useRef(false);\n const isMarkerDragging = React.useRef(false);\n const dragAnimationFrame = React.useRef<number | null>(null);\n\n React.useEffect(() => {\n ensureMapLibreStylesheet(resolvedMapLibreCssHref);\n }, [resolvedMapLibreCssHref]);\n\n React.useEffect(() => {\n if (\n !mapRef.current ||\n !viewState ||\n isUserInteracting.current ||\n isMarkerDragging.current\n ) {\n return;\n }\n\n setInternalViewState((previous) => {\n const next = {\n latitude: viewState.latitude ?? previous.latitude,\n longitude: viewState.longitude ?? previous.longitude,\n zoom: viewState.zoom ?? previous.zoom\n };\n\n const hasChanged =\n previous.latitude !== next.latitude ||\n previous.longitude !== next.longitude ||\n previous.zoom !== next.zoom;\n\n if (!hasChanged) {\n return previous;\n }\n\n const {\n speed = 0.8,\n curve = 1.2,\n bearing = 0,\n easing = (t: number) => 1 - Math.pow(1 - t, 3)\n } = flyToOptions;\n\n mapRef.current?.flyTo({\n center: [next.longitude, next.latitude],\n zoom: next.zoom,\n speed,\n curve,\n bearing,\n easing,\n essential: true\n });\n\n return next;\n });\n }, [flyToOptions, viewState?.latitude, viewState?.longitude, viewState?.zoom]);\n\n const handleMoveStart = React.useCallback(() => {\n isUserInteracting.current = true;\n }, []);\n\n const handleMove = React.useCallback(\n (event: ViewStateChangeEvent) => {\n const nextViewState = event.viewState;\n setInternalViewState({\n latitude: nextViewState.latitude,\n longitude: nextViewState.longitude,\n zoom: nextViewState.zoom\n });\n\n onViewStateChange?.({\n latitude: Number(nextViewState.latitude.toFixed(6)),\n longitude: Number(nextViewState.longitude.toFixed(6)),\n zoom: Number(nextViewState.zoom.toFixed(2))\n });\n },\n [onViewStateChange]\n );\n\n const handleMoveEnd = React.useCallback(\n (event: ViewStateChangeEvent) => {\n isUserInteracting.current = false;\n\n if (!onMoveEnd) {\n return;\n }\n\n const map = event.target;\n const nextCenter = map.getCenter();\n const nextZoom = map.getZoom();\n const bounds = map.getBounds();\n\n onMoveEnd(\n {\n lat: Number(nextCenter.lat.toFixed(6)),\n lng: Number(nextCenter.lng.toFixed(6))\n },\n Number(nextZoom.toFixed(2)),\n bounds\n );\n },\n [onMoveEnd]\n );\n\n const handleMapClick = React.useCallback(\n (event: { lngLat: { lng: number; lat: number } }) => {\n if (!onClick) {\n return;\n }\n\n onClick({ latitude: event.lngLat.lat, longitude: event.lngLat.lng });\n },\n [onClick]\n );\n\n const normalizedMarkers = React.useMemo(\n () => normalizeMarkers(markers),\n [markers]\n );\n\n const markerElements = React.useMemo(\n () =>\n normalizedMarkers.map((marker) => (\n <Marker\n key={marker.id}\n longitude={marker.lng}\n latitude={marker.lat}\n draggable={marker.draggable}\n onDragStart={() => {\n isMarkerDragging.current = true;\n }}\n onDrag={(event) => {\n if (!mapRef.current) {\n return;\n }\n\n const nextLngLat = (event as { lngLat?: { lng?: number; lat?: number } }).lngLat;\n if (!nextLngLat || nextLngLat.lng === undefined || nextLngLat.lat === undefined) {\n return;\n }\n const draggedLng = nextLngLat.lng;\n const draggedLat = nextLngLat.lat;\n\n if (dragAnimationFrame.current) {\n cancelAnimationFrame(dragAnimationFrame.current);\n }\n\n dragAnimationFrame.current = requestAnimationFrame(() => {\n if (!mapRef.current) {\n return;\n }\n\n const bounds = mapRef.current.getBounds();\n const viewportWidth = bounds.getEast() - bounds.getWest();\n const viewportHeight = bounds.getNorth() - bounds.getSouth();\n\n const edgePadding = 0.1;\n const westThreshold = bounds.getWest() + viewportWidth * edgePadding;\n const eastThreshold = bounds.getEast() - viewportWidth * edgePadding;\n const southThreshold = bounds.getSouth() + viewportHeight * edgePadding;\n const northThreshold = bounds.getNorth() - viewportHeight * edgePadding;\n\n const nearWestEdge = draggedLng < westThreshold;\n const nearEastEdge = draggedLng > eastThreshold;\n const nearSouthEdge = draggedLat < southThreshold;\n const nearNorthEdge = draggedLat > northThreshold;\n\n if (!nearWestEdge && !nearEastEdge && !nearSouthEdge && !nearNorthEdge) {\n return;\n }\n\n let panLng = draggedLng;\n let panLat = draggedLat;\n const offsetAmount = 0.2;\n\n if (nearWestEdge) {\n panLng = draggedLng - viewportWidth * offsetAmount;\n }\n if (nearEastEdge) {\n panLng = draggedLng + viewportWidth * offsetAmount;\n }\n if (nearSouthEdge) {\n panLat = draggedLat - viewportHeight * offsetAmount;\n }\n if (nearNorthEdge) {\n panLat = draggedLat + viewportHeight * offsetAmount;\n }\n\n mapRef.current?.easeTo({\n center: [panLng, panLat],\n duration: 200\n });\n });\n }}\n onDragEnd={(event) => {\n isMarkerDragging.current = false;\n\n if (dragAnimationFrame.current) {\n cancelAnimationFrame(dragAnimationFrame.current);\n dragAnimationFrame.current = null;\n }\n\n if (!onMarkerDrag) {\n return;\n }\n\n const nextLngLat = (event as { lngLat?: { lng?: number; lat?: number } }).lngLat;\n if (!nextLngLat || nextLngLat.lng === undefined || nextLngLat.lat === undefined) {\n return;\n }\n\n onMarkerDrag(marker.id ?? null, {\n latitude: nextLngLat.lat,\n longitude: nextLngLat.lng\n });\n }}\n >\n {marker.element\n ? typeof marker.element === \"function\"\n ? marker.element()\n : marker.element\n : <DefaultMarker marker={marker} />}\n </Marker>\n )),\n [normalizedMarkers, onMarkerDrag]\n );\n\n const resolvedMapStyleUrl = React.useMemo(() => {\n if (styleUrl) {\n return appendStadiaApiKey(styleUrl, stadiaApiKey);\n }\n\n if (mapStyle) {\n return getMapLibreStyleUrl(mapStyle, stadiaApiKey);\n }\n\n return getMapLibreStyleUrl(\"osm-bright\", stadiaApiKey);\n }, [mapStyle, stadiaApiKey, styleUrl]);\n\n return (\n <div\n className={joinClassNames(\"relative w-full h-full\", className)}\n style={{ width: \"100%\", height: \"100%\", ...style }}\n >\n <Map\n ref={mapRef}\n {...internalViewState}\n mapStyle={resolvedMapStyleUrl}\n onMoveStart={handleMoveStart}\n onMove={handleMove}\n onMoveEnd={handleMoveEnd}\n onClick={handleMapClick}\n attributionControl={false}\n trackResize\n dragRotate={false}\n touchZoomRotate={false}\n >\n {showGeolocateControl ? (\n <GeolocateControl position={geolocateControlPosition} />\n ) : null}\n\n {showNavigationControl ? (\n <NavigationControl position={navigationControlPosition} />\n ) : null}\n\n {markerElements}\n\n {children}\n </Map>\n </div>\n );\n}\n\nexport const DTMapLibreMap = MapLibre;\n"]}
1
+ {"version":3,"sources":["../../src/utils/getMapLibreStyleUrl.ts","../../src/core/MapLibre.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["const MAPLIBRE_DEFAULT_STYLE_URL =\n \"https://basemaps.cartocdn.com/gl/positron-gl-style/style.json\";\nconst DEFAULT_STADIA_STYLE_URL =\n \"https://tiles.stadiamaps.com/styles/osm_bright.json\";\n\nconst STYLE_MAP: Record<string, string> = {\n default: DEFAULT_STADIA_STYLE_URL,\n \"alidade-smooth\": \"https://tiles.stadiamaps.com/styles/alidade_smooth.json\",\n \"alidade-smooth-dark\": \"https://tiles.stadiamaps.com/styles/alidade_smooth_dark.json\",\n \"maplibre-default\": MAPLIBRE_DEFAULT_STYLE_URL,\n \"osm-bright\": \"https://tiles.stadiamaps.com/styles/osm_bright.json\",\n \"stadia-outdoors\": \"https://tiles.stadiamaps.com/styles/outdoors.json\",\n \"stamen-toner\": \"https://tiles.stadiamaps.com/styles/stamen_toner.json\",\n \"stamen-terrain\": \"https://tiles.stadiamaps.com/styles/stamen_terrain.json\",\n \"stamen-watercolor\": \"https://tiles.stadiamaps.com/styles/stamen_watercolor.json\"\n};\n\nconst HTTP_URL_REGEX = /^https?:\\/\\//i;\n\nexport type MapLibreBuiltInStyle = keyof typeof STYLE_MAP;\n\nfunction isStadiaMapsUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n return parsed.hostname === \"tiles.stadiamaps.com\";\n } catch {\n return false;\n }\n}\n\nfunction assertStadiaApiKey(stadiaApiKey: string): void {\n if (!stadiaApiKey.trim()) {\n throw new Error(\n \"A non-empty stadiaApiKey is required for Stadia Maps style URLs.\"\n );\n }\n}\n\nexport function appendStadiaApiKey(\n styleUrl: string,\n stadiaApiKey: string\n): string {\n if (!isStadiaMapsUrl(styleUrl)) {\n return styleUrl;\n }\n\n assertStadiaApiKey(stadiaApiKey);\n\n const parsed = new URL(styleUrl);\n if (!parsed.searchParams.has(\"api_key\")) {\n parsed.searchParams.set(\"api_key\", stadiaApiKey);\n }\n\n return parsed.toString();\n}\n\nexport function getMapLibreStyleUrl(\n value: string | undefined,\n stadiaApiKey: string\n): string {\n const normalizedApiKey = stadiaApiKey.trim();\n\n if (!value || typeof value !== \"string\") {\n if (!normalizedApiKey) {\n return MAPLIBRE_DEFAULT_STYLE_URL;\n }\n return appendStadiaApiKey(DEFAULT_STADIA_STYLE_URL, normalizedApiKey);\n }\n\n if (STYLE_MAP[value]) {\n const mappedStyleUrl = STYLE_MAP[value];\n if (isStadiaMapsUrl(mappedStyleUrl) && !normalizedApiKey) {\n return MAPLIBRE_DEFAULT_STYLE_URL;\n }\n return appendStadiaApiKey(mappedStyleUrl, normalizedApiKey);\n }\n\n if (HTTP_URL_REGEX.test(value)) {\n if (isStadiaMapsUrl(value) && !normalizedApiKey) {\n return MAPLIBRE_DEFAULT_STYLE_URL;\n }\n return appendStadiaApiKey(value, normalizedApiKey);\n }\n\n if (!normalizedApiKey) {\n return MAPLIBRE_DEFAULT_STYLE_URL;\n }\n\n return appendStadiaApiKey(DEFAULT_STADIA_STYLE_URL, normalizedApiKey);\n}\n\nexport { DEFAULT_STADIA_STYLE_URL, MAPLIBRE_DEFAULT_STYLE_URL };\n","import React from \"react\";\nimport {\n GeolocateControl,\n Map,\n Marker,\n NavigationControl,\n type MapRef,\n type ViewStateChangeEvent\n} from \"react-map-gl/maplibre\";\n\nimport type {\n BasicMarkerInput,\n MapLibreMarker,\n MapLibreProps,\n MapViewState\n} from \"../types\";\nimport { appendStadiaApiKey, getMapLibreStyleUrl } from \"../utils\";\n\nconst DEFAULT_MAPLIBRE_CSS_HREF =\n \"https://cdn.jsdelivr.net/npm/maplibre-gl@5.18.0/dist/maplibre-gl.css\";\nconst MAPLIBRE_STYLESHEET_ID = \"page-speed-maplibre-gl-css\";\n\nfunction joinClassNames(...classNames: Array<string | undefined>): string {\n return classNames.filter(Boolean).join(\" \");\n}\n\nfunction ensureMapLibreStylesheet(href: string): void {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const existingLink = document.getElementById(MAPLIBRE_STYLESHEET_ID);\n if (existingLink instanceof HTMLLinkElement) {\n if (existingLink.getAttribute(\"href\") !== href) {\n existingLink.setAttribute(\"href\", href);\n }\n return;\n }\n\n const matchingLink = Array.from(\n document.querySelectorAll(\"link[rel='stylesheet']\")\n ).find((link) => link.getAttribute(\"href\") === href);\n\n if (matchingLink instanceof HTMLLinkElement) {\n matchingLink.id = MAPLIBRE_STYLESHEET_ID;\n return;\n }\n\n const stylesheet = document.createElement(\"link\");\n stylesheet.id = MAPLIBRE_STYLESHEET_ID;\n stylesheet.rel = \"stylesheet\";\n stylesheet.href = href;\n stylesheet.dataset.pageSpeedMaps = \"maplibre-css\";\n document.head.appendChild(stylesheet);\n}\n\nfunction DefaultMarker({ marker }: { marker: MapLibreMarker }) {\n return (\n <div\n style={{\n cursor: marker.draggable ? \"grab\" : \"pointer\",\n transform: \"translate(-50%, -100%)\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"relative\"\n }}\n onClick={marker.onClick}\n >\n <svg\n aria-hidden=\"true\"\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill={marker.color || \"#3B82F6\"}\n style={{ filter: \"drop-shadow(0 2px 8px rgba(0,0,0,0.35))\" }}\n >\n <path d=\"M12 2C8.13 2 5 5.13 5 9c0 4.85 6.13 12.24 6.39 12.55a.75.75 0 0 0 1.16 0C12.87 21.24 19 13.85 19 9c0-3.87-3.13-7-7-7Zm0 9.75A2.75 2.75 0 1 1 12 6.25a2.75 2.75 0 0 1 0 5.5Z\" />\n </svg>\n {marker.label ? (\n <div\n style={{\n position: \"absolute\",\n bottom: -28,\n left: \"50%\",\n transform: \"translateX(-50%)\",\n background: \"#FFFFFF\",\n borderRadius: 6,\n padding: \"2px 8px\",\n fontSize: 12,\n fontWeight: 500,\n whiteSpace: \"nowrap\",\n boxShadow: \"0 3px 10px rgba(0, 0, 0, 0.2)\"\n }}\n >\n {marker.label}\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction normalizeMarkers(\n markers: (MapLibreMarker | BasicMarkerInput)[]\n): MapLibreMarker[] {\n return markers.map((marker, index) => {\n if (\n (marker as MapLibreMarker).lat !== undefined &&\n (marker as MapLibreMarker).lng !== undefined\n ) {\n return marker as MapLibreMarker;\n }\n\n const basicMarker = marker as BasicMarkerInput;\n return {\n id: basicMarker.id ?? index,\n lat: basicMarker.latitude,\n lng: basicMarker.longitude,\n color: basicMarker.color,\n draggable: basicMarker.draggable,\n label: basicMarker.label,\n element: basicMarker.element,\n onClick: basicMarker.onClick\n };\n });\n}\n\nexport function MapLibre({\n stadiaApiKey,\n mapLibreCssHref,\n viewState,\n onViewStateChange,\n mapStyle,\n center = viewState\n ? { lat: viewState.latitude ?? 0, lng: viewState.longitude ?? 0 }\n : { lat: 0, lng: 0 },\n zoom = viewState?.zoom ?? 14,\n styleUrl,\n markers = [],\n onMoveEnd,\n onClick,\n onMarkerDrag,\n className,\n style,\n children,\n showNavigationControl = true,\n showGeolocateControl = false,\n navigationControlPosition = \"bottom-right\",\n geolocateControlPosition = \"top-left\",\n flyToOptions = {}\n}: MapLibreProps) {\n const mapRef = React.useRef<MapRef>(null);\n const resolvedMapLibreCssHref =\n mapLibreCssHref && mapLibreCssHref.trim().length > 0\n ? mapLibreCssHref\n : DEFAULT_MAPLIBRE_CSS_HREF;\n\n const [internalViewState, setInternalViewState] = React.useState<MapViewState>({\n latitude: viewState?.latitude ?? center.lat,\n longitude: viewState?.longitude ?? center.lng,\n zoom: viewState?.zoom ?? zoom\n });\n\n const isUserInteracting = React.useRef(false);\n const isMarkerDragging = React.useRef(false);\n const dragAnimationFrame = React.useRef<number | null>(null);\n\n React.useEffect(() => {\n ensureMapLibreStylesheet(resolvedMapLibreCssHref);\n }, [resolvedMapLibreCssHref]);\n\n React.useEffect(() => {\n if (\n !mapRef.current ||\n !viewState ||\n isUserInteracting.current ||\n isMarkerDragging.current\n ) {\n return;\n }\n\n setInternalViewState((previous) => {\n const next = {\n latitude: viewState.latitude ?? previous.latitude,\n longitude: viewState.longitude ?? previous.longitude,\n zoom: viewState.zoom ?? previous.zoom\n };\n\n const hasChanged =\n previous.latitude !== next.latitude ||\n previous.longitude !== next.longitude ||\n previous.zoom !== next.zoom;\n\n if (!hasChanged) {\n return previous;\n }\n\n const {\n speed = 0.8,\n curve = 1.2,\n bearing = 0,\n easing = (t: number) => 1 - Math.pow(1 - t, 3)\n } = flyToOptions;\n\n mapRef.current?.flyTo({\n center: [next.longitude, next.latitude],\n zoom: next.zoom,\n speed,\n curve,\n bearing,\n easing,\n essential: true\n });\n\n return next;\n });\n }, [flyToOptions, viewState?.latitude, viewState?.longitude, viewState?.zoom]);\n\n const handleMoveStart = React.useCallback(() => {\n isUserInteracting.current = true;\n }, []);\n\n const handleMove = React.useCallback(\n (event: ViewStateChangeEvent) => {\n const nextViewState = event.viewState;\n setInternalViewState({\n latitude: nextViewState.latitude,\n longitude: nextViewState.longitude,\n zoom: nextViewState.zoom\n });\n\n onViewStateChange?.({\n latitude: Number(nextViewState.latitude.toFixed(6)),\n longitude: Number(nextViewState.longitude.toFixed(6)),\n zoom: Number(nextViewState.zoom.toFixed(2))\n });\n },\n [onViewStateChange]\n );\n\n const handleMoveEnd = React.useCallback(\n (event: ViewStateChangeEvent) => {\n isUserInteracting.current = false;\n\n if (!onMoveEnd) {\n return;\n }\n\n const map = event.target;\n const nextCenter = map.getCenter();\n const nextZoom = map.getZoom();\n const bounds = map.getBounds();\n\n onMoveEnd(\n {\n lat: Number(nextCenter.lat.toFixed(6)),\n lng: Number(nextCenter.lng.toFixed(6))\n },\n Number(nextZoom.toFixed(2)),\n bounds\n );\n },\n [onMoveEnd]\n );\n\n const handleMapClick = React.useCallback(\n (event: { lngLat: { lng: number; lat: number } }) => {\n if (!onClick) {\n return;\n }\n\n onClick({ latitude: event.lngLat.lat, longitude: event.lngLat.lng });\n },\n [onClick]\n );\n\n const normalizedMarkers = React.useMemo(\n () => normalizeMarkers(markers),\n [markers]\n );\n\n const markerElements = React.useMemo(\n () =>\n normalizedMarkers.map((marker) => (\n <Marker\n key={marker.id}\n longitude={marker.lng}\n latitude={marker.lat}\n draggable={marker.draggable}\n onDragStart={() => {\n isMarkerDragging.current = true;\n }}\n onDrag={(event) => {\n if (!mapRef.current) {\n return;\n }\n\n const nextLngLat = (event as { lngLat?: { lng?: number; lat?: number } }).lngLat;\n if (!nextLngLat || nextLngLat.lng === undefined || nextLngLat.lat === undefined) {\n return;\n }\n const draggedLng = nextLngLat.lng;\n const draggedLat = nextLngLat.lat;\n\n if (dragAnimationFrame.current) {\n cancelAnimationFrame(dragAnimationFrame.current);\n }\n\n dragAnimationFrame.current = requestAnimationFrame(() => {\n if (!mapRef.current) {\n return;\n }\n\n const bounds = mapRef.current.getBounds();\n const viewportWidth = bounds.getEast() - bounds.getWest();\n const viewportHeight = bounds.getNorth() - bounds.getSouth();\n\n const edgePadding = 0.1;\n const westThreshold = bounds.getWest() + viewportWidth * edgePadding;\n const eastThreshold = bounds.getEast() - viewportWidth * edgePadding;\n const southThreshold = bounds.getSouth() + viewportHeight * edgePadding;\n const northThreshold = bounds.getNorth() - viewportHeight * edgePadding;\n\n const nearWestEdge = draggedLng < westThreshold;\n const nearEastEdge = draggedLng > eastThreshold;\n const nearSouthEdge = draggedLat < southThreshold;\n const nearNorthEdge = draggedLat > northThreshold;\n\n if (!nearWestEdge && !nearEastEdge && !nearSouthEdge && !nearNorthEdge) {\n return;\n }\n\n let panLng = draggedLng;\n let panLat = draggedLat;\n const offsetAmount = 0.2;\n\n if (nearWestEdge) {\n panLng = draggedLng - viewportWidth * offsetAmount;\n }\n if (nearEastEdge) {\n panLng = draggedLng + viewportWidth * offsetAmount;\n }\n if (nearSouthEdge) {\n panLat = draggedLat - viewportHeight * offsetAmount;\n }\n if (nearNorthEdge) {\n panLat = draggedLat + viewportHeight * offsetAmount;\n }\n\n mapRef.current?.easeTo({\n center: [panLng, panLat],\n duration: 200\n });\n });\n }}\n onDragEnd={(event) => {\n isMarkerDragging.current = false;\n\n if (dragAnimationFrame.current) {\n cancelAnimationFrame(dragAnimationFrame.current);\n dragAnimationFrame.current = null;\n }\n\n if (!onMarkerDrag) {\n return;\n }\n\n const nextLngLat = (event as { lngLat?: { lng?: number; lat?: number } }).lngLat;\n if (!nextLngLat || nextLngLat.lng === undefined || nextLngLat.lat === undefined) {\n return;\n }\n\n onMarkerDrag(marker.id ?? null, {\n latitude: nextLngLat.lat,\n longitude: nextLngLat.lng\n });\n }}\n >\n {marker.element\n ? typeof marker.element === \"function\"\n ? marker.element()\n : marker.element\n : <DefaultMarker marker={marker} />}\n </Marker>\n )),\n [normalizedMarkers, onMarkerDrag]\n );\n\n const resolvedMapStyleUrl = React.useMemo(() => {\n if (styleUrl) {\n return appendStadiaApiKey(styleUrl, stadiaApiKey);\n }\n\n if (mapStyle) {\n return getMapLibreStyleUrl(mapStyle, stadiaApiKey);\n }\n\n return getMapLibreStyleUrl(\"osm-bright\", stadiaApiKey);\n }, [mapStyle, stadiaApiKey, styleUrl]);\n\n return (\n <div\n className={joinClassNames(\"relative w-full h-full\", className)}\n style={{ width: \"100%\", height: \"100%\", ...style }}\n >\n <Map\n ref={mapRef}\n {...internalViewState}\n mapStyle={resolvedMapStyleUrl}\n onMoveStart={handleMoveStart}\n onMove={handleMove}\n onMoveEnd={handleMoveEnd}\n onClick={handleMapClick}\n attributionControl={false}\n trackResize\n dragRotate={false}\n touchZoomRotate={false}\n >\n {showGeolocateControl ? (\n <GeolocateControl position={geolocateControlPosition} />\n ) : null}\n\n {showNavigationControl ? (\n <NavigationControl position={navigationControlPosition} />\n ) : null}\n\n {markerElements}\n\n {children}\n </Map>\n </div>\n );\n}\n\nexport const DTMapLibreMap = MapLibre;\n"]}
@@ -0,0 +1,109 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/hooks/useGeoCenter.ts
6
+ function computeGeoCenter(coordinates) {
7
+ if (coordinates.length === 0) return null;
8
+ if (coordinates.length === 1) {
9
+ return { lat: coordinates[0].lat, lng: coordinates[0].lng };
10
+ }
11
+ const toRad = (deg) => deg * Math.PI / 180;
12
+ const toDeg = (rad) => rad * 180 / Math.PI;
13
+ let x = 0;
14
+ let y = 0;
15
+ let z = 0;
16
+ for (const coord of coordinates) {
17
+ const latRad = toRad(coord.lat);
18
+ const lngRad = toRad(coord.lng);
19
+ x += Math.cos(latRad) * Math.cos(lngRad);
20
+ y += Math.cos(latRad) * Math.sin(lngRad);
21
+ z += Math.sin(latRad);
22
+ }
23
+ const total = coordinates.length;
24
+ x /= total;
25
+ y /= total;
26
+ z /= total;
27
+ const hyp = Math.sqrt(x * x + y * y);
28
+ const lat = toDeg(Math.atan2(z, hyp));
29
+ const lng = toDeg(Math.atan2(y, x));
30
+ return { lat, lng };
31
+ }
32
+ function useGeoCenter(coordinates) {
33
+ return react.useMemo(() => computeGeoCenter(coordinates), [coordinates]);
34
+ }
35
+ var TILE_SIZE = 512;
36
+ function latToMercatorY(lat) {
37
+ const latRad = lat * Math.PI / 180;
38
+ const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
39
+ return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
40
+ }
41
+ function lngToMercatorX(lng) {
42
+ return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
43
+ }
44
+ function computeDefaultZoom(options) {
45
+ const {
46
+ coordinates,
47
+ mapWidth,
48
+ mapHeight,
49
+ padding = 50,
50
+ maxZoom = 18,
51
+ minZoom = 1
52
+ } = options;
53
+ if (coordinates.length === 0) return null;
54
+ if (coordinates.length === 1) return maxZoom;
55
+ if (mapWidth <= 0 || mapHeight <= 0) return null;
56
+ let minLat = Infinity;
57
+ let maxLat = -Infinity;
58
+ let minLng = Infinity;
59
+ let maxLng = -Infinity;
60
+ for (const coord of coordinates) {
61
+ if (coord.lat < minLat) minLat = coord.lat;
62
+ if (coord.lat > maxLat) maxLat = coord.lat;
63
+ if (coord.lng < minLng) minLng = coord.lng;
64
+ if (coord.lng > maxLng) maxLng = coord.lng;
65
+ }
66
+ const pixelXMin = lngToMercatorX(minLng);
67
+ const pixelXMax = lngToMercatorX(maxLng);
68
+ const pixelYMin = latToMercatorY(maxLat);
69
+ const pixelYMax = latToMercatorY(minLat);
70
+ const dx = Math.abs(pixelXMax - pixelXMin);
71
+ const dy = Math.abs(pixelYMax - pixelYMin);
72
+ const availableWidth = mapWidth - padding * 2;
73
+ const availableHeight = mapHeight - padding * 2;
74
+ if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
75
+ let zoom;
76
+ if (dx === 0 && dy === 0) {
77
+ return maxZoom;
78
+ } else if (dx === 0) {
79
+ zoom = Math.log2(availableHeight / dy);
80
+ } else if (dy === 0) {
81
+ zoom = Math.log2(availableWidth / dx);
82
+ } else {
83
+ const zoomX = Math.log2(availableWidth / dx);
84
+ const zoomY = Math.log2(availableHeight / dy);
85
+ zoom = Math.min(zoomX, zoomY);
86
+ }
87
+ return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
88
+ }
89
+ function useDefaultZoom(options) {
90
+ const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
91
+ return react.useMemo(
92
+ () => computeDefaultZoom({
93
+ coordinates,
94
+ mapWidth,
95
+ mapHeight,
96
+ padding,
97
+ maxZoom,
98
+ minZoom
99
+ }),
100
+ [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
101
+ );
102
+ }
103
+
104
+ exports.computeDefaultZoom = computeDefaultZoom;
105
+ exports.computeGeoCenter = computeGeoCenter;
106
+ exports.useDefaultZoom = useDefaultZoom;
107
+ exports.useGeoCenter = useGeoCenter;
108
+ //# sourceMappingURL=index.cjs.map
109
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/useGeoCenter.ts","../../src/hooks/useDefaultZoom.ts"],"names":["useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["import { useMemo } from \"react\";\n\nexport interface GeoCoordinate {\n lat: number;\n lng: number;\n}\n\nexport interface GeoCenterResult {\n lat: number;\n lng: number;\n}\n\n/**\n * Computes the geographic midpoint of an array of coordinates\n * using the Cartesian 3D averaging method (handles antimeridian, poles, etc.)\n *\n * Returns null if the input array is empty.\n */\nexport function computeGeoCenter(\n coordinates: GeoCoordinate[]\n): GeoCenterResult | null {\n if (coordinates.length === 0) return null;\n if (coordinates.length === 1) {\n return { lat: coordinates[0].lat, lng: coordinates[0].lng };\n }\n\n const toRad = (deg: number) => (deg * Math.PI) / 180;\n const toDeg = (rad: number) => (rad * 180) / Math.PI;\n\n let x = 0;\n let y = 0;\n let z = 0;\n\n for (const coord of coordinates) {\n const latRad = toRad(coord.lat);\n const lngRad = toRad(coord.lng);\n x += Math.cos(latRad) * Math.cos(lngRad);\n y += Math.cos(latRad) * Math.sin(lngRad);\n z += Math.sin(latRad);\n }\n\n const total = coordinates.length;\n x /= total;\n y /= total;\n z /= total;\n\n const hyp = Math.sqrt(x * x + y * y);\n const lat = toDeg(Math.atan2(z, hyp));\n const lng = toDeg(Math.atan2(y, x));\n\n return { lat, lng };\n}\n\n/**\n * React hook wrapper around computeGeoCenter.\n * Memoizes based on the coordinates array reference.\n */\nexport function useGeoCenter(\n coordinates: GeoCoordinate[]\n): GeoCenterResult | null {\n return useMemo(() => computeGeoCenter(coordinates), [coordinates]);\n}\n","import { useMemo } from \"react\";\nimport type { GeoCoordinate } from \"./useGeoCenter\";\n\nexport interface DefaultZoomOptions {\n /** Array of coordinates to fit */\n coordinates: GeoCoordinate[];\n /** Map container width in pixels */\n mapWidth: number;\n /** Map container height in pixels */\n mapHeight: number;\n /** Padding in pixels around the bounds (default: 50) */\n padding?: number;\n /** Maximum zoom level to return (default: 18) */\n maxZoom?: number;\n /** Minimum zoom level to return (default: 1) */\n minZoom?: number;\n}\n\nconst TILE_SIZE = 512; // MapLibre GL JS uses 512px tiles\n\n/**\n * Converts latitude to Mercator Y pixel coordinate at zoom 0.\n */\nfunction latToMercatorY(lat: number): number {\n const latRad = (lat * Math.PI) / 180;\n const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));\n return (TILE_SIZE / (2 * Math.PI)) * (Math.PI - mercN);\n}\n\n/**\n * Converts longitude to Mercator X pixel coordinate at zoom 0.\n */\nfunction lngToMercatorX(lng: number): number {\n return (TILE_SIZE / (2 * Math.PI)) * (((lng + 180) / 360) * 2 * Math.PI);\n}\n\n/**\n * Pure function: computes the ideal zoom level to fit all coordinates\n * within the given map dimensions.\n *\n * Returns null if fewer than 1 coordinate is provided.\n * For a single coordinate, returns maxZoom (caller should use markerFocusZoom).\n */\nexport function computeDefaultZoom(options: DefaultZoomOptions): number | null {\n const {\n coordinates,\n mapWidth,\n mapHeight,\n padding = 50,\n maxZoom = 18,\n minZoom = 1,\n } = options;\n\n if (coordinates.length === 0) return null;\n if (coordinates.length === 1) return maxZoom;\n if (mapWidth <= 0 || mapHeight <= 0) return null;\n\n // Compute bounding box\n let minLat = Infinity;\n let maxLat = -Infinity;\n let minLng = Infinity;\n let maxLng = -Infinity;\n\n for (const coord of coordinates) {\n if (coord.lat < minLat) minLat = coord.lat;\n if (coord.lat > maxLat) maxLat = coord.lat;\n if (coord.lng < minLng) minLng = coord.lng;\n if (coord.lng > maxLng) maxLng = coord.lng;\n }\n\n // Compute pixel span at zoom 0\n const pixelXMin = lngToMercatorX(minLng);\n const pixelXMax = lngToMercatorX(maxLng);\n const pixelYMin = latToMercatorY(maxLat); // Note: Y is inverted in Mercator\n const pixelYMax = latToMercatorY(minLat);\n\n const dx = Math.abs(pixelXMax - pixelXMin);\n const dy = Math.abs(pixelYMax - pixelYMin);\n\n // Available viewport after padding\n const availableWidth = mapWidth - padding * 2;\n const availableHeight = mapHeight - padding * 2;\n\n if (availableWidth <= 0 || availableHeight <= 0) return minZoom;\n\n // Compute zoom for each axis: viewport = pixelSpan * 2^zoom\n // So zoom = log2(viewport / pixelSpan)\n let zoom: number;\n\n if (dx === 0 && dy === 0) {\n // All coordinates are identical\n return maxZoom;\n } else if (dx === 0) {\n zoom = Math.log2(availableHeight / dy);\n } else if (dy === 0) {\n zoom = Math.log2(availableWidth / dx);\n } else {\n const zoomX = Math.log2(availableWidth / dx);\n const zoomY = Math.log2(availableHeight / dy);\n zoom = Math.min(zoomX, zoomY); // Use the more restrictive axis\n }\n\n // Clamp to min/max and floor to avoid sub-pixel jitter\n return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));\n}\n\n/**\n * React hook wrapper around computeDefaultZoom.\n */\nexport function useDefaultZoom(options: DefaultZoomOptions): number | null {\n const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;\n\n return useMemo(\n () =>\n computeDefaultZoom({\n coordinates,\n mapWidth,\n mapHeight,\n padding,\n maxZoom,\n minZoom,\n }),\n [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]\n );\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { GeoCenterResult, GeoCoordinate, computeGeoCenter, useGeoCenter } from './useGeoCenter.cjs';
2
+ export { DefaultZoomOptions, computeDefaultZoom, useDefaultZoom } from './useDefaultZoom.cjs';
@@ -0,0 +1,2 @@
1
+ export { GeoCenterResult, GeoCoordinate, computeGeoCenter, useGeoCenter } from './useGeoCenter.js';
2
+ export { DefaultZoomOptions, computeDefaultZoom, useDefaultZoom } from './useDefaultZoom.js';
@@ -0,0 +1,104 @@
1
+ import { useMemo } from 'react';
2
+
3
+ // src/hooks/useGeoCenter.ts
4
+ function computeGeoCenter(coordinates) {
5
+ if (coordinates.length === 0) return null;
6
+ if (coordinates.length === 1) {
7
+ return { lat: coordinates[0].lat, lng: coordinates[0].lng };
8
+ }
9
+ const toRad = (deg) => deg * Math.PI / 180;
10
+ const toDeg = (rad) => rad * 180 / Math.PI;
11
+ let x = 0;
12
+ let y = 0;
13
+ let z = 0;
14
+ for (const coord of coordinates) {
15
+ const latRad = toRad(coord.lat);
16
+ const lngRad = toRad(coord.lng);
17
+ x += Math.cos(latRad) * Math.cos(lngRad);
18
+ y += Math.cos(latRad) * Math.sin(lngRad);
19
+ z += Math.sin(latRad);
20
+ }
21
+ const total = coordinates.length;
22
+ x /= total;
23
+ y /= total;
24
+ z /= total;
25
+ const hyp = Math.sqrt(x * x + y * y);
26
+ const lat = toDeg(Math.atan2(z, hyp));
27
+ const lng = toDeg(Math.atan2(y, x));
28
+ return { lat, lng };
29
+ }
30
+ function useGeoCenter(coordinates) {
31
+ return useMemo(() => computeGeoCenter(coordinates), [coordinates]);
32
+ }
33
+ var TILE_SIZE = 512;
34
+ function latToMercatorY(lat) {
35
+ const latRad = lat * Math.PI / 180;
36
+ const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
37
+ return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
38
+ }
39
+ function lngToMercatorX(lng) {
40
+ return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
41
+ }
42
+ function computeDefaultZoom(options) {
43
+ const {
44
+ coordinates,
45
+ mapWidth,
46
+ mapHeight,
47
+ padding = 50,
48
+ maxZoom = 18,
49
+ minZoom = 1
50
+ } = options;
51
+ if (coordinates.length === 0) return null;
52
+ if (coordinates.length === 1) return maxZoom;
53
+ if (mapWidth <= 0 || mapHeight <= 0) return null;
54
+ let minLat = Infinity;
55
+ let maxLat = -Infinity;
56
+ let minLng = Infinity;
57
+ let maxLng = -Infinity;
58
+ for (const coord of coordinates) {
59
+ if (coord.lat < minLat) minLat = coord.lat;
60
+ if (coord.lat > maxLat) maxLat = coord.lat;
61
+ if (coord.lng < minLng) minLng = coord.lng;
62
+ if (coord.lng > maxLng) maxLng = coord.lng;
63
+ }
64
+ const pixelXMin = lngToMercatorX(minLng);
65
+ const pixelXMax = lngToMercatorX(maxLng);
66
+ const pixelYMin = latToMercatorY(maxLat);
67
+ const pixelYMax = latToMercatorY(minLat);
68
+ const dx = Math.abs(pixelXMax - pixelXMin);
69
+ const dy = Math.abs(pixelYMax - pixelYMin);
70
+ const availableWidth = mapWidth - padding * 2;
71
+ const availableHeight = mapHeight - padding * 2;
72
+ if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
73
+ let zoom;
74
+ if (dx === 0 && dy === 0) {
75
+ return maxZoom;
76
+ } else if (dx === 0) {
77
+ zoom = Math.log2(availableHeight / dy);
78
+ } else if (dy === 0) {
79
+ zoom = Math.log2(availableWidth / dx);
80
+ } else {
81
+ const zoomX = Math.log2(availableWidth / dx);
82
+ const zoomY = Math.log2(availableHeight / dy);
83
+ zoom = Math.min(zoomX, zoomY);
84
+ }
85
+ return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
86
+ }
87
+ function useDefaultZoom(options) {
88
+ const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
89
+ return useMemo(
90
+ () => computeDefaultZoom({
91
+ coordinates,
92
+ mapWidth,
93
+ mapHeight,
94
+ padding,
95
+ maxZoom,
96
+ minZoom
97
+ }),
98
+ [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
99
+ );
100
+ }
101
+
102
+ export { computeDefaultZoom, computeGeoCenter, useDefaultZoom, useGeoCenter };
103
+ //# sourceMappingURL=index.js.map
104
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/useGeoCenter.ts","../../src/hooks/useDefaultZoom.ts"],"names":["useMemo"],"mappings":"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","file":"index.js","sourcesContent":["import { useMemo } from \"react\";\n\nexport interface GeoCoordinate {\n lat: number;\n lng: number;\n}\n\nexport interface GeoCenterResult {\n lat: number;\n lng: number;\n}\n\n/**\n * Computes the geographic midpoint of an array of coordinates\n * using the Cartesian 3D averaging method (handles antimeridian, poles, etc.)\n *\n * Returns null if the input array is empty.\n */\nexport function computeGeoCenter(\n coordinates: GeoCoordinate[]\n): GeoCenterResult | null {\n if (coordinates.length === 0) return null;\n if (coordinates.length === 1) {\n return { lat: coordinates[0].lat, lng: coordinates[0].lng };\n }\n\n const toRad = (deg: number) => (deg * Math.PI) / 180;\n const toDeg = (rad: number) => (rad * 180) / Math.PI;\n\n let x = 0;\n let y = 0;\n let z = 0;\n\n for (const coord of coordinates) {\n const latRad = toRad(coord.lat);\n const lngRad = toRad(coord.lng);\n x += Math.cos(latRad) * Math.cos(lngRad);\n y += Math.cos(latRad) * Math.sin(lngRad);\n z += Math.sin(latRad);\n }\n\n const total = coordinates.length;\n x /= total;\n y /= total;\n z /= total;\n\n const hyp = Math.sqrt(x * x + y * y);\n const lat = toDeg(Math.atan2(z, hyp));\n const lng = toDeg(Math.atan2(y, x));\n\n return { lat, lng };\n}\n\n/**\n * React hook wrapper around computeGeoCenter.\n * Memoizes based on the coordinates array reference.\n */\nexport function useGeoCenter(\n coordinates: GeoCoordinate[]\n): GeoCenterResult | null {\n return useMemo(() => computeGeoCenter(coordinates), [coordinates]);\n}\n","import { useMemo } from \"react\";\nimport type { GeoCoordinate } from \"./useGeoCenter\";\n\nexport interface DefaultZoomOptions {\n /** Array of coordinates to fit */\n coordinates: GeoCoordinate[];\n /** Map container width in pixels */\n mapWidth: number;\n /** Map container height in pixels */\n mapHeight: number;\n /** Padding in pixels around the bounds (default: 50) */\n padding?: number;\n /** Maximum zoom level to return (default: 18) */\n maxZoom?: number;\n /** Minimum zoom level to return (default: 1) */\n minZoom?: number;\n}\n\nconst TILE_SIZE = 512; // MapLibre GL JS uses 512px tiles\n\n/**\n * Converts latitude to Mercator Y pixel coordinate at zoom 0.\n */\nfunction latToMercatorY(lat: number): number {\n const latRad = (lat * Math.PI) / 180;\n const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));\n return (TILE_SIZE / (2 * Math.PI)) * (Math.PI - mercN);\n}\n\n/**\n * Converts longitude to Mercator X pixel coordinate at zoom 0.\n */\nfunction lngToMercatorX(lng: number): number {\n return (TILE_SIZE / (2 * Math.PI)) * (((lng + 180) / 360) * 2 * Math.PI);\n}\n\n/**\n * Pure function: computes the ideal zoom level to fit all coordinates\n * within the given map dimensions.\n *\n * Returns null if fewer than 1 coordinate is provided.\n * For a single coordinate, returns maxZoom (caller should use markerFocusZoom).\n */\nexport function computeDefaultZoom(options: DefaultZoomOptions): number | null {\n const {\n coordinates,\n mapWidth,\n mapHeight,\n padding = 50,\n maxZoom = 18,\n minZoom = 1,\n } = options;\n\n if (coordinates.length === 0) return null;\n if (coordinates.length === 1) return maxZoom;\n if (mapWidth <= 0 || mapHeight <= 0) return null;\n\n // Compute bounding box\n let minLat = Infinity;\n let maxLat = -Infinity;\n let minLng = Infinity;\n let maxLng = -Infinity;\n\n for (const coord of coordinates) {\n if (coord.lat < minLat) minLat = coord.lat;\n if (coord.lat > maxLat) maxLat = coord.lat;\n if (coord.lng < minLng) minLng = coord.lng;\n if (coord.lng > maxLng) maxLng = coord.lng;\n }\n\n // Compute pixel span at zoom 0\n const pixelXMin = lngToMercatorX(minLng);\n const pixelXMax = lngToMercatorX(maxLng);\n const pixelYMin = latToMercatorY(maxLat); // Note: Y is inverted in Mercator\n const pixelYMax = latToMercatorY(minLat);\n\n const dx = Math.abs(pixelXMax - pixelXMin);\n const dy = Math.abs(pixelYMax - pixelYMin);\n\n // Available viewport after padding\n const availableWidth = mapWidth - padding * 2;\n const availableHeight = mapHeight - padding * 2;\n\n if (availableWidth <= 0 || availableHeight <= 0) return minZoom;\n\n // Compute zoom for each axis: viewport = pixelSpan * 2^zoom\n // So zoom = log2(viewport / pixelSpan)\n let zoom: number;\n\n if (dx === 0 && dy === 0) {\n // All coordinates are identical\n return maxZoom;\n } else if (dx === 0) {\n zoom = Math.log2(availableHeight / dy);\n } else if (dy === 0) {\n zoom = Math.log2(availableWidth / dx);\n } else {\n const zoomX = Math.log2(availableWidth / dx);\n const zoomY = Math.log2(availableHeight / dy);\n zoom = Math.min(zoomX, zoomY); // Use the more restrictive axis\n }\n\n // Clamp to min/max and floor to avoid sub-pixel jitter\n return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));\n}\n\n/**\n * React hook wrapper around computeDefaultZoom.\n */\nexport function useDefaultZoom(options: DefaultZoomOptions): number | null {\n const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;\n\n return useMemo(\n () =>\n computeDefaultZoom({\n coordinates,\n mapWidth,\n mapHeight,\n padding,\n maxZoom,\n minZoom,\n }),\n [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]\n );\n}\n"]}
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/hooks/useDefaultZoom.ts
6
+ var TILE_SIZE = 512;
7
+ function latToMercatorY(lat) {
8
+ const latRad = lat * Math.PI / 180;
9
+ const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
10
+ return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
11
+ }
12
+ function lngToMercatorX(lng) {
13
+ return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
14
+ }
15
+ function computeDefaultZoom(options) {
16
+ const {
17
+ coordinates,
18
+ mapWidth,
19
+ mapHeight,
20
+ padding = 50,
21
+ maxZoom = 18,
22
+ minZoom = 1
23
+ } = options;
24
+ if (coordinates.length === 0) return null;
25
+ if (coordinates.length === 1) return maxZoom;
26
+ if (mapWidth <= 0 || mapHeight <= 0) return null;
27
+ let minLat = Infinity;
28
+ let maxLat = -Infinity;
29
+ let minLng = Infinity;
30
+ let maxLng = -Infinity;
31
+ for (const coord of coordinates) {
32
+ if (coord.lat < minLat) minLat = coord.lat;
33
+ if (coord.lat > maxLat) maxLat = coord.lat;
34
+ if (coord.lng < minLng) minLng = coord.lng;
35
+ if (coord.lng > maxLng) maxLng = coord.lng;
36
+ }
37
+ const pixelXMin = lngToMercatorX(minLng);
38
+ const pixelXMax = lngToMercatorX(maxLng);
39
+ const pixelYMin = latToMercatorY(maxLat);
40
+ const pixelYMax = latToMercatorY(minLat);
41
+ const dx = Math.abs(pixelXMax - pixelXMin);
42
+ const dy = Math.abs(pixelYMax - pixelYMin);
43
+ const availableWidth = mapWidth - padding * 2;
44
+ const availableHeight = mapHeight - padding * 2;
45
+ if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
46
+ let zoom;
47
+ if (dx === 0 && dy === 0) {
48
+ return maxZoom;
49
+ } else if (dx === 0) {
50
+ zoom = Math.log2(availableHeight / dy);
51
+ } else if (dy === 0) {
52
+ zoom = Math.log2(availableWidth / dx);
53
+ } else {
54
+ const zoomX = Math.log2(availableWidth / dx);
55
+ const zoomY = Math.log2(availableHeight / dy);
56
+ zoom = Math.min(zoomX, zoomY);
57
+ }
58
+ return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
59
+ }
60
+ function useDefaultZoom(options) {
61
+ const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
62
+ return react.useMemo(
63
+ () => computeDefaultZoom({
64
+ coordinates,
65
+ mapWidth,
66
+ mapHeight,
67
+ padding,
68
+ maxZoom,
69
+ minZoom
70
+ }),
71
+ [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
72
+ );
73
+ }
74
+
75
+ exports.computeDefaultZoom = computeDefaultZoom;
76
+ exports.useDefaultZoom = useDefaultZoom;
77
+ //# sourceMappingURL=useDefaultZoom.cjs.map
78
+ //# sourceMappingURL=useDefaultZoom.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/useDefaultZoom.ts"],"names":["useMemo"],"mappings":"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","file":"useDefaultZoom.cjs","sourcesContent":["import { useMemo } from \"react\";\nimport type { GeoCoordinate } from \"./useGeoCenter\";\n\nexport interface DefaultZoomOptions {\n /** Array of coordinates to fit */\n coordinates: GeoCoordinate[];\n /** Map container width in pixels */\n mapWidth: number;\n /** Map container height in pixels */\n mapHeight: number;\n /** Padding in pixels around the bounds (default: 50) */\n padding?: number;\n /** Maximum zoom level to return (default: 18) */\n maxZoom?: number;\n /** Minimum zoom level to return (default: 1) */\n minZoom?: number;\n}\n\nconst TILE_SIZE = 512; // MapLibre GL JS uses 512px tiles\n\n/**\n * Converts latitude to Mercator Y pixel coordinate at zoom 0.\n */\nfunction latToMercatorY(lat: number): number {\n const latRad = (lat * Math.PI) / 180;\n const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));\n return (TILE_SIZE / (2 * Math.PI)) * (Math.PI - mercN);\n}\n\n/**\n * Converts longitude to Mercator X pixel coordinate at zoom 0.\n */\nfunction lngToMercatorX(lng: number): number {\n return (TILE_SIZE / (2 * Math.PI)) * (((lng + 180) / 360) * 2 * Math.PI);\n}\n\n/**\n * Pure function: computes the ideal zoom level to fit all coordinates\n * within the given map dimensions.\n *\n * Returns null if fewer than 1 coordinate is provided.\n * For a single coordinate, returns maxZoom (caller should use markerFocusZoom).\n */\nexport function computeDefaultZoom(options: DefaultZoomOptions): number | null {\n const {\n coordinates,\n mapWidth,\n mapHeight,\n padding = 50,\n maxZoom = 18,\n minZoom = 1,\n } = options;\n\n if (coordinates.length === 0) return null;\n if (coordinates.length === 1) return maxZoom;\n if (mapWidth <= 0 || mapHeight <= 0) return null;\n\n // Compute bounding box\n let minLat = Infinity;\n let maxLat = -Infinity;\n let minLng = Infinity;\n let maxLng = -Infinity;\n\n for (const coord of coordinates) {\n if (coord.lat < minLat) minLat = coord.lat;\n if (coord.lat > maxLat) maxLat = coord.lat;\n if (coord.lng < minLng) minLng = coord.lng;\n if (coord.lng > maxLng) maxLng = coord.lng;\n }\n\n // Compute pixel span at zoom 0\n const pixelXMin = lngToMercatorX(minLng);\n const pixelXMax = lngToMercatorX(maxLng);\n const pixelYMin = latToMercatorY(maxLat); // Note: Y is inverted in Mercator\n const pixelYMax = latToMercatorY(minLat);\n\n const dx = Math.abs(pixelXMax - pixelXMin);\n const dy = Math.abs(pixelYMax - pixelYMin);\n\n // Available viewport after padding\n const availableWidth = mapWidth - padding * 2;\n const availableHeight = mapHeight - padding * 2;\n\n if (availableWidth <= 0 || availableHeight <= 0) return minZoom;\n\n // Compute zoom for each axis: viewport = pixelSpan * 2^zoom\n // So zoom = log2(viewport / pixelSpan)\n let zoom: number;\n\n if (dx === 0 && dy === 0) {\n // All coordinates are identical\n return maxZoom;\n } else if (dx === 0) {\n zoom = Math.log2(availableHeight / dy);\n } else if (dy === 0) {\n zoom = Math.log2(availableWidth / dx);\n } else {\n const zoomX = Math.log2(availableWidth / dx);\n const zoomY = Math.log2(availableHeight / dy);\n zoom = Math.min(zoomX, zoomY); // Use the more restrictive axis\n }\n\n // Clamp to min/max and floor to avoid sub-pixel jitter\n return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));\n}\n\n/**\n * React hook wrapper around computeDefaultZoom.\n */\nexport function useDefaultZoom(options: DefaultZoomOptions): number | null {\n const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;\n\n return useMemo(\n () =>\n computeDefaultZoom({\n coordinates,\n mapWidth,\n mapHeight,\n padding,\n maxZoom,\n minZoom,\n }),\n [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]\n );\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import { GeoCoordinate } from './useGeoCenter.cjs';
2
+
3
+ interface DefaultZoomOptions {
4
+ /** Array of coordinates to fit */
5
+ coordinates: GeoCoordinate[];
6
+ /** Map container width in pixels */
7
+ mapWidth: number;
8
+ /** Map container height in pixels */
9
+ mapHeight: number;
10
+ /** Padding in pixels around the bounds (default: 50) */
11
+ padding?: number;
12
+ /** Maximum zoom level to return (default: 18) */
13
+ maxZoom?: number;
14
+ /** Minimum zoom level to return (default: 1) */
15
+ minZoom?: number;
16
+ }
17
+ /**
18
+ * Pure function: computes the ideal zoom level to fit all coordinates
19
+ * within the given map dimensions.
20
+ *
21
+ * Returns null if fewer than 1 coordinate is provided.
22
+ * For a single coordinate, returns maxZoom (caller should use markerFocusZoom).
23
+ */
24
+ declare function computeDefaultZoom(options: DefaultZoomOptions): number | null;
25
+ /**
26
+ * React hook wrapper around computeDefaultZoom.
27
+ */
28
+ declare function useDefaultZoom(options: DefaultZoomOptions): number | null;
29
+
30
+ export { type DefaultZoomOptions, computeDefaultZoom, useDefaultZoom };
@@ -0,0 +1,30 @@
1
+ import { GeoCoordinate } from './useGeoCenter.js';
2
+
3
+ interface DefaultZoomOptions {
4
+ /** Array of coordinates to fit */
5
+ coordinates: GeoCoordinate[];
6
+ /** Map container width in pixels */
7
+ mapWidth: number;
8
+ /** Map container height in pixels */
9
+ mapHeight: number;
10
+ /** Padding in pixels around the bounds (default: 50) */
11
+ padding?: number;
12
+ /** Maximum zoom level to return (default: 18) */
13
+ maxZoom?: number;
14
+ /** Minimum zoom level to return (default: 1) */
15
+ minZoom?: number;
16
+ }
17
+ /**
18
+ * Pure function: computes the ideal zoom level to fit all coordinates
19
+ * within the given map dimensions.
20
+ *
21
+ * Returns null if fewer than 1 coordinate is provided.
22
+ * For a single coordinate, returns maxZoom (caller should use markerFocusZoom).
23
+ */
24
+ declare function computeDefaultZoom(options: DefaultZoomOptions): number | null;
25
+ /**
26
+ * React hook wrapper around computeDefaultZoom.
27
+ */
28
+ declare function useDefaultZoom(options: DefaultZoomOptions): number | null;
29
+
30
+ export { type DefaultZoomOptions, computeDefaultZoom, useDefaultZoom };
@@ -0,0 +1,75 @@
1
+ import { useMemo } from 'react';
2
+
3
+ // src/hooks/useDefaultZoom.ts
4
+ var TILE_SIZE = 512;
5
+ function latToMercatorY(lat) {
6
+ const latRad = lat * Math.PI / 180;
7
+ const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
8
+ return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
9
+ }
10
+ function lngToMercatorX(lng) {
11
+ return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
12
+ }
13
+ function computeDefaultZoom(options) {
14
+ const {
15
+ coordinates,
16
+ mapWidth,
17
+ mapHeight,
18
+ padding = 50,
19
+ maxZoom = 18,
20
+ minZoom = 1
21
+ } = options;
22
+ if (coordinates.length === 0) return null;
23
+ if (coordinates.length === 1) return maxZoom;
24
+ if (mapWidth <= 0 || mapHeight <= 0) return null;
25
+ let minLat = Infinity;
26
+ let maxLat = -Infinity;
27
+ let minLng = Infinity;
28
+ let maxLng = -Infinity;
29
+ for (const coord of coordinates) {
30
+ if (coord.lat < minLat) minLat = coord.lat;
31
+ if (coord.lat > maxLat) maxLat = coord.lat;
32
+ if (coord.lng < minLng) minLng = coord.lng;
33
+ if (coord.lng > maxLng) maxLng = coord.lng;
34
+ }
35
+ const pixelXMin = lngToMercatorX(minLng);
36
+ const pixelXMax = lngToMercatorX(maxLng);
37
+ const pixelYMin = latToMercatorY(maxLat);
38
+ const pixelYMax = latToMercatorY(minLat);
39
+ const dx = Math.abs(pixelXMax - pixelXMin);
40
+ const dy = Math.abs(pixelYMax - pixelYMin);
41
+ const availableWidth = mapWidth - padding * 2;
42
+ const availableHeight = mapHeight - padding * 2;
43
+ if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
44
+ let zoom;
45
+ if (dx === 0 && dy === 0) {
46
+ return maxZoom;
47
+ } else if (dx === 0) {
48
+ zoom = Math.log2(availableHeight / dy);
49
+ } else if (dy === 0) {
50
+ zoom = Math.log2(availableWidth / dx);
51
+ } else {
52
+ const zoomX = Math.log2(availableWidth / dx);
53
+ const zoomY = Math.log2(availableHeight / dy);
54
+ zoom = Math.min(zoomX, zoomY);
55
+ }
56
+ return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
57
+ }
58
+ function useDefaultZoom(options) {
59
+ const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
60
+ return useMemo(
61
+ () => computeDefaultZoom({
62
+ coordinates,
63
+ mapWidth,
64
+ mapHeight,
65
+ padding,
66
+ maxZoom,
67
+ minZoom
68
+ }),
69
+ [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
70
+ );
71
+ }
72
+
73
+ export { computeDefaultZoom, useDefaultZoom };
74
+ //# sourceMappingURL=useDefaultZoom.js.map
75
+ //# sourceMappingURL=useDefaultZoom.js.map