{"version":3,"file":"main.umd.cjs","names":[],"sources":["../src/main.ts"],"sourcesContent":["import type { VistaData, VistaExtension, VistaImageParams, VistaView } from 'vistaview';\nimport { VistaBox } from 'vistaview';\n\nexport interface OpenStreetMapConfig {\n  zoom?: number; // Default zoom level (0-19)\n  width?: number; // Map width in pixels\n  height?: number; // Map height in pixels\n  tileLayer?: string; // Tile layer URL (default: OpenStreetMap)\n  attribution?: string; // Custom attribution\n}\n\nexport interface OpenStreetMapLocation {\n  lat: number;\n  lng: number;\n  zoom?: number;\n}\n\n/**\n * Parse OpenStreetMap URL and extract location data\n * Supports various OpenStreetMap URL formats:\n * - https://www.openstreetmap.org/#map=15/40.7128/-74.0060\n * - https://www.openstreetmap.org/?mlat=40.7128&mlon=-74.0060#map=15/40.7128/-74.0060\n * - Custom format: osm://40.7128,-74.0060,15\n * @param url - OpenStreetMap URL or coordinate string\n * @returns Location data or null if not found\n */\nexport function parseOpenStreetMapLocation(url: string): OpenStreetMapLocation | null {\n  if (!url) return null;\n\n  try {\n    // Match custom format: osm://lat,lng,zoom or just lat,lng,zoom\n    const coordMatch = url.match(/(-?\\d+\\.?\\d*),\\s*(-?\\d+\\.?\\d*),?\\s*(\\d+\\.?\\d*)?/);\n    if (coordMatch) {\n      return {\n        lat: parseFloat(coordMatch[1]),\n        lng: parseFloat(coordMatch[2]),\n        zoom: coordMatch[3] ? parseFloat(coordMatch[3]) : undefined,\n      };\n    }\n\n    // Try URL parsing for openstreetmap.org links\n    const urlObj = new URL(url);\n    if (urlObj.hostname.includes('openstreetmap.org')) {\n      // Extract from hash like #map=15/40.7128/-74.0060\n      const hashMatch = urlObj.hash.match(/#map=(\\d+\\.?\\d*)\\/(-?\\d+\\.?\\d*)\\/(-?\\d+\\.?\\d*)/);\n      if (hashMatch) {\n        return {\n          zoom: parseFloat(hashMatch[1]),\n          lat: parseFloat(hashMatch[2]),\n          lng: parseFloat(hashMatch[3]),\n        };\n      }\n\n      // Extract from query params\n      const mlat = urlObj.searchParams.get('mlat');\n      const mlon = urlObj.searchParams.get('mlon');\n      if (mlat && mlon) {\n        return {\n          lat: parseFloat(mlat),\n          lng: parseFloat(mlon),\n        };\n      }\n    }\n  } catch (error) {\n    // Not a valid URL, might be coordinate string - already handled above\n  }\n\n  return null;\n}\n\n/**\n * Get OpenStreetMap static image URL\n * Uses a direct tile approach for static map preview\n * @param location - Location data\n * @param config - OpenStreetMap configuration\n * @returns Static map image URL\n */\nexport function getOpenStreetMapStaticImage(\n  location: OpenStreetMapLocation,\n  config: OpenStreetMapConfig\n): string {\n  const zoom = location.zoom || config.zoom || 15;\n\n  // Calculate tile coordinates for the given lat/lng/zoom\n  const lat = location.lat;\n  const lng = location.lng;\n  const n = Math.pow(2, zoom);\n  const x = Math.floor(((lng + 180) / 360) * n);\n  const y = Math.floor(\n    ((1 -\n      Math.log(Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)) / Math.PI) /\n      2) *\n      n\n  );\n\n  // Return a single tile centered on the location\n  return `https://tile.openstreetmap.org/${zoom}/${x}/${y}.png`;\n}\n\nexport class VistaOpenStreetMap extends VistaBox {\n  element: HTMLDivElement;\n  private osmConfig: OpenStreetMapConfig;\n  private location: OpenStreetMapLocation;\n  private thumbnailImage: HTMLImageElement;\n\n  constructor(par: VistaImageParams, config: OpenStreetMapConfig, location: OpenStreetMapLocation) {\n    super(par);\n\n    this.osmConfig = config;\n    this.location = location;\n\n    const div = document.createElement('div');\n    div.style.position = 'relative';\n    this.thumbnailImage = document.createElement('img');\n    div.appendChild(this.thumbnailImage);\n    this.thumbnailImage.src =\n      this.origin?.image.src || getOpenStreetMapStaticImage(location, config);\n    this.thumbnailImage.style.width = '100%';\n    this.thumbnailImage.style.height = '100%';\n    this.thumbnailImage.style.objectFit = 'cover';\n    this.thumbnailImage.classList.add('vvw--pulsing');\n\n    this.element = div;\n\n    this.element.classList.add('vvw-img-hi');\n\n    // Set sizes\n    const { width: fullWidth, height: fullHeight } = this.getFullSizeDim();\n    this.fullH = fullHeight;\n    this.fullW = fullWidth;\n    this.minW = this.fullW * 0.5;\n    this.maxW = this.fullW; // no scaling\n    this.element.style.width = `${fullWidth}px`;\n    this.element.style.height = `${fullHeight}px`;\n\n    // Trigger setSizes to setup thumb and map initial style\n    this.setSizes({ stableSize: false, initDimension: true });\n\n    if (this.pos === 0) {\n      // Load Leaflet dynamically if not already loaded\n      this.loadLeaflet().then(() => {\n        this.initializeMap(div);\n      });\n    } else {\n      this.isLoadedResolved!(true);\n    }\n  }\n\n  private async loadLeaflet(): Promise<void> {\n    // Check if Leaflet is already loaded\n    if ((window as any).L) {\n      return;\n    }\n\n    // Load CSS\n    if (!document.querySelector('.vistaview-leaflet-css')) {\n      const link = document.createElement('link');\n      link.rel = 'stylesheet';\n      link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';\n      link.className = 'vistaview-leaflet-css';\n      document.head.appendChild(link);\n    }\n\n    // Load JS\n    if (document.querySelector('.vistaview-leaflet-js')) {\n      return;\n    }\n\n    return new Promise((resolve, reject) => {\n      const script = document.createElement('script');\n      script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';\n      script.className = 'vistaview-leaflet-js';\n      script.onload = () => resolve();\n      script.onerror = () => reject(new Error('Failed to load Leaflet'));\n      document.head.appendChild(script);\n    });\n  }\n\n  private initializeMap(container: HTMLDivElement): void {\n    const L = (window as any).L;\n    if (!L) {\n      this.isLoadedRejected!(new Error('Leaflet not loaded'));\n      return;\n    }\n\n    // Create map container div\n    const mapDiv = document.createElement('div');\n    mapDiv.style.position = 'absolute';\n    mapDiv.style.top = '0';\n    mapDiv.style.left = '0';\n    mapDiv.style.width = '100%';\n    mapDiv.style.height = '100%';\n    mapDiv.style.opacity = '0';\n    mapDiv.style.transition = 'opacity 1s ease';\n    container.appendChild(mapDiv);\n\n    // Stop pointer events from propagating to VistaView's drag handlers\n    mapDiv.addEventListener('pointerdown', (e) => {\n      e.stopPropagation();\n    });\n\n    // Initialize Leaflet map\n    const map = L.map(mapDiv, {\n      center: [this.location.lat, this.location.lng],\n      zoom: this.location.zoom || this.osmConfig.zoom || 15,\n    });\n\n    // Add tile layer\n    const tileLayer =\n      this.osmConfig.tileLayer || 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';\n    const attribution =\n      this.osmConfig.attribution ||\n      '&copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors';\n\n    L.tileLayer(tileLayer, {\n      attribution: attribution,\n      maxZoom: 19,\n    }).addTo(map);\n\n    // Add marker\n    L.marker([this.location.lat, this.location.lng])\n      .addTo(map)\n      .bindPopup(`${this.location.lat}, ${this.location.lng}`);\n\n    // Wait for tiles to load\n    map.whenReady(() => {\n      this.onImageReady = () => {\n        map.invalidateSize();\n        mapDiv.style.opacity = '1';\n        this.thumbnailImage.classList.remove('vvw--pulsing');\n      };\n\n      this.isLoadedResolved!(true);\n    });\n  }\n\n  // Use 16:9 aspect ratio with max 800px width\n  protected getFullSizeDim(): { width: number; height: number } {\n    const maxWidth = Math.min(window.innerWidth, this.osmConfig.width || 800);\n    return {\n      width: maxWidth,\n      height: (maxWidth * 9) / 16,\n    };\n  }\n\n  // Override to avoid propagating content change event\n  setFinalTransform() {\n    return super.setFinalTransform({ propagateEvent: false });\n  }\n}\n\nexport function openStreetMap(config: OpenStreetMapConfig = {}): VistaExtension {\n  return {\n    name: 'openStreetMap',\n    onInitializeImage: (params: VistaImageParams) => {\n      const url = params.elm.config.src;\n      const location = parseOpenStreetMapLocation(url);\n      if (!location) return;\n\n      return new VistaOpenStreetMap(params, config, location);\n    },\n    onImageView: async (data: VistaData, v: VistaView) => {\n      const mainData = data.images.to![Math.floor(data.images.to!.length / 2)];\n      if (mainData instanceof VistaOpenStreetMap) {\n        v.deactivateUi(['download', 'zoomIn', 'zoomOut'], mainData);\n      }\n    },\n  };\n}\n"],"mappings":"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"}