@page-speed/maps 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as React3 from 'react';
2
- import React3__default from 'react';
2
+ import React3__default, { useMemo } from 'react';
3
3
  import { Marker, Map as Map$1, GeolocateControl, NavigationControl } from 'react-map-gl/maplibre';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
@@ -518,6 +518,74 @@ function MapLibre({
518
518
  }
519
519
  );
520
520
  }
521
+ var TILE_SIZE = 512;
522
+ function latToMercatorY(lat) {
523
+ const latRad = lat * Math.PI / 180;
524
+ const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
525
+ return TILE_SIZE / (2 * Math.PI) * (Math.PI - mercN);
526
+ }
527
+ function lngToMercatorX(lng) {
528
+ return TILE_SIZE / (2 * Math.PI) * ((lng + 180) / 360 * 2 * Math.PI);
529
+ }
530
+ function computeDefaultZoom(options) {
531
+ const {
532
+ coordinates,
533
+ mapWidth,
534
+ mapHeight,
535
+ padding = 50,
536
+ maxZoom = 18,
537
+ minZoom = 1
538
+ } = options;
539
+ if (coordinates.length === 0) return null;
540
+ if (coordinates.length === 1) return maxZoom;
541
+ if (mapWidth <= 0 || mapHeight <= 0) return null;
542
+ let minLat = Infinity;
543
+ let maxLat = -Infinity;
544
+ let minLng = Infinity;
545
+ let maxLng = -Infinity;
546
+ for (const coord of coordinates) {
547
+ if (coord.lat < minLat) minLat = coord.lat;
548
+ if (coord.lat > maxLat) maxLat = coord.lat;
549
+ if (coord.lng < minLng) minLng = coord.lng;
550
+ if (coord.lng > maxLng) maxLng = coord.lng;
551
+ }
552
+ const pixelXMin = lngToMercatorX(minLng);
553
+ const pixelXMax = lngToMercatorX(maxLng);
554
+ const pixelYMin = latToMercatorY(maxLat);
555
+ const pixelYMax = latToMercatorY(minLat);
556
+ const dx = Math.abs(pixelXMax - pixelXMin);
557
+ const dy = Math.abs(pixelYMax - pixelYMin);
558
+ const availableWidth = mapWidth - padding * 2;
559
+ const availableHeight = mapHeight - padding * 2;
560
+ if (availableWidth <= 0 || availableHeight <= 0) return minZoom;
561
+ let zoom;
562
+ if (dx === 0 && dy === 0) {
563
+ return maxZoom;
564
+ } else if (dx === 0) {
565
+ zoom = Math.log2(availableHeight / dy);
566
+ } else if (dy === 0) {
567
+ zoom = Math.log2(availableWidth / dx);
568
+ } else {
569
+ const zoomX = Math.log2(availableWidth / dx);
570
+ const zoomY = Math.log2(availableHeight / dy);
571
+ zoom = Math.min(zoomX, zoomY);
572
+ }
573
+ return Math.max(minZoom, Math.min(maxZoom, Math.floor(zoom * 100) / 100));
574
+ }
575
+ function useDefaultZoom(options) {
576
+ const { coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom } = options;
577
+ return useMemo(
578
+ () => computeDefaultZoom({
579
+ coordinates,
580
+ mapWidth,
581
+ mapHeight,
582
+ padding,
583
+ maxZoom,
584
+ minZoom
585
+ }),
586
+ [coordinates, mapWidth, mapHeight, padding, maxZoom, minZoom]
587
+ );
588
+ }
521
589
  var PANEL_POSITION_CLASS = {
522
590
  "top-left": "left-4 top-4",
523
591
  "top-right": "right-4 top-4",
@@ -762,9 +830,50 @@ function GeoMap({
762
830
  clearSelectionOnMapClick = true,
763
831
  mapChildren,
764
832
  optixFlowConfig,
833
+ mapSize,
765
834
  IconComponent = FallbackIcon,
766
835
  ImgComponent = FallbackImg
767
836
  }) {
837
+ const containerRef = React3.useRef(null);
838
+ const [containerDimensions, setContainerDimensions] = React3.useState({
839
+ width: 800,
840
+ // Default width
841
+ height: 520
842
+ // Default height
843
+ });
844
+ const [isMobile, setIsMobile] = React3.useState(false);
845
+ React3.useEffect(() => {
846
+ const checkMobile = () => {
847
+ setIsMobile(window.innerWidth < 768);
848
+ };
849
+ checkMobile();
850
+ window.addEventListener("resize", checkMobile);
851
+ return () => window.removeEventListener("resize", checkMobile);
852
+ }, []);
853
+ const calculatedHeight = React3.useMemo(() => {
854
+ if (mapSize) {
855
+ return isMobile ? mapSize.mobile : mapSize.desktop;
856
+ }
857
+ return isMobile ? 420 : 520;
858
+ }, [mapSize, isMobile]);
859
+ React3.useEffect(() => {
860
+ if (!containerRef.current) return;
861
+ const updateDimensions = () => {
862
+ if (containerRef.current) {
863
+ const rect = containerRef.current.getBoundingClientRect();
864
+ setContainerDimensions({
865
+ width: rect.width || 800,
866
+ height: rect.height || calculatedHeight
867
+ });
868
+ }
869
+ };
870
+ updateDimensions();
871
+ if (typeof ResizeObserver !== "undefined") {
872
+ const resizeObserver = new ResizeObserver(updateDimensions);
873
+ resizeObserver.observe(containerRef.current);
874
+ return () => resizeObserver.disconnect();
875
+ }
876
+ }, [calculatedHeight]);
768
877
  const normalizedStandaloneMarkers = React3.useMemo(
769
878
  () => markers.map((marker, index) => ({
770
879
  ...marker,
@@ -848,39 +957,41 @@ function GeoMap({
848
957
  longitude: DEFAULT_VIEW_STATE.longitude
849
958
  };
850
959
  }, [normalizedClusters, normalizedStandaloneMarkers]);
851
- const calculatedZoom = React3.useMemo(() => {
852
- if (normalizedStandaloneMarkers.length + normalizedClusters.length <= 1) {
853
- return markerFocusZoom;
854
- }
855
- const allCoords = [];
960
+ const zoomCoordinates = React3.useMemo(() => {
961
+ const coords = [];
856
962
  normalizedStandaloneMarkers.forEach((marker) => {
857
- allCoords.push({
858
- latitude: marker.latitude,
859
- longitude: marker.longitude
963
+ coords.push({
964
+ lat: marker.latitude,
965
+ lng: marker.longitude
860
966
  });
861
967
  });
862
968
  normalizedClusters.forEach((cluster) => {
863
- allCoords.push({
864
- latitude: cluster.latitude,
865
- longitude: cluster.longitude
969
+ coords.push({
970
+ lat: cluster.latitude,
971
+ lng: cluster.longitude
866
972
  });
867
973
  });
868
- if (allCoords.length === 0) {
974
+ return coords;
975
+ }, [normalizedStandaloneMarkers, normalizedClusters]);
976
+ const properZoom = useDefaultZoom({
977
+ coordinates: zoomCoordinates,
978
+ mapWidth: containerDimensions.width,
979
+ mapHeight: containerDimensions.height,
980
+ padding: 80,
981
+ // Increased padding for better framing
982
+ maxZoom: 18,
983
+ minZoom: 1
984
+ });
985
+ const calculatedZoom = React3.useMemo(() => {
986
+ if (zoomCoordinates.length === 1) {
987
+ return markerFocusZoom;
988
+ }
989
+ if (zoomCoordinates.length === 0) {
869
990
  return DEFAULT_VIEW_STATE.zoom;
870
991
  }
871
- const lats = allCoords.map((c) => c.latitude);
872
- const lngs = allCoords.map((c) => c.longitude);
873
- const latDiff = Math.max(...lats) - Math.min(...lats);
874
- const lngDiff = Math.max(...lngs) - Math.min(...lngs);
875
- const maxDiff = Math.max(latDiff, lngDiff);
876
- if (maxDiff > 10) return 3;
877
- if (maxDiff > 5) return 5;
878
- if (maxDiff > 2) return 7;
879
- if (maxDiff > 1) return 9;
880
- if (maxDiff > 0.5) return 10;
881
- if (maxDiff > 0.1) return 12;
882
- return 13;
883
- }, [normalizedClusters, normalizedStandaloneMarkers, markerFocusZoom]);
992
+ const adjustedZoom = properZoom ? properZoom - 0.5 : DEFAULT_VIEW_STATE.zoom;
993
+ return Math.min(adjustedZoom, 15);
994
+ }, [properZoom, zoomCoordinates.length, markerFocusZoom]);
884
995
  const [uncontrolledViewState, setUncontrolledViewState] = React3.useState({
885
996
  latitude: defaultViewState?.latitude ?? firstCoordinate.latitude,
886
997
  longitude: defaultViewState?.longitude ?? firstCoordinate.longitude,
@@ -1206,25 +1317,35 @@ function GeoMap({
1206
1317
  return /* @__PURE__ */ jsxs(
1207
1318
  "div",
1208
1319
  {
1320
+ ref: containerRef,
1209
1321
  className: cn(
1210
- "relative overflow-hidden rounded-2xl border border-border bg-background",
1322
+ "relative rounded-2xl border border-border bg-background",
1323
+ // Remove overflow-hidden from outer container to allow panel to overflow
1211
1324
  className
1212
1325
  ),
1326
+ style: {
1327
+ // If className includes height settings, they'll override via CSS specificity
1328
+ height: className?.includes("h-[") || className?.includes("min-h-[") || className?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
1329
+ // Explicitly allow overflow for marker panels
1330
+ overflow: "visible"
1331
+ },
1213
1332
  children: [
1214
1333
  /* @__PURE__ */ jsx(
1215
1334
  "div",
1216
1335
  {
1217
1336
  className: cn(
1218
- "w-full",
1219
- // Default height, can be overridden by mapWrapperClassName
1220
- mapWrapperClassName || "h-[520px]"
1337
+ "w-full rounded-2xl",
1338
+ // Only apply default height class if mapWrapperClassName not provided
1339
+ !mapWrapperClassName && `h-[${calculatedHeight}px]`,
1340
+ mapWrapperClassName
1221
1341
  ),
1222
1342
  style: {
1223
- // CRITICAL: Always use explicit height to prevent MapLibre canvas expansion
1224
- height: mapWrapperClassName ? void 0 : "520px",
1343
+ // If mapWrapperClassName includes height, let it handle the height
1344
+ height: mapWrapperClassName?.includes("h-[") || mapWrapperClassName?.includes("min-h-[") || mapWrapperClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`,
1225
1345
  maxHeight: "100vh",
1226
1346
  // Prevent excessive growth
1227
1347
  position: "relative",
1348
+ // Keep overflow hidden only on the map wrapper to contain the canvas
1228
1349
  overflow: "hidden"
1229
1350
  },
1230
1351
  children: /* @__PURE__ */ jsx(
@@ -1250,6 +1371,10 @@ function GeoMap({
1250
1371
  geolocateControlPosition,
1251
1372
  flyToOptions,
1252
1373
  className: cn("h-full w-full", mapClassName),
1374
+ style: {
1375
+ // Pass the calculated height to MapLibre for better zoom calculations
1376
+ height: mapClassName?.includes("h-[") || mapClassName?.includes("min-h-[") || mapClassName?.includes("max-h-[") ? void 0 : `${calculatedHeight}px`
1377
+ },
1253
1378
  children: mapChildren
1254
1379
  }
1255
1380
  )
@@ -1259,9 +1384,13 @@ function GeoMap({
1259
1384
  "div",
1260
1385
  {
1261
1386
  className: cn(
1262
- "pointer-events-none absolute z-20",
1387
+ "pointer-events-none absolute z-30",
1263
1388
  PANEL_POSITION_CLASS[panelPosition]
1264
1389
  ),
1390
+ style: {
1391
+ // Ensure panel can overflow and has higher z-index
1392
+ zIndex: 30
1393
+ },
1265
1394
  children: /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: renderMarkerPanel() })
1266
1395
  }
1267
1396
  ) : null