@mapfirst.ai/core 0.0.25 → 0.0.26

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 +1 @@
1
- {"version":3,"sources":["#style-inject:#style-inject","../src/markers.css","../src/dotmarker.ts","../src/marker.ts","../src/marker-updater.ts","../src/adapters/markermanager.ts","../src/adapters/maplibre/markermanager.ts","../src/adapters/google/markermanager.ts","../src/adapters/mapbox/markermanager.ts","../src/adapters/index.ts","../src/adapters/maplibre/index.ts","../src/adapters/google/index.ts","../src/adapters/mapbox/index.ts","../src/utils/clustering.ts","../src/utils/filters.ts","../src/index.ts"],"sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\".mapfirst-marker-root{display:flex;z-index:20;flex-direction:column;align-items:center;pointer-events:auto}.mapfirst-marker-pill{border:2px solid;border-radius:999px;padding:8px;font-size:16px;font-weight:600;font-family:system-ui,-apple-system,sans-serif;box-shadow:0 4px 6px #6b728080;display:flex;align-items:center;justify-content:center;position:relative;transition:transform .2s;transform-origin:center bottom}.mapfirst-marker-pill-pending{background:#ffffff80;backdrop-filter:blur(4px);border-color:transparent;cursor:default}.mapfirst-marker-pill-active{background:#012b11;border-color:#fff;color:#fff;cursor:pointer}.mapfirst-marker-pill-active.mapfirst-marker-non-primary{background:#ffffffb3;border-color:#03852e80;color:#03852e80;padding:4px}.mapfirst-marker-pill-active.mapfirst-marker-selected{background:#fff;border-color:#03852e;color:#03852e;transform:scale(1.2)}.mapfirst-marker-pill-active:hover{transform:scale(1.2)}.mapfirst-marker-badge{position:absolute;top:-12px;right:-20px}.mapfirst-marker-award-container{position:relative;width:32px;height:32px}.mapfirst-marker-award-back{position:absolute;stroke:#f5f5f5;stroke-width:2px}.mapfirst-marker-award-dot{position:absolute;top:6.2px;left:6.3px;width:18.5px;height:18.5px;border-radius:50%;z-index:1}.mapfirst-marker-award-dot-type-0{background:#ffef0e}.mapfirst-marker-award-dot-type-1{background:#01ea5b}.mapfirst-marker-award-front{position:relative;z-index:2;color:#012b11}.mapfirst-marker-rating-badge{display:flex;align-items:center;justify-content:center;border-radius:999px;background:#03852e;color:#fff;font-size:12px;line-height:1;box-shadow:0 2px 4px #0003;padding:2px 6px;border:2px solid #ffffff;font-weight:400}.mapfirst-marker-content{display:flex;align-items:center}.mapfirst-dot-marker-container{display:flex;z-index:10;align-items:center;justify-content:center;pointer-events:auto}.mapfirst-dot-marker-button{width:20px;height:20px;border-radius:999px;border:2px solid #ffffff;box-shadow:0 2px 4px #6b728066;transition:transform .2s;outline:none;transform-origin:center center}.mapfirst-dot-marker-button-pending{background:#d1d5db;cursor:default}.mapfirst-dot-marker-button-active{background:#012b11;cursor:pointer}.mapfirst-dot-marker-button-active.mapfirst-dot-marker-non-primary{background:#ffffffb3;border-color:#03852e33}.mapfirst-dot-marker-button-active.mapfirst-dot-marker-selected{background:#fff;border-color:#03852e}.mapfirst-dot-marker-button-active:hover{transform:scale(1.2)}.mapfirst-dot-marker-button-active:focus{outline:2px solid #ffffff;outline-offset:2px}.mapfirst-property-hover-card{position:absolute;width:270px;background:#fff;border-radius:8px;box-shadow:0 4px 12px #00000026;overflow:hidden;display:flex;pointer-events:auto;z-index:9999;transition:opacity .2s}.mapfirst-property-hover-card img{width:120px;height:120px;object-fit:cover;flex-shrink:0}.mapfirst-property-hover-details{display:flex;flex-direction:column;padding:8px 12px;flex:1;gap:4px}.mapfirst-property-hover-name{font-size:14px;font-weight:600;color:#1a1a1a;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.3}.mapfirst-property-hover-rating{display:flex;align-items:center;gap:4px;font-size:12px}.mapfirst-property-hover-rating .rating-value{font-weight:600;color:#1a1a1a}.mapfirst-property-hover-rating .stars{display:flex;gap:1px;font-size:10px;line-height:1}.mapfirst-property-hover-rating .reviews{color:#666;font-size:11px}.mapfirst-property-hover-price{font-size:12px;color:#666;margin-top:2px}.mapfirst-property-hover-price strong{color:#1a1a1a;font-weight:600}.mapfirst-property-hover-learn-more{font-size:12px;color:#03852e;text-decoration:none;font-weight:500;margin-top:auto;pointer-events:auto;display:inline-block}.mapfirst-property-hover-learn-more:hover{text-decoration:underline}\\n\")","import type { Property } from \".\";\r\nimport \"./markers.css\";\r\nimport { ClusterDisplayItem } from \"./utils/clustering\";\r\n\r\nexport function createDotMarkerElement(\r\n item: Extract<ClusterDisplayItem, { kind: \"dot\" }>,\r\n primaryType: string,\r\n selectedMarkerId: number | null,\r\n onMarkerClick?: (marker: Property) => void\r\n) {\r\n if (typeof document === \"undefined\") {\r\n return null;\r\n }\r\n\r\n const marker = item.marker;\r\n const isPrimaryType = marker.type === primaryType;\r\n const isSelected = selectedMarkerId === marker.tripadvisor_id;\r\n const isAccommodation = marker.type === \"Accommodation\";\r\n const isPending =\r\n isAccommodation && marker.pricing?.offer?.availability !== \"available\";\r\n\r\n // Create container div to match primary marker structure\r\n const container = document.createElement(\"div\");\r\n container.className = \"mapfirst-dot-marker-container\";\r\n container.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"3\" : \"1\";\r\n\r\n const button = document.createElement(\"div\");\r\n button.className = isPending\r\n ? \"mapfirst-dot-marker-button mapfirst-dot-marker-button-pending\"\r\n : `mapfirst-dot-marker-button mapfirst-dot-marker-button-active${\r\n isSelected\r\n ? \" mapfirst-dot-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-dot-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n button.title = marker.name ?? String(marker.tripadvisor_id);\r\n\r\n button.addEventListener(\"click\", (evt) => {\r\n evt.stopPropagation();\r\n if (!isPending) {\r\n onMarkerClick?.(marker);\r\n }\r\n });\r\n\r\n container.appendChild(button);\r\n return container;\r\n}\r\n","import type { Property } from \".\";\r\nimport \"./markers.css\";\r\nimport { ClusterDisplayItem } from \"./utils/clustering\";\r\n\r\nconst AWARD_SVG = `<svg viewBox=\"0 0 24 24\" width=\"32\" height=\"32\" fill=\"currentColor\"><path d=\"M12 3.953a7.442 7.442 0 1 0 .001 14.884A7.442 7.442 0 0 0 12 3.953m0 14.05a6.61 6.61 0 1 1 0-13.218 6.61 6.61 0 0 1 0 13.219M10.343 11.9a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.821 0m5.134 0a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.82 0m.82-1.897.84-.913h-1.863A5.8 5.8 0 0 0 12 8.08a5.77 5.77 0 0 0-3.27 1.008H6.862l.84.913a2.567 2.567 0 1 0 3.475 3.78l.823.896.823-.895a2.568 2.568 0 1 0 3.474-3.78m-6.865 3.634a1.738 1.738 0 1 1 0-3.476 1.738 1.738 0 0 1 0 3.476M12 11.85c0-1.143-.832-2.124-1.929-2.543A5 5 0 0 1 12 8.92a5 5 0 0 1 1.928.386c-1.096.42-1.927 1.4-1.927 2.543m2.566 1.787a1.738 1.738 0 1 1 .001-3.476 1.738 1.738 0 0 1 0 3.476m-8.456 3.719s-.377-.946-1.396-1.903c-1.02-.957-2.303-1.132-2.303-1.132s.457 1.02 1.54 2.04c1.086 1.017 2.159.995 2.159.995m2.568 1.41s-.524-.511-1.479-.883-1.861-.191-1.861-.191.598.54 1.615.935c1.016.397 1.725.139 1.725.139m2.493.505s-.545-.224-1.357-.196-1.415.47-1.415.47.608.222 1.473.193 1.3-.467 1.3-.467m-6.186-4.203s-.175-1.008-.974-2.154c-.8-1.147-2.015-1.578-2.015-1.578s.238 1.098 1.089 2.319c.85 1.22 1.9 1.413 1.9 1.413m-1.003-3.071s.195-1.021-.134-2.393c-.328-1.371-1.294-2.21-1.294-2.21s-.17 1.128.18 2.589c.35 1.46 1.248 2.014 1.248 2.014\"></path><path d=\"M17.887 17.355s.377-.946 1.396-1.903c1.02-.957 2.303-1.132 2.303-1.132s-.457 1.02-1.54 2.04c-1.086 1.017-2.159.995-2.159.995m-2.567 1.41s.524-.511 1.479-.883 1.861-.191 1.861-.191-.598.54-1.615.935c-1.016.397-1.725.139-1.725.139m-2.493.505s.545-.224 1.357-.196 1.415.47 1.415.47-.608.222-1.473.193-1.3-.467-1.3-.467m6.186-4.203s.175-1.008.974-2.154c.8-1.147 2.015-1.578 2.015-1.578s-.238 1.098-1.089 2.319c-.85 1.22-1.9 1.413-1.9 1.413m1.003-3.071s-.195-1.021.133-2.393c.33-1.371 1.293-2.21 1.293-2.21s.17 1.128-.18 2.589c-.349 1.46-1.246 2.014-1.246 2.014M12 20.047a.413.413 0 1 0 0-.827.413.413 0 0 0 0 .827\"></path></svg>`;\r\n\r\nconst AWARD_BACK_SVG = `<svg viewBox=\"0 0 24 24\" width=\"32\" height=\"32\"><path d=\"M12 3.953a7.442 7.442 0 1 0 .001 14.884A7.442 7.442 0 0 0 12 3.953m0 14.05a6.61 6.61 0 1 1 0-13.218 6.61 6.61 0 0 1 0 13.219M10.343 11.9a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.821 0m5.134 0a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.82 0m.82-1.897.84-.913h-1.863A5.8 5.8 0 0 0 12 8.08a5.77 5.77 0 0 0-3.27 1.008H6.862l.84.913a2.567 2.567 0 1 0 3.475 3.78l.823.896.823-.895a2.568 2.568 0 1 0 3.474-3.78m-6.865 3.634a1.738 1.738 0 1 1 0-3.476 1.738 1.738 0 0 1 0 3.476M12 11.85c0-1.143-.832-2.124-1.929-2.543A5 5 0 0 1 12 8.92a5 5 0 0 1 1.928.386c-1.096.42-1.927 1.4-1.927 2.543m2.566 1.787a1.738 1.738 0 1 1 .001-3.476 1.738 1.738 0 0 1 0 3.476m-8.456 3.719s-.377-.946-1.396-1.903c-1.02-.957-2.303-1.132-2.303-1.132s.457 1.02 1.54 2.04c1.086 1.017 2.159.995 2.159.995m2.568 1.41s-.524-.511-1.479-.883-1.861-.191-1.861-.191.598.54 1.615.935c1.016.397 1.725.139 1.725.139m2.493.505s-.545-.224-1.357-.196-1.415.47-1.415.47.608.222 1.473.193 1.3-.467 1.3-.467m-6.186-4.203s-.175-1.008-.974-2.154c-.8-1.147-2.015-1.578-2.015-1.578s.238 1.098 1.089 2.319c.85 1.22 1.9 1.413 1.9 1.413m-1.003-3.071s.195-1.021-.134-2.393c-.328-1.371-1.294-2.21-1.294-2.21s-.17 1.128.18 2.589c.35 1.46 1.248 2.014 1.248 2.014\"></path><path d=\"M17.887 17.355s.377-.946 1.396-1.903c1.02-.957 2.303-1.132 2.303-1.132s-.457 1.02-1.54 2.04c-1.086 1.017-2.159.995-2.159.995m-2.567 1.41s.524-.511 1.479-.883 1.861-.191 1.861-.191-.598.54-1.615.935c-1.016.397-1.725.139-1.725.139m-2.493.505s.545-.224 1.357-.196 1.415.47 1.415.47-.608.222-1.473.193-1.3-.467-1.3-.467m6.186-4.203s.175-1.008.974-2.154c.8-1.147 2.015-1.578 2.015-1.578s-.238 1.098-1.089 2.319c-.85 1.22-1.9 1.413-1.9 1.413m1.003-3.071s-.195-1.021.133-2.393c.33-1.371 1.293-2.21 1.293-2.21s.17 1.128-.18 2.589c-.349 1.46-1.246 2.014-1.246 2.014M12 20.047a.413.413 0 1 0 0-.827.413.413 0 0 0 0 .827\"></path></svg>`;\r\n\r\nconst EAT_DRINK_SVG = `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M14.051 6.549v.003l1.134 1.14 3.241-3.25.003-.002 1.134 1.136-3.243 3.252 1.134 1.14a1 1 0 0 0 .09-.008c.293-.05.573-.324.72-.474l.005-.006 2.596-2.603L22 8.016l-2.597 2.604a3.73 3.73 0 0 1-1.982 1.015 4.3 4.3 0 0 1-3.162-.657l-.023-.016-.026-.018-1.366 1.407 8.509 8.512L20.219 22l-.002-.002-6.654-6.663-2.597 2.76-7.3-7.315C1.967 8.948 1.531 6.274 2.524 4.198c.241-.504.566-.973.978-1.386l8.154 8.416 1.418-1.423-.039-.045c-.858-1.002-1.048-2.368-.62-3.595a4.15 4.15 0 0 1 .983-1.561L16 2l1.135 1.138-2.598 2.602-.047.045c-.16.151-.394.374-.433.678zM3.809 5.523c-.362 1.319-.037 2.905 1.06 4.103L10.93 15.7l1.408-1.496zM2.205 20.697 3.34 21.84l4.543-4.552-1.135-1.143z\"/></svg>`;\r\n\r\nconst ATTRACTION_SVG = `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M7.56 7.5H3.75a.25.25 0 0 0-.25.25v10c0 .138.112.25.25.25h16.5a.25.25 0 0 0 .25-.25v-10a.25.25 0 0 0-.25-.25h-3.81l-2-2H9.56zM8.94 4h6.12l2 2h3.19c.966 0 1.75.784 1.75 1.75v10a1.75 1.75 0 0 1-1.75 1.75H3.75A1.75 1.75 0 0 1 2 17.75v-10C2 6.784 2.784 6 3.75 6h3.19z\"/><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M12 9.25a2.75 2.75 0 1 0 0 5.5 2.75 2.75 0 0 0 0-5.5M7.75 12a4.25 4.25 0 1 1 8.5 0 4.25 4.25 0 0 1-8.5 0\"/></svg>`;\r\n\r\nfunction getDefaultImageForType(type: string): string {\r\n const normalizedType = type\r\n .toLowerCase()\r\n .replace(/\\s+/g, \"\")\r\n .replace(/&/g, \"\");\r\n return `/img/${normalizedType}.webp`;\r\n}\r\n\r\nfunction createPropertyCard(marker: Property): HTMLElement {\r\n const card = document.createElement(\"div\");\r\n card.className = \"mapfirst-property-hover-card\";\r\n\r\n const rating = marker.rating || 0;\r\n const reviews = marker.reviews || 0;\r\n const displayPrice =\r\n marker.pricing?.offer?.displayPrice ?? marker.price_level;\r\n const url = marker.pricing?.offer?.clickUrl ?? marker.urls?.tripadvisor.main;\r\n\r\n // Generate star rating\r\n const renderStars = () => {\r\n const fullStars = Math.floor(rating);\r\n const hasHalfStar = rating % 1 >= 0.5;\r\n const stars = [];\r\n\r\n for (let i = 0; i < fullStars; i++) {\r\n stars.push(`<span style=\"color: #03852e\">●</span>`);\r\n }\r\n if (hasHalfStar) {\r\n stars.push(`<span style=\"color: #03852e\">◐</span>`);\r\n }\r\n const emptyStars = 5 - stars.length;\r\n for (let i = 0; i < emptyStars; i++) {\r\n stars.push(`<span style=\"color: #ccc\">○</span>`);\r\n }\r\n return stars.join(\"\");\r\n };\r\n\r\n const imageUrl = getDefaultImageForType(marker.type);\r\n\r\n card.innerHTML = `\r\n <img \r\n src=\"${imageUrl}\" \r\n alt=\"${marker.name}\"\r\n onerror=\"this.src='/images/placeholder.jpg'\"\r\n />\r\n <div class=\"mapfirst-property-hover-details\">\r\n <div class=\"mapfirst-property-hover-name\">${marker.name}</div>\r\n <div class=\"mapfirst-property-hover-rating\">\r\n <span class=\"rating-value\">${rating.toFixed(1)}</span>\r\n <span class=\"stars\">${renderStars()}</span>\r\n <span class=\"reviews\">(${reviews})</span>\r\n </div>\r\n ${\r\n marker.type === \"Accommodation\" && displayPrice\r\n ? `\r\n <div class=\"mapfirst-property-hover-price\">\r\n Starting at <strong>${displayPrice}</strong>\r\n </div>\r\n `\r\n : \"\"\r\n }\r\n ${\r\n url\r\n ? `\r\n <a\r\n href=\"${url}\"\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n class=\"mapfirst-property-hover-learn-more\"\r\n >\r\n Learn More\r\n </a>\r\n `\r\n : \"\"\r\n }\r\n </div>\r\n `;\r\n\r\n return card;\r\n}\r\n\r\nfunction positionCard(\r\n card: HTMLElement,\r\n markerElement: HTMLElement,\r\n mapContainer: HTMLElement\r\n) {\r\n // Get marker position and dimensions\r\n const markerRect = markerElement.getBoundingClientRect();\r\n const containerRect = mapContainer.getBoundingClientRect();\r\n\r\n const cardWidth = 270; // Fixed card width\r\n const cardHeight = 120; // Approximate card height\r\n const offset = 12; // Gap between marker and card\r\n\r\n // Calculate available space on each side\r\n const spaceRight = containerRect.right - markerRect.right;\r\n const spaceLeft = markerRect.left - containerRect.left;\r\n const spaceBottom = containerRect.bottom - markerRect.bottom;\r\n const spaceTop = markerRect.top - containerRect.top;\r\n\r\n // Default position: bottom center\r\n let left =\r\n markerRect.left - containerRect.left + markerRect.width / 2 - cardWidth / 2;\r\n let top = markerRect.top - containerRect.top + markerRect.height + offset;\r\n\r\n // Horizontal adjustment if card would overflow\r\n if (left < 0) {\r\n left = 8; // Small margin from left edge\r\n } else if (left + cardWidth > containerRect.width) {\r\n left = containerRect.width - cardWidth - 8; // Small margin from right edge\r\n }\r\n\r\n // Vertical adjustment if not enough space below\r\n if (spaceBottom < cardHeight + offset && spaceTop > spaceBottom) {\r\n // Position above if more space above\r\n top = markerRect.top - containerRect.top - cardHeight - offset;\r\n }\r\n\r\n card.style.left = `${left}px`;\r\n card.style.top = `${top}px`;\r\n}\r\n\r\nexport function createPrimaryMarkerElement(\r\n item: Extract<ClusterDisplayItem, { kind: \"primary\" }>,\r\n primaryType: string,\r\n selectedMarkerId: number | null,\r\n onMarkerClick?: (marker: Property) => void\r\n) {\r\n if (typeof document === \"undefined\") {\r\n return null;\r\n }\r\n\r\n const marker = item.marker;\r\n const isPrimaryType = marker.type === primaryType;\r\n const isSelected = selectedMarkerId === marker.tripadvisor_id;\r\n const isAccommodation = marker.type === \"Accommodation\";\r\n const hasPrice = marker.pricing?.offer?.displayPrice;\r\n const isPending = isAccommodation && !hasPrice;\r\n\r\n // Rating\r\n const ratingLabel = (() => {\r\n if (marker.rating === undefined || marker.rating === null) return null;\r\n const numeric =\r\n typeof marker.rating === \"number\" ? marker.rating : Number(marker.rating);\r\n if (Number.isNaN(numeric) || numeric <= 0) return null;\r\n return numeric.toFixed(1);\r\n })();\r\n\r\n const root = document.createElement(\"div\");\r\n root.className = \"mapfirst-marker-root\";\r\n root.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"12\" : \"11\";\r\n\r\n const pill = document.createElement(\"div\");\r\n pill.className = isPending\r\n ? \"mapfirst-marker-pill mapfirst-marker-pill-pending\"\r\n : `mapfirst-marker-pill mapfirst-marker-pill-active${\r\n isSelected\r\n ? \" mapfirst-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n // pill.title = marker.name ?? String(marker.tripadvisor_id);\r\n\r\n // Awards or Rating badge\r\n if (!isPending && (marker.awards?.length || ratingLabel)) {\r\n const badge = document.createElement(\"div\");\r\n badge.className = \"mapfirst-marker-badge\";\r\n if (!isPrimaryType) {\r\n badge.style.opacity = \"0.2\";\r\n }\r\n badge.className = \"mapfirst-marker-badge\";\r\n\r\n if (marker.awards?.length && marker.awards[0].type) {\r\n const awardContainer = document.createElement(\"div\");\r\n awardContainer.className = \"mapfirst-marker-award-container\";\r\n\r\n const backLayer = document.createElement(\"div\");\r\n backLayer.className = \"mapfirst-marker-award-back\";\r\n backLayer.innerHTML = AWARD_BACK_SVG;\r\n\r\n const colorDot = document.createElement(\"div\");\r\n colorDot.className = `mapfirst-marker-award-dot mapfirst-marker-award-dot-type-${marker.awards[0].type}`;\r\n\r\n const frontLayer = document.createElement(\"div\");\r\n frontLayer.className = \"mapfirst-marker-award-front\";\r\n frontLayer.innerHTML = AWARD_SVG;\r\n\r\n awardContainer.appendChild(backLayer);\r\n awardContainer.appendChild(colorDot);\r\n awardContainer.appendChild(frontLayer);\r\n badge.appendChild(awardContainer);\r\n } else if (ratingLabel) {\r\n badge.className = \"mapfirst-marker-badge mapfirst-marker-rating-badge\";\r\n badge.textContent = ratingLabel;\r\n }\r\n\r\n pill.appendChild(badge);\r\n }\r\n\r\n // Content\r\n const content = document.createElement(\"span\");\r\n content.className = \"mapfirst-marker-content\";\r\n if (isAccommodation) {\r\n content.textContent = marker.pricing?.offer?.displayPrice ?? \"—\";\r\n } else if (marker.type === \"Eat & Drink\") {\r\n content.innerHTML = EAT_DRINK_SVG;\r\n } else if (marker.type === \"Attraction\") {\r\n content.innerHTML = ATTRACTION_SVG;\r\n }\r\n pill.appendChild(content);\r\n\r\n pill.addEventListener(\"click\", (evt) => {\r\n evt.stopPropagation();\r\n if (!isPending) {\r\n onMarkerClick?.(marker);\r\n }\r\n });\r\n\r\n // Add hover card\r\n if (!isPending) {\r\n const propertyCard = createPropertyCard(marker);\r\n let hoverTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let hideTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let positionUpdateFrame: number | null = null;\r\n\r\n const cleanupCard = () => {\r\n if (hoverTimeout) {\r\n clearTimeout(hoverTimeout);\r\n hoverTimeout = null;\r\n }\r\n if (hideTimeout) {\r\n clearTimeout(hideTimeout);\r\n hideTimeout = null;\r\n }\r\n if (positionUpdateFrame) {\r\n cancelAnimationFrame(positionUpdateFrame);\r\n positionUpdateFrame = null;\r\n }\r\n if (propertyCard.parentElement) {\r\n propertyCard.remove();\r\n }\r\n };\r\n\r\n const updateCardPosition = () => {\r\n if (propertyCard.parentElement) {\r\n let mapContainer = root.parentElement;\r\n while (\r\n mapContainer &&\r\n getComputedStyle(mapContainer).position === \"static\"\r\n ) {\r\n mapContainer = mapContainer.parentElement;\r\n }\r\n\r\n if (mapContainer) {\r\n positionCard(propertyCard, root, mapContainer);\r\n positionUpdateFrame = requestAnimationFrame(updateCardPosition);\r\n }\r\n }\r\n };\r\n\r\n const showCard = (immediate = false) => {\r\n if (hideTimeout) {\r\n clearTimeout(hideTimeout);\r\n hideTimeout = null;\r\n }\r\n\r\n const doShow = () => {\r\n // Find map container\r\n let mapContainer = root.parentElement;\r\n while (\r\n mapContainer &&\r\n getComputedStyle(mapContainer).position === \"static\"\r\n ) {\r\n mapContainer = mapContainer.parentElement;\r\n }\r\n\r\n if (mapContainer) {\r\n mapContainer.appendChild(propertyCard);\r\n positionCard(propertyCard, root, mapContainer);\r\n // Start continuous position updates\r\n positionUpdateFrame = requestAnimationFrame(updateCardPosition);\r\n }\r\n };\r\n\r\n if (immediate) {\r\n doShow();\r\n } else {\r\n hoverTimeout = setTimeout(doShow, 300); // Delay to avoid showing on quick hovers\r\n }\r\n };\r\n\r\n const hideCard = () => {\r\n // Don't hide if marker is selected\r\n if (isSelected) return;\r\n\r\n if (hoverTimeout) {\r\n clearTimeout(hoverTimeout);\r\n hoverTimeout = null;\r\n }\r\n if (positionUpdateFrame) {\r\n cancelAnimationFrame(positionUpdateFrame);\r\n positionUpdateFrame = null;\r\n }\r\n hideTimeout = setTimeout(() => {\r\n if (propertyCard.parentElement) {\r\n propertyCard.remove();\r\n }\r\n }, 100); // Small delay to allow mouse to enter card\r\n };\r\n\r\n // Show card immediately if marker is selected\r\n if (isSelected) {\r\n showCard(true);\r\n }\r\n\r\n pill.addEventListener(\"mouseenter\", () => showCard(false));\r\n pill.addEventListener(\"mouseleave\", hideCard);\r\n\r\n // Keep card visible when hovering over it\r\n propertyCard.addEventListener(\"mouseenter\", () => {\r\n if (hideTimeout) {\r\n clearTimeout(hideTimeout);\r\n hideTimeout = null;\r\n }\r\n // Resume position updates if stopped\r\n if (!positionUpdateFrame && propertyCard.parentElement) {\r\n positionUpdateFrame = requestAnimationFrame(updateCardPosition);\r\n }\r\n });\r\n\r\n propertyCard.addEventListener(\"mouseleave\", hideCard);\r\n\r\n // Cleanup card when marker is removed from DOM\r\n const observer = new MutationObserver((mutations) => {\r\n for (const mutation of mutations) {\r\n for (const removedNode of mutation.removedNodes) {\r\n if (removedNode === root || removedNode.contains(root)) {\r\n cleanupCard();\r\n observer.disconnect();\r\n return;\r\n }\r\n }\r\n }\r\n });\r\n\r\n // Start observing when the root is added to the DOM\r\n if (root.parentElement) {\r\n observer.observe(root.parentElement, { childList: true, subtree: true });\r\n } else {\r\n // If not yet in DOM, wait for it\r\n const checkParent = setInterval(() => {\r\n if (root.parentElement) {\r\n observer.observe(root.parentElement, {\r\n childList: true,\r\n subtree: true,\r\n });\r\n clearInterval(checkParent);\r\n }\r\n }, 100);\r\n }\r\n }\r\n\r\n root.appendChild(pill);\r\n return root;\r\n}\r\n","/**\r\n * Utility functions to update marker DOM elements without recreating them\r\n */\r\n\r\n/**\r\n * Updates the z-index and CSS classes of a primary marker element\r\n */\r\nexport function updatePrimaryMarkerElement(\r\n element: HTMLElement,\r\n isPrimaryType: boolean,\r\n isSelected: boolean,\r\n isPending: boolean\r\n) {\r\n // Update root z-index\r\n const root = element;\r\n root.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"12\" : \"11\";\r\n\r\n // Update pill classes\r\n const pill = root.querySelector(\".mapfirst-marker-pill\");\r\n if (pill) {\r\n if (isPending) {\r\n pill.className = \"mapfirst-marker-pill mapfirst-marker-pill-pending\";\r\n } else {\r\n pill.className = `mapfirst-marker-pill mapfirst-marker-pill-active${\r\n isSelected\r\n ? \" mapfirst-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n }\r\n }\r\n\r\n // Update badge opacity for non-primary markers\r\n const badge = root.querySelector(\".mapfirst-marker-badge\");\r\n if (badge instanceof HTMLElement) {\r\n badge.style.opacity = !isPrimaryType && !isSelected ? \"0.2\" : \"\";\r\n }\r\n}\r\n\r\n/**\r\n * Updates the z-index and CSS classes of a dot marker element\r\n */\r\nexport function updateDotMarkerElement(\r\n element: HTMLElement,\r\n isPrimaryType: boolean,\r\n isSelected: boolean,\r\n isPending: boolean\r\n) {\r\n // Update container z-index\r\n const container = element;\r\n container.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"3\" : \"1\";\r\n\r\n // Update button classes\r\n const button = container.querySelector(\".mapfirst-dot-marker-button\");\r\n if (button) {\r\n if (isPending) {\r\n button.className =\r\n \"mapfirst-dot-marker-button mapfirst-dot-marker-button-pending\";\r\n } else {\r\n button.className = `mapfirst-dot-marker-button mapfirst-dot-marker-button-active${\r\n isSelected\r\n ? \" mapfirst-dot-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-dot-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Extracts the tripadvisor_id from a marker key\r\n */\r\nexport function extractMarkerIdFromKey(key: string): number | null {\r\n const match = key.match(/^(?:primary|dot)-(\\d+)-/);\r\n return match ? parseInt(match[1], 10) : null;\r\n}\r\n\r\n/**\r\n * Extracts the state flags from a marker key\r\n */\r\nexport function extractStateFromKey(key: string): {\r\n isPrimary: boolean;\r\n isSelected: boolean;\r\n} {\r\n const match = key.match(/-p([01])-s([01])$/);\r\n if (!match) {\r\n return { isPrimary: true, isSelected: false };\r\n }\r\n return {\r\n isPrimary: match[1] === \"1\",\r\n isSelected: match[2] === \"1\",\r\n };\r\n}\r\n","import type { Property } from \"../types\";\r\nimport { createDotMarkerElement } from \"../dotmarker\";\r\nimport { createPrimaryMarkerElement } from \"../marker\";\r\nimport {\r\n updatePrimaryMarkerElement,\r\n updateDotMarkerElement,\r\n extractMarkerIdFromKey,\r\n} from \"../marker-updater\";\r\nimport { ClusterDisplayItem } from \"../utils/clustering\";\r\n\r\nexport type MarkerEntry<T = any> = {\r\n key: string;\r\n marker: T;\r\n kind: \"primary\" | \"dot\";\r\n parentId?: number;\r\n};\r\n\r\nexport abstract class BaseMarkerManager<TMarker = any> {\r\n protected readonly mapInstance: any;\r\n protected readonly onMarkerClick?: (marker: Property) => void;\r\n protected markerCache = new Map<string, MarkerEntry<TMarker>>();\r\n protected primaryType: string = \"Accommodation\";\r\n protected selectedMarkerId: number | null = null;\r\n\r\n constructor(mapInstance: any, onMarkerClick?: (marker: Property) => void) {\r\n this.mapInstance = mapInstance;\r\n this.onMarkerClick = onMarkerClick;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (primaryType && primaryType !== this.primaryType) {\r\n this.primaryType = primaryType;\r\n }\r\n if (selectedMarkerId !== undefined) {\r\n this.selectedMarkerId = selectedMarkerId;\r\n }\r\n\r\n // Create a set of keys for the new items\r\n const newKeys = new Set(items.map((item) => item.key));\r\n\r\n // Remove markers that are no longer needed\r\n for (const [key, entry] of this.markerCache.entries()) {\r\n if (!newKeys.has(key)) {\r\n this.removeMarkerFromMap(entry.marker);\r\n this.markerCache.delete(key);\r\n }\r\n }\r\n\r\n // Add or update markers\r\n for (const item of items) {\r\n const coords = safeLatLon(item.marker.location);\r\n if (!coords) continue;\r\n\r\n const existing = this.markerCache.get(item.key);\r\n\r\n if (existing) {\r\n // Update existing marker position if needed\r\n try {\r\n this.updateMarkerPosition(existing.marker, coords);\r\n } catch {\r\n // If update fails, remove and recreate\r\n this.removeMarkerFromMap(existing.marker);\r\n this.markerCache.delete(item.key);\r\n this.createAndAddMarker(item, coords);\r\n }\r\n } else {\r\n // Check if there's a marker for the same property with a different key (styling change)\r\n const markerId = item.marker.tripadvisor_id;\r\n let existingEntry: MarkerEntry<TMarker> | undefined;\r\n let existingKey: string | undefined;\r\n\r\n for (const [key, entry] of this.markerCache.entries()) {\r\n if (\r\n extractMarkerIdFromKey(key) === markerId &&\r\n entry.kind === item.kind\r\n ) {\r\n existingEntry = entry;\r\n existingKey = key;\r\n break;\r\n }\r\n }\r\n\r\n if (existingEntry && existingKey) {\r\n // Same marker, different state - update styles instead of recreating\r\n const isPrimaryType = item.marker.type === this.primaryType;\r\n const isSelected =\r\n this.selectedMarkerId === item.marker.tripadvisor_id;\r\n const isAccommodation = item.marker.type === \"Accommodation\";\r\n const isPending =\r\n item.kind === \"primary\"\r\n ? isAccommodation && !item.marker.pricing?.offer?.displayPrice\r\n : isAccommodation &&\r\n item.marker.pricing?.offer?.availability !== \"available\";\r\n\r\n const element = this.getMarkerElement(existingEntry.marker);\r\n if (element) {\r\n if (item.kind === \"primary\") {\r\n updatePrimaryMarkerElement(\r\n element,\r\n isPrimaryType,\r\n isSelected,\r\n isPending\r\n );\r\n } else {\r\n updateDotMarkerElement(\r\n element,\r\n isPrimaryType,\r\n isSelected,\r\n isPending\r\n );\r\n }\r\n }\r\n\r\n // Update zIndex if supported\r\n this.updateMarkerZIndex(\r\n existingEntry.marker,\r\n item,\r\n isPrimaryType,\r\n isSelected\r\n );\r\n\r\n // Update cache with new key\r\n this.markerCache.delete(existingKey);\r\n this.markerCache.set(item.key, existingEntry);\r\n\r\n // Update position\r\n try {\r\n this.updateMarkerPosition(existingEntry.marker, coords);\r\n } catch {\r\n // If update fails, ignore\r\n }\r\n } else {\r\n // Create new marker\r\n this.createAndAddMarker(item, coords);\r\n }\r\n }\r\n }\r\n }\r\n\r\n destroy() {\r\n for (const entry of this.markerCache.values()) {\r\n this.removeMarkerFromMap(entry.marker);\r\n }\r\n this.markerCache.clear();\r\n }\r\n\r\n protected createAndAddMarker(\r\n item: ClusterDisplayItem,\r\n coords: { lon: number; lat: number }\r\n ) {\r\n const element =\r\n item.kind === \"primary\"\r\n ? createPrimaryMarkerElement(\r\n item,\r\n this.primaryType,\r\n this.selectedMarkerId,\r\n this.onMarkerClick\r\n )\r\n : createDotMarkerElement(\r\n item,\r\n this.primaryType,\r\n this.selectedMarkerId,\r\n this.onMarkerClick\r\n );\r\n\r\n if (!element) return;\r\n\r\n const isPrimaryType = item.marker.type === this.primaryType;\r\n const isSelected = this.selectedMarkerId === item.marker.tripadvisor_id;\r\n\r\n try {\r\n const marker = this.createMarker(\r\n element,\r\n coords,\r\n item,\r\n isPrimaryType,\r\n isSelected\r\n );\r\n if (marker) {\r\n this.markerCache.set(item.key, {\r\n key: item.key,\r\n marker,\r\n kind: item.kind,\r\n parentId: item.kind === \"dot\" ? item.parentId : undefined,\r\n });\r\n }\r\n } catch (error) {\r\n console.error(\"Error creating marker\", error);\r\n }\r\n }\r\n\r\n // Abstract methods to be implemented by subclasses\r\n protected abstract createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): TMarker | null;\r\n\r\n protected abstract removeMarkerFromMap(marker: TMarker): void;\r\n\r\n protected abstract updateMarkerPosition(\r\n marker: TMarker,\r\n coords: { lon: number; lat: number }\r\n ): void;\r\n\r\n protected abstract getMarkerElement(marker: TMarker): HTMLElement | null;\r\n\r\n protected updateMarkerZIndex(\r\n marker: TMarker,\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): void {\r\n // Default implementation does nothing (override in subclasses that support zIndex)\r\n }\r\n}\r\n\r\nfunction safeLatLon(location?: { lon?: number; lat?: number }) {\r\n if (typeof location?.lon !== \"number\" || typeof location?.lat !== \"number\") {\r\n return null;\r\n }\r\n if (Number.isNaN(location.lon) || Number.isNaN(location.lat)) {\r\n return null;\r\n }\r\n return { lon: location.lon, lat: location.lat };\r\n}\r\n","import type { Property } from \"../../types\";\r\nimport { BaseMarkerManager } from \"../markermanager\";\r\nimport { ClusterDisplayItem } from \"../../utils/clustering\";\r\n\r\nexport type MapLibreMarkerHandle = {\r\n setLngLat(lngLat: [number, number]): MapLibreMarkerHandle;\r\n addTo(map: any): MapLibreMarkerHandle;\r\n remove(): void;\r\n getElement(): HTMLElement;\r\n};\r\n\r\nexport type MapLibreNamespace = {\r\n Marker: new (options?: {\r\n element?: HTMLElement;\r\n anchor?: string;\r\n }) => MapLibreMarkerHandle;\r\n};\r\n\r\ntype MapLibreMarkerManagerOptions = {\r\n mapInstance: any;\r\n maplibregl: MapLibreNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n};\r\n\r\nexport class MapLibreMarkerManager extends BaseMarkerManager<MapLibreMarkerHandle> {\r\n private readonly MarkerCtor?: MapLibreNamespace[\"Marker\"];\r\n\r\n constructor(options: MapLibreMarkerManagerOptions) {\r\n super(options.mapInstance, options.onMarkerClick);\r\n this.MarkerCtor = options.maplibregl?.Marker;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (!this.MarkerCtor) {\r\n return;\r\n }\r\n super.render(items, primaryType, selectedMarkerId);\r\n }\r\n\r\n protected createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem\r\n ): MapLibreMarkerHandle | null {\r\n if (!this.MarkerCtor) return null;\r\n\r\n return new this.MarkerCtor({\r\n element,\r\n anchor: item.kind === \"primary\" ? \"bottom\" : \"center\",\r\n })\r\n .setLngLat([coords.lon, coords.lat])\r\n .addTo(this.mapInstance);\r\n }\r\n\r\n protected removeMarkerFromMap(marker: MapLibreMarkerHandle): void {\r\n try {\r\n marker.remove();\r\n } catch {\r\n // swallow removal errors\r\n }\r\n }\r\n\r\n protected updateMarkerPosition(\r\n marker: MapLibreMarkerHandle,\r\n coords: { lon: number; lat: number }\r\n ): void {\r\n marker.setLngLat([coords.lon, coords.lat]);\r\n }\r\n\r\n protected getMarkerElement(marker: MapLibreMarkerHandle): HTMLElement | null {\r\n return marker.getElement();\r\n }\r\n}\r\n","import type { Property } from \"../../types\";\r\nimport { BaseMarkerManager } from \"../markermanager\";\r\nimport { ClusterDisplayItem } from \"../../utils/clustering\";\r\n\r\nexport type GoogleMapsMarkerHandle = any; // google.maps.marker.AdvancedMarkerElement\r\n\r\nexport type GoogleMapsNamespace = any; // typeof google.maps\r\n\r\ntype GoogleMapsMarkerManagerOptions = {\r\n mapInstance: any; // google.maps.Map\r\n google: GoogleMapsNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n};\r\n\r\nexport class GoogleMapsMarkerManager extends BaseMarkerManager<GoogleMapsMarkerHandle> {\r\n private readonly google: GoogleMapsNamespace;\r\n\r\n constructor(options: GoogleMapsMarkerManagerOptions) {\r\n super(options.mapInstance, options.onMarkerClick);\r\n this.google = options.google;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (!this.google?.marker?.AdvancedMarkerElement) {\r\n console.warn(\"AdvancedMarkerElement not available\");\r\n return;\r\n }\r\n super.render(items, primaryType, selectedMarkerId);\r\n }\r\n\r\n protected createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): GoogleMapsMarkerHandle | null {\r\n if (!this.google?.marker?.AdvancedMarkerElement) return null;\r\n\r\n const zIndex =\r\n item.kind === \"primary\"\r\n ? isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 12\r\n : 11\r\n : isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 3\r\n : 1;\r\n\r\n return new this.google.marker.AdvancedMarkerElement({\r\n map: this.mapInstance,\r\n position: { lat: coords.lat, lng: coords.lon },\r\n content: element,\r\n zIndex,\r\n });\r\n }\r\n\r\n protected removeMarkerFromMap(marker: GoogleMapsMarkerHandle): void {\r\n try {\r\n marker.map = null;\r\n } catch (error) {\r\n console.error(\"Error removing marker\", error);\r\n }\r\n }\r\n\r\n protected updateMarkerPosition(\r\n marker: GoogleMapsMarkerHandle,\r\n coords: { lon: number; lat: number }\r\n ): void {\r\n marker.position = { lat: coords.lat, lng: coords.lon };\r\n }\r\n\r\n protected getMarkerElement(\r\n marker: GoogleMapsMarkerHandle\r\n ): HTMLElement | null {\r\n const element = marker.content;\r\n return element instanceof HTMLElement ? element : null;\r\n }\r\n\r\n protected updateMarkerZIndex(\r\n marker: GoogleMapsMarkerHandle,\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): void {\r\n const zIndex =\r\n item.kind === \"primary\"\r\n ? isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 12\r\n : 11\r\n : isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 3\r\n : 1;\r\n marker.zIndex = zIndex;\r\n }\r\n}\r\n","import type { Property } from \"../../types\";\r\nimport { BaseMarkerManager } from \"../markermanager\";\r\nimport { ClusterDisplayItem } from \"../../utils/clustering\";\r\n\r\nexport type MapboxMarkerHandle = {\r\n setLngLat(lngLat: [number, number]): MapboxMarkerHandle;\r\n addTo(map: any): MapboxMarkerHandle;\r\n remove(): void;\r\n getElement(): HTMLElement;\r\n};\r\n\r\nexport type MapboxNamespace = {\r\n Marker: new (options?: {\r\n element?: HTMLElement;\r\n anchor?: string;\r\n }) => MapboxMarkerHandle;\r\n};\r\n\r\ntype MapboxMarkerManagerOptions = {\r\n mapInstance: any;\r\n mapboxgl: MapboxNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n};\r\n\r\nexport class MapboxMarkerManager extends BaseMarkerManager<MapboxMarkerHandle> {\r\n private readonly MarkerCtor?: MapboxNamespace[\"Marker\"];\r\n\r\n constructor(options: MapboxMarkerManagerOptions) {\r\n super(options.mapInstance, options.onMarkerClick);\r\n this.MarkerCtor = options.mapboxgl?.Marker;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (!this.MarkerCtor) {\r\n return;\r\n }\r\n super.render(items, primaryType, selectedMarkerId);\r\n }\r\n\r\n protected createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem\r\n ): MapboxMarkerHandle | null {\r\n if (!this.MarkerCtor) return null;\r\n\r\n return new this.MarkerCtor({\r\n element,\r\n anchor: item.kind === \"primary\" ? \"bottom\" : \"center\",\r\n })\r\n .setLngLat([coords.lon, coords.lat])\r\n .addTo(this.mapInstance);\r\n }\r\n\r\n protected removeMarkerFromMap(marker: MapboxMarkerHandle): void {\r\n try {\r\n marker.remove();\r\n } catch {\r\n // swallow removal errors\r\n }\r\n }\r\n\r\n protected updateMarkerPosition(\r\n marker: MapboxMarkerHandle,\r\n coords: { lon: number; lat: number }\r\n ): void {\r\n marker.setLngLat([coords.lon, coords.lat]);\r\n }\r\n\r\n protected getMarkerElement(marker: MapboxMarkerHandle): HTMLElement | null {\r\n return marker.getElement();\r\n }\r\n}\r\n","export {\r\n MapLibreMarkerManager,\r\n type MapLibreMarkerHandle,\r\n type MapLibreNamespace,\r\n} from \"./maplibre/markermanager\";\r\n\r\nexport {\r\n GoogleMapsMarkerManager,\r\n type GoogleMapsMarkerHandle,\r\n type GoogleMapsNamespace,\r\n} from \"./google/markermanager\";\r\n\r\nexport {\r\n MapboxMarkerManager,\r\n type MapboxMarkerHandle,\r\n type MapboxNamespace,\r\n} from \"./mapbox/markermanager\";\r\n\r\n/**\r\n * Abstract base class for map adapters supporting different map libraries\r\n */\r\nexport abstract class MapAdapter {\r\n protected map: any;\r\n\r\n constructor(map: any) {\r\n this.map = map;\r\n }\r\n\r\n /**\r\n * Get the underlying map instance\r\n * @returns {any} The native map instance\r\n */\r\n getMap(): any {\r\n return this.map;\r\n }\r\n\r\n /**\r\n * Initialize the adapter with platform-specific configuration\r\n * @param {any} options Platform-specific initialization options\r\n * @returns {any} The marker manager instance\r\n */\r\n abstract initialize(options: any): any;\r\n\r\n /**\r\n * Get the marker manager instance\r\n * @returns {any} The marker manager\r\n */\r\n abstract getMarkerManager(): any;\r\n\r\n /**\r\n * Clean up event listeners and resources\r\n */\r\n abstract cleanup(): void;\r\n\r\n /**\r\n * Get the map container element\r\n * @returns {HTMLElement | null} The map container DOM element\r\n */\r\n abstract getContainer(): HTMLElement | null;\r\n\r\n /**\r\n * Set up impression tracking when map becomes visible\r\n * @param {() => void} onImpression Callback to invoke when map is visible\r\n */\r\n setupImpressionTracking(onImpression: () => void): void {\r\n if (typeof window === \"undefined\" || !window.IntersectionObserver) {\r\n return;\r\n }\r\n\r\n const container = this.getContainer();\r\n if (!container) {\r\n return;\r\n }\r\n\r\n const observer = new IntersectionObserver(\r\n (entries) => {\r\n entries.forEach((entry) => {\r\n if (entry.isIntersecting) {\r\n onImpression();\r\n observer.disconnect();\r\n }\r\n });\r\n },\r\n { threshold: 0.1 }\r\n );\r\n\r\n observer.observe(container);\r\n\r\n // Store cleanup function\r\n const cleanup = () => observer.disconnect();\r\n const originalCleanup = this.cleanup.bind(this);\r\n this.cleanup = () => {\r\n cleanup();\r\n originalCleanup();\r\n };\r\n }\r\n\r\n /**\r\n * Get the current center coordinates of the map\r\n * @returns {{ lng: number; lat: number }} [longitude, latitude]\r\n */\r\n abstract getCenter(): { lng: number; lat: number };\r\n\r\n /**\r\n * Get the current zoom level of the map\r\n * @returns {number} Current zoom level\r\n */\r\n abstract getZoom(): number;\r\n\r\n /**\r\n * Get the current bearing (rotation) of the map\r\n * @returns {number} Bearing in degrees\r\n */\r\n abstract getBearing(): number;\r\n\r\n /**\r\n * Get the current pitch (tilt) of the map\r\n * @returns {number} Pitch in degrees\r\n */\r\n abstract getPitch(): number;\r\n\r\n /**\r\n * Get the current bounds of the map viewport\r\n * @returns {MapBounds} Map bounds with southwest and northeast corners\r\n */\r\n abstract getMapBounds(): MapBounds;\r\n\r\n /**\r\n * Project a geographical coordinate to screen space\r\n * @param {[number, number]} lngLat [longitude, latitude]\r\n * @returns {{ x: number; y: number }} Screen coordinates\r\n */\r\n abstract project(lngLat: [number, number]): { x: number; y: number };\r\n}\r\n\r\nexport type LngLat = { lng: number; lat: number };\r\n\r\nexport type MapBounds = {\r\n sw: { lat: number; lng: number };\r\n ne: { lat: number; lng: number };\r\n};\r\n","import { MapAdapter, type LngLat, type MapBounds } from \"../index\";\nimport { MapLibreMarkerManager, type MapLibreNamespace } from \"./markermanager\";\nimport type { Property } from \"../../types\";\n\nexport class MapLibreAdapter extends MapAdapter {\n private markerManager?: MapLibreMarkerManager;\n private cleanupFns: Array<() => void> = [];\n\n constructor(map: any) {\n super(map);\n }\n\n initialize(options: {\n maplibregl: MapLibreNamespace;\n onMarkerClick?: (marker: Property) => void;\n onRefresh?: () => void;\n onMapMoveEnd?: (bounds: MapBounds) => void;\n }) {\n this.markerManager = new MapLibreMarkerManager({\n mapInstance: this.map,\n maplibregl: options.maplibregl,\n onMarkerClick: options.onMarkerClick,\n });\n\n if (options.onRefresh) {\n this.attachEventListeners(options.onRefresh);\n }\n\n if (options.onMapMoveEnd) {\n this.attachBoundsTracking(options.onMapMoveEnd);\n }\n\n return this.markerManager;\n }\n\n private attachBoundsTracking(onMapMoveEnd: (bounds: MapBounds) => void) {\n if (!this.map || typeof this.map.on !== \"function\") {\n return;\n }\n\n const handleMoveEnd = () => {\n const bounds = this.getMapBounds();\n onMapMoveEnd(bounds);\n };\n\n // Set initial bounds on load\n const handleLoad = () => {\n const bounds = this.getMapBounds();\n onMapMoveEnd(bounds);\n };\n\n if (this.map.loaded && this.map.loaded()) {\n handleLoad();\n } else {\n this.map.once(\"load\", handleLoad);\n this.cleanupFns.push(() => {\n if (typeof this.map.off === \"function\") {\n this.map.off(\"load\", handleLoad);\n }\n });\n }\n\n this.map.on(\"moveend\", handleMoveEnd);\n this.cleanupFns.push(() => {\n if (typeof this.map.off === \"function\") {\n this.map.off(\"moveend\", handleMoveEnd);\n }\n });\n }\n\n private attachEventListeners(onRefresh: () => void) {\n if (!this.map || typeof this.map.on !== \"function\") {\n return;\n }\n const events = [\"move\", \"zoom\", \"dragend\", \"pitch\", \"rotate\"];\n events.forEach((eventName) => {\n this.map.on(eventName, onRefresh);\n this.cleanupFns.push(() => {\n if (typeof this.map.off === \"function\") {\n this.map.off(eventName, onRefresh);\n }\n });\n });\n }\n\n getMarkerManager() {\n return this.markerManager;\n }\n\n getContainer(): HTMLElement | null {\n return this.map?.getContainer?.() || null;\n }\n\n cleanup() {\n for (const cleanup of this.cleanupFns) {\n try {\n cleanup();\n } catch {\n // ignore\n }\n }\n this.cleanupFns.length = 0;\n }\n\n getMap(): any {\n return this.map;\n }\n\n getCenter(): LngLat {\n const center = this.map.getCenter();\n return { lng: center.lng, lat: center.lat };\n }\n\n getZoom(): number {\n return this.map.getZoom();\n }\n\n getBearing(): number {\n return this.map.getBearing();\n }\n\n getPitch(): number {\n return this.map.getPitch();\n }\n\n getMapBounds(): MapBounds {\n const bounds = this.map.getBounds();\n const sw = bounds.getSouthWest();\n const ne = bounds.getNorthEast();\n return {\n sw: { lat: sw.lat, lng: sw.lng },\n ne: { lat: ne.lat, lng: ne.lng },\n };\n }\n\n project(lngLat: [number, number]) {\n return this.map.project({ lng: lngLat[0], lat: lngLat[1] });\n }\n\n on(event: string, handler: (...args: any[]) => void): void {\n this.map.on(event, handler);\n }\n\n off(event: string, handler: (...args: any[]) => void): void {\n this.map.off(event, handler);\n }\n\n resize(): void {\n this.map.resize();\n }\n\n remove(): void {\n this.cleanup();\n this.map.remove();\n }\n}\n","import { MapAdapter, type LngLat, type MapBounds } from \"../index\";\r\nimport {\r\n GoogleMapsMarkerManager,\r\n type GoogleMapsNamespace,\r\n} from \"./markermanager\";\r\nimport type { Property } from \"../../types\";\r\n\r\nexport class GoogleMapsAdapter extends MapAdapter {\r\n private overlayView: any;\r\n private markerManager?: GoogleMapsMarkerManager;\r\n private cleanupFns: Array<() => void> = [];\r\n\r\n constructor(map: any) {\r\n super(map);\r\n this.initializeOverlayView();\r\n }\r\n\r\n initialize(options: {\r\n google: GoogleMapsNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n onRefresh?: () => void;\r\n onMapMoveEnd?: (bounds: MapBounds) => void;\r\n }) {\r\n this.markerManager = new GoogleMapsMarkerManager({\r\n mapInstance: this.map,\r\n google: options.google,\r\n onMarkerClick: options.onMarkerClick,\r\n });\r\n\r\n if (options.onRefresh) {\r\n this.attachEventListeners(options.onRefresh);\r\n }\r\n\r\n if (options.onMapMoveEnd) {\r\n this.attachBoundsTracking(options.onMapMoveEnd, options.google);\r\n }\r\n\r\n return this.markerManager;\r\n }\r\n\r\n private attachBoundsTracking(\r\n onMapMoveEnd: (bounds: MapBounds) => void,\r\n google: GoogleMapsNamespace\r\n ) {\r\n if (!this.map) {\r\n return;\r\n }\r\n\r\n const handleIdle = () => {\r\n const bounds = this.getMapBounds();\r\n onMapMoveEnd(bounds);\r\n };\r\n\r\n // Set initial bounds\r\n handleIdle();\r\n\r\n const listener = google.event.addListener(this.map, \"idle\", handleIdle);\r\n this.cleanupFns.push(() => {\r\n google.event.removeListener(listener);\r\n });\r\n }\r\n\r\n private attachEventListeners(onRefresh: () => void) {\r\n const events = [\r\n \"center_changed\",\r\n \"zoom_changed\",\r\n \"drag\",\r\n \"heading_changed\",\r\n \"tilt_changed\",\r\n ];\r\n const listeners: any[] = [];\r\n\r\n events.forEach((eventName) => {\r\n const listener = this.map.addListener(eventName, onRefresh);\r\n listeners.push(listener);\r\n });\r\n\r\n this.cleanupFns.push(() => {\r\n listeners.forEach((listener) => {\r\n try {\r\n listener.remove();\r\n } catch {\r\n // ignore\r\n }\r\n });\r\n });\r\n }\r\n\r\n getMarkerManager() {\r\n return this.markerManager;\r\n }\r\n\r\n getContainer(): HTMLElement | null {\r\n return this.map?.getDiv?.() || null;\r\n }\r\n\r\n cleanup() {\r\n for (const cleanup of this.cleanupFns) {\r\n try {\r\n cleanup();\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n this.cleanupFns.length = 0;\r\n }\r\n\r\n private initializeOverlayView() {\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (!googleMaps) return;\r\n\r\n // Create a custom overlay to access the projection\r\n const OverlayView = googleMaps.OverlayView;\r\n if (!OverlayView) return;\r\n\r\n this.overlayView = new OverlayView();\r\n this.overlayView.draw = function () {}; // Required method\r\n this.overlayView.setMap(this.map);\r\n }\r\n\r\n getMap(): any {\r\n return this.map;\r\n }\r\n\r\n getCenter(): LngLat {\r\n const center = this.map.getCenter();\r\n if (!center) {\r\n return { lng: 0, lat: 0 };\r\n }\r\n return { lng: center.lng(), lat: center.lat() };\r\n }\r\n\r\n getZoom(): number {\r\n return this.map.getZoom() ?? 0;\r\n }\r\n\r\n getBearing(): number {\r\n return this.map.getHeading() ?? 0;\r\n }\r\n\r\n getPitch(): number {\r\n return this.map.getTilt() ?? 0;\r\n }\r\n\r\n getMapBounds(): MapBounds {\r\n const bounds = this.map.getBounds();\r\n if (!bounds) {\r\n return {\r\n sw: { lat: 0, lng: 0 },\r\n ne: { lat: 0, lng: 0 },\r\n };\r\n }\r\n const sw = bounds.getSouthWest();\r\n const ne = bounds.getNorthEast();\r\n return {\r\n sw: { lat: sw.lat(), lng: sw.lng() },\r\n ne: { lat: ne.lat(), lng: ne.lng() },\r\n };\r\n }\r\n\r\n project(lngLat: [number, number]): { x: number; y: number } {\r\n if (!this.overlayView) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n const projection = this.overlayView.getProjection();\r\n if (!projection) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (!googleMaps) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n const latLng = new googleMaps.LatLng(lngLat[1], lngLat[0]);\r\n const point = projection.fromLatLngToContainerPixel(latLng);\r\n\r\n if (!point) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n return {\r\n x: point.x,\r\n y: point.y,\r\n };\r\n }\r\n\r\n on(event: string, handler: (...args: any[]) => void): void {\r\n this.map.addListener(event, handler);\r\n }\r\n\r\n off(event: string, handler: (...args: any[]) => void): void {\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (googleMaps?.event) {\r\n googleMaps.event.clearListeners(this.map, event);\r\n }\r\n }\r\n\r\n resize(): void {\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (googleMaps?.event) {\r\n googleMaps.event.trigger(this.map, \"resize\");\r\n }\r\n }\r\n\r\n remove(): void {\r\n this.cleanup();\r\n // Clean up overlay view\r\n if (this.overlayView) {\r\n this.overlayView.setMap(null);\r\n this.overlayView = null;\r\n }\r\n // Google Maps doesn't have a remove method\r\n // Users should handle cleanup themselves\r\n }\r\n}\r\n","import { MapAdapter, type LngLat, type MapBounds } from \"../index\";\r\nimport { MapboxMarkerManager, type MapboxNamespace } from \"./markermanager\";\r\nimport type { Property } from \"../../types\";\r\n\r\nexport class MapboxAdapter extends MapAdapter {\r\n private markerManager?: MapboxMarkerManager;\r\n private cleanupFns: Array<() => void> = [];\r\n\r\n constructor(map: any) {\r\n super(map);\r\n }\r\n\r\n initialize(options: {\r\n mapboxgl: MapboxNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n onRefresh?: () => void;\r\n onMapMoveEnd?: (bounds: MapBounds) => void;\r\n }) {\r\n this.markerManager = new MapboxMarkerManager({\r\n mapInstance: this.map,\r\n mapboxgl: options.mapboxgl,\r\n onMarkerClick: options.onMarkerClick,\r\n });\r\n\r\n if (options.onRefresh) {\r\n this.attachEventListeners(options.onRefresh);\r\n }\r\n\r\n if (options.onMapMoveEnd) {\r\n this.attachBoundsTracking(options.onMapMoveEnd);\r\n }\r\n\r\n return this.markerManager;\r\n }\r\n\r\n private attachBoundsTracking(onMapMoveEnd: (bounds: MapBounds) => void) {\r\n if (!this.map || typeof this.map.on !== \"function\") {\r\n return;\r\n }\r\n\r\n const handleMoveEnd = () => {\r\n const bounds = this.getMapBounds();\r\n onMapMoveEnd(bounds);\r\n };\r\n\r\n // Set initial bounds on load\r\n const handleLoad = () => {\r\n const bounds = this.getMapBounds();\r\n // Initialize tempBounds without triggering pendingBounds\r\n onMapMoveEnd(bounds);\r\n };\r\n\r\n if (this.map.loaded && this.map.loaded()) {\r\n handleLoad();\r\n } else {\r\n this.map.once(\"load\", handleLoad);\r\n this.cleanupFns.push(() => {\r\n if (typeof this.map.off === \"function\") {\r\n this.map.off(\"load\", handleLoad);\r\n }\r\n });\r\n }\r\n\r\n this.map.on(\"moveend\", handleMoveEnd);\r\n this.cleanupFns.push(() => {\r\n if (typeof this.map.off === \"function\") {\r\n this.map.off(\"moveend\", handleMoveEnd);\r\n }\r\n });\r\n }\r\n\r\n private attachEventListeners(onRefresh: () => void) {\r\n if (!this.map || typeof this.map.on !== \"function\") {\r\n return;\r\n }\r\n const events = [\"move\", \"zoom\", \"dragend\", \"pitch\", \"rotate\"];\r\n events.forEach((eventName) => {\r\n this.map.on(eventName, onRefresh);\r\n this.cleanupFns.push(() => {\r\n if (typeof this.map.off === \"function\") {\r\n this.map.off(eventName, onRefresh);\r\n }\r\n });\r\n });\r\n }\r\n\r\n getMarkerManager() {\r\n return this.markerManager;\r\n }\r\n\r\n getContainer(): HTMLElement | null {\r\n return this.map?.getContainer?.() || null;\r\n }\r\n\r\n cleanup() {\r\n for (const cleanup of this.cleanupFns) {\r\n try {\r\n cleanup();\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n this.cleanupFns.length = 0;\r\n }\r\n\r\n getMap(): any {\r\n return this.map;\r\n }\r\n\r\n getCenter(): LngLat {\r\n const center = this.map.getCenter();\r\n return { lng: center.lng, lat: center.lat };\r\n }\r\n\r\n getZoom(): number {\r\n return this.map.getZoom();\r\n }\r\n\r\n getBearing(): number {\r\n return this.map.getBearing();\r\n }\r\n\r\n getPitch(): number {\r\n return this.map.getPitch();\r\n }\r\n\r\n getMapBounds(): MapBounds {\r\n const bounds = this.map.getBounds();\r\n const sw = bounds.getSouthWest();\r\n const ne = bounds.getNorthEast();\r\n return {\r\n sw: { lat: sw.lat, lng: sw.lng },\r\n ne: { lat: ne.lat, lng: ne.lng },\r\n };\r\n }\r\n\r\n project(lngLat: [number, number]) {\r\n return this.map.project({ lng: lngLat[0], lat: lngLat[1] });\r\n }\r\n\r\n on(event: string, handler: (...args: any[]) => void): void {\r\n this.map.on(event, handler);\r\n }\r\n\r\n off(event: string, handler: (...args: any[]) => void): void {\r\n this.map.off(event, handler);\r\n }\r\n\r\n resize(): void {\r\n this.map.resize();\r\n }\r\n\r\n remove(): void {\r\n this.cleanup();\r\n this.map.remove();\r\n }\r\n}\r\n","import { MapAdapter } from \"../adapters\";\r\nimport { Property, PropertyType } from \"../types\";\r\n\r\nexport type ClusterDisplayItem =\r\n | {\r\n kind: \"primary\";\r\n marker: Property;\r\n key: string;\r\n }\r\n | {\r\n kind: \"dot\";\r\n marker: Property;\r\n key: string;\r\n parentId: number;\r\n };\r\n\r\nexport type ViewStateSnapshot = {\r\n longitude: number;\r\n latitude: number;\r\n zoom: number;\r\n bearing: number;\r\n pitch: number;\r\n};\r\n\r\nexport type ClusterParams = {\r\n primaryType: PropertyType;\r\n markers: Property[];\r\n map: MapAdapter | null;\r\n selectedMarkerId: number | null;\r\n zoom: number;\r\n collisionThresholdPx?: number;\r\n dotCollisionThresholdPx?: number;\r\n};\r\n\r\nexport type ProjectedMarker = {\r\n marker: Property;\r\n index: number;\r\n x: number;\r\n y: number;\r\n};\r\n\r\nexport function extractViewState(mapInstance: MapAdapter): ViewStateSnapshot {\r\n const center = mapInstance.getCenter();\r\n return {\r\n longitude: center.lng,\r\n latitude: center.lat,\r\n zoom: mapInstance.getZoom(),\r\n bearing: mapInstance.getBearing(),\r\n pitch: mapInstance.getPitch(),\r\n };\r\n}\r\n\r\nconst COLLISION_THRESHOLD_PX_ZOOM_BREAKPOINTS: Array<{\r\n zoom: number;\r\n threshold: number;\r\n}> = [\r\n { zoom: 6, threshold: 120 },\r\n { zoom: 8, threshold: 108 },\r\n { zoom: 10, threshold: 92 },\r\n { zoom: 12, threshold: 80 },\r\n { zoom: 14, threshold: 68 },\r\n { zoom: 16, threshold: 56 },\r\n];\r\n\r\nfunction resolveCollisionThreshold(zoom: number) {\r\n for (const breakpoint of COLLISION_THRESHOLD_PX_ZOOM_BREAKPOINTS) {\r\n if (zoom <= breakpoint.zoom) {\r\n return breakpoint.threshold;\r\n }\r\n }\r\n return 48;\r\n}\r\n\r\nexport function clusterMarkers({\r\n primaryType,\r\n markers,\r\n map,\r\n selectedMarkerId,\r\n zoom,\r\n collisionThresholdPx,\r\n dotCollisionThresholdPx,\r\n}: ClusterParams): ClusterDisplayItem[] {\r\n if (!markers.length) return [];\r\n if (!map) {\r\n return markers.map((marker) => ({\r\n kind: \"primary\" as const,\r\n marker,\r\n key: `primary-${marker.tripadvisor_id}`,\r\n }));\r\n }\r\n\r\n const projected: ProjectedMarker[] = markers\r\n .map((marker, index) => {\r\n const location = marker.location as { lon?: number; lat?: number };\r\n if (\r\n typeof location?.lon !== \"number\" ||\r\n typeof location?.lat !== \"number\"\r\n ) {\r\n return null;\r\n }\r\n const { x, y } = map.project([location.lon, location.lat]);\r\n return { marker, index, x, y };\r\n })\r\n .filter((value): value is ProjectedMarker => Boolean(value));\r\n\r\n if (!projected.length) {\r\n return [];\r\n }\r\n\r\n const threshold = resolveCollisionThreshold(zoom);\r\n const dotThreshold = resolveDotCollisionThreshold(zoom);\r\n const parent = projected.map((_, idx) => idx);\r\n\r\n const find = (i: number): number => {\r\n if (parent[i] === i) return i;\r\n parent[i] = find(parent[i]);\r\n return parent[i];\r\n };\r\n\r\n const union = (a: number, b: number) => {\r\n const rootA = find(a);\r\n const rootB = find(b);\r\n if (rootA === rootB) return;\r\n parent[rootB] = rootA;\r\n };\r\n\r\n for (let i = 0; i < projected.length; i += 1) {\r\n for (let j = i + 1; j < projected.length; j += 1) {\r\n const dx = projected[i].x - projected[j].x;\r\n const dy = projected[i].y - projected[j].y;\r\n if (Math.hypot(dx, dy) <= threshold) {\r\n union(i, j);\r\n }\r\n }\r\n }\r\n\r\n const groups = new Map<number, ProjectedMarker[]>();\r\n for (const item of projected) {\r\n const root = find(item.index);\r\n const group = groups.get(root);\r\n if (group) {\r\n group.push(item);\r\n } else {\r\n groups.set(root, [item]);\r\n }\r\n }\r\n\r\n const clustered: ClusterDisplayItem[] = [];\r\n\r\n groups.forEach((groupItems) => {\r\n if (groupItems.length === 1) {\r\n const [{ marker }] = groupItems;\r\n const isPrimary = marker.type === primaryType;\r\n const isSelected = selectedMarkerId === marker.tripadvisor_id;\r\n clustered.push({\r\n kind: \"primary\",\r\n marker,\r\n key: `primary-${marker.tripadvisor_id}-p${isPrimary ? 1 : 0}-s${\r\n isSelected ? 1 : 0\r\n }-${marker.pricing?.availability}`,\r\n });\r\n return;\r\n }\r\n\r\n const sorted = [...groupItems].sort((a, b) =>\r\n compareMarkers(b.marker, a.marker, primaryType)\r\n );\r\n const [primary, ...rest] = sorted;\r\n const isPrimaryPrimary = primary.marker.type === primaryType;\r\n const isSelectedPrimary =\r\n selectedMarkerId === primary.marker.tripadvisor_id;\r\n clustered.push({\r\n kind: \"primary\",\r\n marker: primary.marker,\r\n key: `primary-${primary.marker.tripadvisor_id}-p${\r\n isPrimaryPrimary ? 1 : 0\r\n }-s${isSelectedPrimary ? 1 : 0}-${primary.marker.pricing?.availability}`,\r\n });\r\n\r\n if (!rest.length) return;\r\n\r\n const dotCandidates: ProjectedMarker[] = [];\r\n const remainder: ProjectedMarker[] = [];\r\n\r\n rest.forEach((item) => {\r\n if (selectedMarkerId && item.marker.tripadvisor_id === selectedMarkerId) {\r\n const isPrimary = item.marker.type === primaryType;\r\n clustered.push({\r\n kind: \"primary\",\r\n marker: item.marker,\r\n key: `primary-${item.marker.tripadvisor_id}-p${\r\n isPrimary ? 1 : 0\r\n }-s1-${item.marker.pricing?.availability}`,\r\n });\r\n return;\r\n }\r\n\r\n if (distancePx(primary, item) <= dotThreshold) {\r\n dotCandidates.push(item);\r\n } else {\r\n remainder.push(item);\r\n }\r\n });\r\n\r\n dotCandidates.forEach((item) => {\r\n const isPrimary = item.marker.type === primaryType;\r\n clustered.push({\r\n kind: \"dot\",\r\n marker: item.marker,\r\n key: `dot-${item.marker.tripadvisor_id}-p${isPrimary ? 1 : 0}-s0-${\r\n item.marker.pricing?.availability\r\n }`,\r\n parentId: primary.marker.tripadvisor_id,\r\n });\r\n });\r\n\r\n if (remainder.length) {\r\n const followUp = clusterMarkers({\r\n markers: remainder.map((item) => item.marker),\r\n map,\r\n selectedMarkerId,\r\n zoom,\r\n primaryType,\r\n collisionThresholdPx,\r\n dotCollisionThresholdPx,\r\n });\r\n clustered.push(...followUp);\r\n }\r\n });\r\n\r\n return clustered;\r\n}\r\n\r\nfunction distancePx(a: ProjectedMarker, b: ProjectedMarker) {\r\n return Math.hypot(a.x - b.x, a.y - b.y);\r\n}\r\n\r\nfunction resolveDotCollisionThreshold(zoom: number) {\r\n const base = resolveCollisionThreshold(zoom);\r\n return Math.max(48, base);\r\n}\r\n\r\nfunction compareMarkers(a: Property, b: Property, primaryType: PropertyType) {\r\n const aIsPrimary = a.type === primaryType;\r\n const bIsPrimary = b.type === primaryType;\r\n if (aIsPrimary && !bIsPrimary) return 1;\r\n if (!aIsPrimary && bIsPrimary) return -1;\r\n\r\n const ratingDiff = resolveRating(a) - resolveRating(b);\r\n if (ratingDiff !== 0) return ratingDiff;\r\n\r\n const priceDiff = resolvePrice(a) - resolvePrice(b);\r\n if (priceDiff !== 0) return priceDiff;\r\n\r\n const reviewsDiff = (a.reviews ?? 0) - (b.reviews ?? 0);\r\n if (reviewsDiff !== 0) return reviewsDiff;\r\n\r\n return a.tripadvisor_id - b.tripadvisor_id;\r\n}\r\n\r\nfunction resolveRating(marker: Property) {\r\n if (typeof marker.rating === \"number\") return marker.rating;\r\n if (marker.rating === undefined || marker.rating === null) return -Infinity;\r\n const parsed = Number(marker.rating);\r\n return Number.isNaN(parsed) ? -Infinity : parsed;\r\n}\r\n\r\nfunction resolvePrice(marker: Property) {\r\n if (!marker.pricing?.offer?.price) return -Infinity;\r\n const numeric = Number(\r\n (marker.pricing.offer.displayPrice ?? \"0\")\r\n .replace(/[^0-9.,-]+/g, \"\")\r\n .replace(/,/g, \"\")\r\n );\r\n return Number.isNaN(numeric) ? -Infinity : numeric;\r\n}\r\n\r\nexport function metersToPixels(meters: number, latitude: number, zoom: number) {\r\n const metersPerPixel =\r\n (Math.cos((latitude * Math.PI) / 180) * 2 * Math.PI * 6378137) /\r\n (256 * 2 ** zoom);\r\n if (!Number.isFinite(metersPerPixel) || metersPerPixel <= 0) {\r\n return meters;\r\n }\r\n return meters / metersPerPixel;\r\n}\r\n","import type { FilterSchema, SmartFilter } from \"../types\";\r\n\r\n/**\r\n * Response type from the API containing filter information\r\n */\r\nexport type ApiFiltersResponse = Pick<\r\n FilterSchema,\r\n | \"amenities\"\r\n | \"hotelStyle\"\r\n | \"price\"\r\n | \"minRating\"\r\n | \"starRating\"\r\n | \"transformed_query\"\r\n | \"selected_restaurant_price_levels\"\r\n>;\r\n\r\n/**\r\n * Converts API filter response into SmartFilter objects that can be used with the SmartFilter component.\r\n * This utility processes the various filter types returned from the API and transforms them into\r\n * a standardized SmartFilter format.\r\n *\r\n * @param apiFilters - The filter response from the API\r\n * @returns An array of SmartFilter objects\r\n *\r\n * @example\r\n * ```typescript\r\n * const apiResponse = await search({ query: \"hotels with pool\" });\r\n * const filters = processApiFilters(apiResponse.filters);\r\n * // filters will contain SmartFilter objects for amenities, price range, ratings, etc.\r\n * ```\r\n */\r\nexport function processApiFilters(\r\n apiFilters: ApiFiltersResponse\r\n): SmartFilter[] {\r\n const filters: SmartFilter[] = [];\r\n\r\n // Process amenities\r\n if (apiFilters.amenities && Array.isArray(apiFilters.amenities)) {\r\n apiFilters.amenities.forEach((amenity: string) => {\r\n filters.push({\r\n id: `amenity-${amenity}`,\r\n label: amenity,\r\n type: \"amenity\",\r\n value: amenity,\r\n });\r\n });\r\n }\r\n\r\n // Process hotel styles\r\n if (apiFilters.hotelStyle && Array.isArray(apiFilters.hotelStyle)) {\r\n apiFilters.hotelStyle.forEach((style: string) => {\r\n filters.push({\r\n id: `hotelStyle-${style}`,\r\n label: style,\r\n type: \"hotelStyle\",\r\n value: style,\r\n });\r\n });\r\n }\r\n\r\n // Process price range\r\n if (apiFilters.price) {\r\n filters.push({\r\n id: \"priceRange\",\r\n label: \"Price Range\",\r\n type: \"priceRange\",\r\n value: `${apiFilters.price.min}-${apiFilters.price.max}`,\r\n priceRange: apiFilters.price,\r\n });\r\n }\r\n\r\n // Process minimum rating\r\n if (\r\n typeof apiFilters.minRating === \"number\" &&\r\n Number.isFinite(apiFilters.minRating)\r\n ) {\r\n filters.push({\r\n id: \"minRating\",\r\n label: `${apiFilters.minRating}+`,\r\n type: \"minRating\",\r\n value: String(apiFilters.minRating),\r\n numericValue: apiFilters.minRating,\r\n });\r\n }\r\n\r\n // Process star rating\r\n if (\r\n typeof apiFilters.starRating === \"number\" &&\r\n Number.isFinite(apiFilters.starRating)\r\n ) {\r\n filters.push({\r\n id: \"starRating\",\r\n label: `${apiFilters.starRating} Stars`,\r\n type: \"starRating\",\r\n value: String(apiFilters.starRating),\r\n numericValue: apiFilters.starRating,\r\n });\r\n }\r\n\r\n // Process transformed query\r\n if (apiFilters.transformed_query) {\r\n filters.push({\r\n id: \"transformed_query\",\r\n label: apiFilters.transformed_query,\r\n type: \"transformed_query\",\r\n value: apiFilters.transformed_query,\r\n });\r\n }\r\n\r\n // Process restaurant price levels\r\n if (apiFilters.selected_restaurant_price_levels) {\r\n filters.push({\r\n id: \"selected_restaurant_price_levels\",\r\n label: apiFilters.selected_restaurant_price_levels.join(\", \"),\r\n type: \"selected_restaurant_price_levels\",\r\n value: apiFilters.selected_restaurant_price_levels.join(\", \"),\r\n priceLevels: apiFilters.selected_restaurant_price_levels,\r\n });\r\n }\r\n\r\n return filters;\r\n}\r\n\r\n/**\r\n * Converts filter objects (SmartFilter or React Filter) back to API-compatible filter format.\r\n * This is the inverse operation of processApiFilters.\r\n * Accepts filters with label as string or ReactNode and normalizes them.\r\n *\r\n * @param filters - Array of filter objects (SmartFilter or React Filter with ReactNode labels)\r\n * @returns API-compatible SmartFilter array\r\n *\r\n * @example\r\n * ```typescript\r\n * const filters = [\r\n * { id: \"amenity-pool\", label: \"Pool\", type: \"amenity\", value: \"Pool\" }\r\n * ];\r\n * const apiFilters = convertToApiFilters(filters);\r\n * // apiFilters will contain normalized SmartFilter objects\r\n * ```\r\n */\r\nexport function convertToApiFilters(filters: any[]): SmartFilter[] {\r\n return filters.map((filter) => {\r\n const apiFilter: SmartFilter = {\r\n id: filter.id,\r\n label:\r\n typeof filter.label === \"string\"\r\n ? filter.label\r\n : String(filter.label || \"\"),\r\n type: filter.type,\r\n value: filter.value,\r\n };\r\n\r\n if (filter.numericValue !== undefined) {\r\n apiFilter.numericValue = filter.numericValue;\r\n }\r\n\r\n if (filter.priceRange) {\r\n // Handle both optional and required min/max\r\n const min = filter.priceRange.min;\r\n const max = filter.priceRange.max;\r\n if (min !== undefined) {\r\n apiFilter.priceRange = {\r\n min,\r\n ...(max !== undefined && { max }),\r\n };\r\n }\r\n }\r\n\r\n if (filter.priceLevels) {\r\n apiFilter.priceLevels = filter.priceLevels;\r\n }\r\n\r\n return apiFilter;\r\n });\r\n}\r\n","import type { MapAdapter } from \"./adapters\";\nimport { MapLibreAdapter } from \"./adapters/maplibre\";\nimport { GoogleMapsAdapter } from \"./adapters/google\";\nimport { MapboxAdapter } from \"./adapters/mapbox\";\nimport type {\n APIResponse,\n FilterSchema,\n HotelPricingAPIResponse,\n InitialLocationData,\n InitialRequestBody,\n PollOptions,\n Price,\n PriceLevel,\n Property,\n PropertyType,\n SmartFilter,\n} from \"./types\";\nimport type { MapLibreNamespace } from \"./adapters/maplibre/markermanager\";\nimport type { GoogleMapsNamespace } from \"./adapters/google/markermanager\";\nimport type { MapboxNamespace } from \"./adapters/mapbox/markermanager\";\nimport {\n ClusterDisplayItem,\n clusterMarkers,\n extractViewState,\n ViewStateSnapshot,\n} from \"./utils/clustering\";\nimport type {\n MapBounds,\n ViewState,\n ActiveLocation,\n FilterState,\n MapState,\n MapStateCallbacks,\n MapStateUpdate,\n} from \"./state-types\";\n\nexport type {\n Property,\n PropertyType,\n PriceLevel,\n Price,\n FilterSchema,\n Locale,\n SmartFilter,\n} from \"./types\";\n\nexport type { ApiFiltersResponse } from \"./utils/filters\";\nexport { processApiFilters, convertToApiFilters } from \"./utils/filters\";\n\nexport type {\n MapBounds,\n ViewState,\n ActiveLocation,\n FilterState,\n MapState,\n MapStateCallbacks,\n MapStateUpdate,\n} from \"./state-types\";\n\nexport type { MapLibreNamespace } from \"./adapters/maplibre/markermanager\";\n\nexport type { GoogleMapsNamespace } from \"./adapters/google/markermanager\";\n\nexport type { MapboxNamespace } from \"./adapters/mapbox/markermanager\";\n\n// Environment configuration\nexport type Environment = \"prod\" | \"test\";\n\nconst API_URLS: Record<Environment, string> = {\n prod: \"https://api.mapfirst.ai\",\n test: \"https://api.mapfirst.ai/test\",\n};\n\n// Properties fetch error class\nexport class PropertiesFetchError extends Error {\n status: number;\n code?: string;\n\n constructor({\n message,\n status,\n code,\n }: {\n message: string;\n status: number;\n code?: string;\n }) {\n super(message);\n this.name = \"PropertiesFetchError\";\n this.status = status;\n this.code = code;\n }\n}\n\ntype PropertiesErrorResponse = {\n error?: string;\n detail?: string;\n code?: string;\n};\n\ntype FetchPropertiesOptions = {\n signal?: AbortSignal;\n};\n\n// Fetch properties from API\nexport async function fetchProperties<TBody = any, TResponse = any>(\n url: string,\n body: TBody,\n apiKey?: string,\n { signal }: FetchPropertiesOptions = {}\n): Promise<TResponse> {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(apiKey && {\n \"X-API-Key\": apiKey,\n }),\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!response.ok) {\n let message = `Unexpected response: ${response.status}`;\n let code: string | undefined;\n try {\n const errorBody = (await response.json()) as PropertiesErrorResponse;\n message = errorBody.detail ?? errorBody.error ?? message;\n code = errorBody.code;\n } catch {\n // ignore JSON parsing errors and fall back to status-based message\n }\n throw new PropertiesFetchError({ message, status: response.status, code });\n }\n\n return (await response.json()) as TResponse;\n}\n\nfunction toISO(date: Date | string): string {\n if (typeof date === \"string\") return date;\n return date.toISOString().slice(0, 10);\n}\n\nasync function trackMapImpression(\n apiUrl: string,\n apiKey?: string,\n metadata?: Record<string, any>\n): Promise<void> {\n try {\n await fetch(`${apiUrl}/${apiKey}/impressions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(apiKey && { \"X-API-Key\": apiKey }),\n },\n body: JSON.stringify({\n timestamp: new Date().toISOString(),\n type: \"map_view\",\n ...metadata,\n }),\n });\n } catch (error) {\n // Silently fail - don't block user experience for analytics\n console.debug(\"Failed to track map impression:\", error);\n }\n}\n\nexport type BaseMapFirstOptions = {\n properties?: Property[];\n primaryType?: PropertyType;\n selectedMarkerId?: number | null;\n clusterRadiusMeters?: number;\n autoSelectOnClick?: boolean;\n onClusterUpdate?: (\n clusters: ClusterDisplayItem[],\n viewState: ViewStateSnapshot | null\n ) => void;\n // State management options\n state?: Partial<MapState>;\n callbacks?: MapStateCallbacks;\n // API configuration\n useApi?: boolean; // default: true, can only be set at initialization\n environment?: Environment;\n apiKey?: string;\n requestBody?: any;\n // Initial location data (alternative to requestBody)\n initialLocationData?: InitialLocationData;\n // Map behavior options\n fitBoundsPadding?: {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n };\n apiUrl?: string;\n};\n\ntype AdapterDrivenOptions = BaseMapFirstOptions & {\n adapter: MapAdapter;\n platform?: undefined;\n};\n\ntype MapLibreOptions = BaseMapFirstOptions & {\n platform: \"maplibre\";\n mapInstance?: any;\n maplibregl: MapLibreNamespace;\n onMarkerClick?: (marker: Property) => void;\n};\n\ntype GoogleMapsOptions = BaseMapFirstOptions & {\n platform: \"google\";\n mapInstance?: any; // google.maps.Map\n google: GoogleMapsNamespace;\n onMarkerClick?: (marker: Property) => void;\n};\n\ntype MapboxOptions = BaseMapFirstOptions & {\n platform: \"mapbox\";\n mapInstance?: any;\n mapboxgl: MapboxNamespace;\n onMarkerClick?: (marker: Property) => void;\n};\n\nexport type MapFirstOptions =\n | AdapterDrivenOptions\n | MapLibreOptions\n | GoogleMapsOptions\n | MapboxOptions;\n\nconst DEFAULT_PRIMARY_TYPE: PropertyType = \"Accommodation\";\n\n// Helper function to calculate default check-in/check-out dates\nfunction getDefaultDates(): { checkIn: Date; checkOut: Date } {\n const dayMs = 24 * 60 * 60 * 1000;\n const base = new Date(Date.now() + 10 * dayMs);\n const daysUntilSaturday = (6 - base.getDay() + 7) % 7;\n const checkIn = new Date(base.getTime() + daysUntilSaturday * dayMs);\n const startDay = checkIn.getDay();\n const daysUntilWeekend = startDay === 0 ? 6 : 6 - startDay;\n const checkOut = new Date(checkIn.getTime() + (daysUntilWeekend + 1) * dayMs);\n return { checkIn, checkOut };\n}\n\nexport class MapFirstCore {\n private adapter: MapAdapter | null = null;\n private properties: Property[] = [];\n private primaryType?: PropertyType;\n private selectedMarkerId: number | null = null;\n private destroyed = false;\n private clusterItems: ClusterDisplayItem[] = [];\n private isMapAttached = false;\n\n // State management\n private state: MapState;\n private callbacks: MapStateCallbacks;\n\n // API configuration\n private useApi: boolean;\n private readonly environment: Environment;\n private readonly apiUrl: string;\n private apiKey?: string;\n private currentPlatform: \"google\" | \"maplibre\" | \"mapbox\" | undefined;\n private requestBody?: any;\n private readonly fitBoundsPadding: {\n top: number;\n bottom: number;\n left: number;\n right: number;\n };\n\n constructor(private readonly options: MapFirstOptions) {\n this.properties = [...(options.properties ?? [])];\n this.primaryType = options.primaryType;\n this.selectedMarkerId = options.selectedMarkerId ?? null;\n\n // Initialize API configuration\n this.useApi = options.useApi ?? true;\n this.environment = options.environment ?? \"prod\";\n this.apiUrl = options.apiUrl ?? API_URLS[this.environment];\n this.apiKey = options.apiKey;\n this.requestBody = options.requestBody;\n this.currentPlatform = options.platform;\n\n // Validate platform restrictions when useApi is false\n if (!this.useApi && options.platform && options.platform !== \"maplibre\") {\n throw new Error(\n \"When useApi is false, only maplibre platform is supported. Google Maps and Mapbox require API usage.\"\n );\n }\n\n // Determine if using Google Maps\n const isGoogleMaps = isGoogleMapsOptions(options);\n\n // Set default padding based on platform (Google Maps uses 0, others use padding)\n this.fitBoundsPadding = {\n top: options.fitBoundsPadding?.top ?? (isGoogleMaps ? 0 : 50),\n bottom: options.fitBoundsPadding?.bottom ?? (isGoogleMaps ? 0 : 160),\n left: options.fitBoundsPadding?.left ?? (isGoogleMaps ? 0 : 50),\n right: options.fitBoundsPadding?.right ?? (isGoogleMaps ? 0 : 50),\n };\n\n // Initialize default dates\n const defaultDates = getDefaultDates();\n\n // Initialize state\n this.state = {\n center: [0, 0],\n zoom: 0,\n bounds: null,\n pendingBounds: null,\n tempBounds: null,\n properties: this.properties,\n primary: this.primaryType ?? DEFAULT_PRIMARY_TYPE,\n selectedPropertyId: this.selectedMarkerId,\n initialLoading: true,\n isSearching: false,\n firstCallDone: false,\n filters: {\n checkIn: defaultDates.checkIn,\n checkOut: defaultDates.checkOut,\n numAdults: 2,\n numRooms: 1,\n ...(options.initialLocationData?.currency && {\n currency: options.initialLocationData.currency,\n }),\n },\n activeLocation: {\n country: \"\",\n location_id: null,\n locationName: \"\",\n coordinates: [0, 0],\n },\n isFlyToAnimating: false,\n ...options.state,\n };\n\n this.callbacks = options.callbacks ?? {};\n\n // Initialize map adapter if mapInstance is provided\n if (this.hasMapInstance(options)) {\n this.adapter = this.createAdapter(options);\n this.isMapAttached = true;\n this.refresh();\n }\n\n // Handle initial location data or auto-load properties\n if (options.initialLocationData) {\n this.initializeFromLocationData(options.initialLocationData);\n } else if (this.requestBody && this.isMapAttached) {\n this.autoLoadProperties();\n }\n }\n\n private hasMapInstance(options: MapFirstOptions): boolean {\n if (\"adapter\" in options && options.adapter) return true;\n if (\"mapInstance\" in options && options.mapInstance) return true;\n return false;\n }\n\n private async initializeFromLocationData(\n locationData: InitialLocationData\n ): Promise<void> {\n if (!this.useApi) {\n console.warn(\n \"initializeFromLocationData requires API usage. Set useApi to true.\"\n );\n return;\n }\n try {\n const { city, country, query } = locationData;\n\n let requestBody: any = {\n filters: this.getFilters(),\n initial: true,\n };\n\n // Geo-lookup if city/country provided\n if ((city && country) || country) {\n const geoResponse = await fetch(\n `${this.apiUrl}/geo-lookup?country=${encodeURIComponent(country!)}${\n city ? `&city=${encodeURIComponent(city)}` : \"\"\n }`,\n {\n headers: {\n ...(this.apiKey && {\n \"X-API-Key\": this.apiKey,\n }),\n },\n }\n );\n\n if (geoResponse.ok) {\n const geoData = await geoResponse.json();\n\n let finalCity = city;\n if (\n geoData.location_name &&\n geoData.path3_name &&\n geoData.location_name === geoData.path3_name\n ) {\n finalCity = undefined;\n }\n if (geoData.location_name) finalCity = geoData.location_name;\n\n const finalCountry = geoData.path3_name || country;\n\n requestBody = {\n ...requestBody,\n city: finalCity,\n country: finalCountry,\n location_id: geoData.location_id,\n longitude: geoData.longitude,\n latitude: geoData.latitude,\n };\n\n // Update active location\n this.setActiveLocation({\n city: finalCity,\n country: finalCountry,\n location_id: geoData.location_id,\n locationName:\n finalCity && finalCountry\n ? `${finalCity}, ${finalCountry}`\n : finalCountry || \"\",\n coordinates: [geoData.latitude, geoData.longitude],\n });\n\n // Update state center\n this.setState({\n center: [geoData.latitude, geoData.longitude],\n zoom: 12,\n });\n } else {\n this.handleError(\n new Error(`Geo mapping fetch failed: ${geoResponse.statusText}`),\n \"initializeFromLocationData\"\n );\n }\n } else if (query) {\n requestBody.query = query;\n }\n\n this.requestBody = requestBody;\n\n // Auto-load properties if map is already attached\n if (this.isMapAttached) {\n await this.autoLoadProperties();\n }\n } catch (error) {\n this.handleError(error, \"initializeFromLocationData\");\n }\n }\n\n private async autoLoadProperties(): Promise<void> {\n if (!this.useApi) {\n console.warn(\n \"autoLoadProperties requires API usage. Set useApi to true.\"\n );\n return;\n }\n if (!this.requestBody) return;\n\n // Default request body structure based on InitialDataLoader.tsx\n const defaultRequestBody: InitialRequestBody = {\n filters: this.getFilters(),\n initial: true,\n ...this.requestBody,\n };\n\n await this.runPropertiesSearch({\n body: defaultRequestBody,\n onError: (error) => {\n this.handleError(error, \"autoLoadProperties\");\n this.callbacks.onPropertiesLoadError?.(error);\n },\n });\n }\n\n attachMap(\n mapInstance: any,\n config: {\n platform: \"maplibre\" | \"google\" | \"mapbox\";\n maplibregl?: MapLibreNamespace;\n google?: GoogleMapsNamespace;\n mapboxgl?: MapboxNamespace;\n onMarkerClick?: (marker: Property) => void;\n }\n ): void {\n // Validate platform restrictions when useApi is false\n if (!this.useApi && config.platform !== \"maplibre\") {\n throw new Error(\n \"When useApi is false, only maplibre platform is supported. Google Maps and Mapbox require API usage.\"\n );\n }\n\n if (this.isMapAttached) {\n console.warn(\"Map is already attached. Destroying previous adapter.\");\n if (this.adapter) {\n const markerManager = this.adapter.getMarkerManager();\n markerManager?.destroy();\n this.adapter.cleanup();\n }\n }\n\n const adapterConfig: any = {\n ...this.options,\n platform: config.platform,\n mapInstance,\n maplibregl: config.maplibregl,\n google: config.google,\n mapboxgl: config.mapboxgl,\n onMarkerClick: config.onMarkerClick,\n };\n\n this.currentPlatform = config.platform;\n this.adapter = this.createAdapter(adapterConfig);\n this.isMapAttached = true;\n this.refresh();\n\n // Auto-load properties if we have requestBody and haven't loaded yet\n if (this.requestBody && !this.state.firstCallDone) {\n this.autoLoadProperties();\n }\n }\n\n private createAdapter(options: MapFirstOptions): MapAdapter | null {\n if (isMapLibreOptions(options) && options.mapInstance) {\n return this.initializeAdapter(new MapLibreAdapter(options.mapInstance), {\n maplibregl: options.maplibregl,\n onMarkerClick: options.onMarkerClick,\n });\n }\n if (isGoogleMapsOptions(options) && options.mapInstance) {\n return this.initializeAdapter(\n new GoogleMapsAdapter(options.mapInstance),\n { google: options.google, onMarkerClick: options.onMarkerClick }\n );\n }\n if (isMapboxOptions(options) && options.mapInstance) {\n return this.initializeAdapter(new MapboxAdapter(options.mapInstance), {\n mapboxgl: options.mapboxgl,\n onMarkerClick: options.onMarkerClick,\n });\n }\n if (\"adapter\" in options && options.adapter) {\n return options.adapter;\n }\n return null;\n }\n\n private initializeAdapter(adapter: MapAdapter, config: any): MapAdapter {\n const shouldAutoSelect = this.options.autoSelectOnClick ?? true;\n adapter.initialize({\n ...config,\n onMarkerClick: (marker: Property) => {\n if (marker.location) {\n this.flyMapTo(marker.location.lon, marker.location.lat, 14);\n }\n\n // Change primary type if clicking a secondary marker\n if (marker.type !== this.primaryType) {\n this.setPrimaryType(marker.type);\n }\n if (shouldAutoSelect) {\n this.setSelectedMarker(\n marker.tripadvisor_id === this.selectedMarkerId\n ? null\n : marker.tripadvisor_id\n );\n }\n config.onMarkerClick?.(marker);\n },\n onRefresh: () => this.refresh(),\n onMapMoveEnd: (bounds: MapBounds) => {\n // Only call handleMapMoveEnd if it's a real movement, not initial setup\n if (this.state.tempBounds === null) {\n this.setTempBounds(bounds);\n this.setPendingBounds(null);\n } else {\n this.handleMapMoveEnd(bounds);\n }\n },\n });\n\n // Set up impression tracking when map becomes visible in viewport\n if (this.useApi) {\n adapter.setupImpressionTracking(() => {\n // trackMapImpression(this.apiUrl, this.apiKey, {\n // platform: this.currentPlatform,\n // environment: this.environment,\n // });\n console.log(\"ToDo: Track Map Impression\");\n });\n }\n\n return adapter;\n }\n\n _setProperties(properties: Property[]) {\n this.ensureAlive();\n this.properties = [\n ...properties.filter((x) =>\n x.type === \"Accommodation\"\n ? x.pricing?.availability !== \"unavailable\"\n : true\n ),\n ];\n this.updateState({\n properties: this.properties,\n });\n this.callbacks.onPropertiesChange?.(properties);\n this.refresh();\n }\n\n addProperty(property: Property) {\n this.ensureAlive();\n this.properties = [...this.properties, property];\n this.updateState({ properties: this.properties });\n this.callbacks.onPropertiesChange?.(this.properties);\n this.refresh();\n }\n\n clearProperties() {\n this.ensureAlive();\n this.properties = [];\n this.updateState({ properties: [] });\n this.callbacks.onPropertiesChange?.([]);\n this.refresh();\n }\n\n setPrimaryType(primary: PropertyType) {\n this.ensureAlive();\n if (this.primaryType === primary) return;\n this.primaryType = primary;\n this.updateState({ primary });\n this.callbacks.onPrimaryTypeChange?.(primary);\n this.refresh();\n }\n\n setSelectedMarker(markerId: number | null) {\n this.ensureAlive();\n if (this.selectedMarkerId === markerId) return;\n\n // If selecting a marker, check if we need to change the primary type\n if (markerId !== null) {\n const marker = this.properties.find((p) => p.tripadvisor_id === markerId);\n if (marker && marker.type !== this.primaryType) {\n this.setPrimaryType(marker.type);\n }\n }\n\n this.selectedMarkerId = markerId;\n this.updateState({ selectedPropertyId: markerId });\n this.callbacks.onSelectedPropertyChange?.(markerId);\n this.refresh();\n }\n\n // State management methods\n getState(): Readonly<MapState> {\n return { ...this.state };\n }\n\n // Centralized error handler\n private handleError(error: unknown, context: string = \"MapFirstCore\") {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const errorObj = error instanceof Error ? error : new Error(errorMessage);\n\n console.error(`[${context}]`, errorMessage);\n\n if (this.callbacks.onError) {\n this.callbacks.onError(errorObj, context);\n }\n }\n\n updateState(update: MapStateUpdate) {\n this.state = { ...this.state, ...update };\n }\n\n setState(newState: Partial<MapState>) {\n const prevState = { ...this.state };\n this.updateState(newState);\n\n // Trigger callbacks for changed values\n if (newState.center !== undefined && newState.center !== prevState.center) {\n this.callbacks.onCenterChange?.(newState.center, this.state.zoom);\n }\n if (newState.zoom !== undefined && newState.zoom !== prevState.zoom) {\n this.callbacks.onZoomChange?.(newState.zoom);\n }\n if (newState.bounds !== undefined && newState.bounds !== prevState.bounds) {\n this.callbacks.onBoundsChange?.(newState.bounds);\n }\n if (\n newState.pendingBounds !== undefined &&\n newState.pendingBounds !== prevState.pendingBounds\n ) {\n this.callbacks.onPendingBoundsChange?.(newState.pendingBounds);\n }\n if (\n newState.filters !== undefined &&\n newState.filters !== prevState.filters\n ) {\n this.callbacks.onFiltersChange?.(newState.filters);\n }\n if (\n newState.activeLocation !== undefined &&\n newState.activeLocation !== prevState.activeLocation\n ) {\n this.callbacks.onActiveLocationChange?.(newState.activeLocation);\n }\n if (\n newState.initialLoading !== undefined &&\n newState.initialLoading !== prevState.initialLoading\n ) {\n this.callbacks.onLoadingStateChange?.(newState.initialLoading);\n }\n if (\n newState.isSearching !== undefined &&\n newState.isSearching !== prevState.isSearching\n ) {\n this.callbacks.onSearchingStateChange?.(newState.isSearching);\n }\n }\n\n setFilters(filters: FilterState) {\n this.setState({ filters });\n }\n\n setActiveLocation(location: ActiveLocation) {\n this.setState({ activeLocation: location });\n }\n\n setBounds(bounds: MapBounds | null) {\n this.setState({ bounds });\n }\n\n setPendingBounds(bounds: MapBounds | null) {\n this.setState({ pendingBounds: bounds });\n }\n\n setTempBounds(bounds: MapBounds | null) {\n this.setState({ tempBounds: bounds });\n }\n\n setLoading(loading: boolean) {\n this.setState({ initialLoading: loading });\n }\n\n setSearching(searching: boolean) {\n this.setState({ isSearching: searching });\n }\n\n setFlyToAnimating(animating: boolean) {\n this.setState({ isFlyToAnimating: animating });\n }\n\n handleMapMoveEnd(bounds: MapBounds) {\n if (this.state.isFlyToAnimating) {\n this.setState({\n isFlyToAnimating: false,\n tempBounds: bounds,\n pendingBounds: null,\n });\n return;\n }\n\n const tempBounds = this.state.tempBounds;\n if (!tempBounds) {\n this.setState({\n tempBounds: bounds,\n pendingBounds: bounds,\n });\n return;\n }\n\n const delta = 0.01;\n const hasChanged =\n Math.abs(bounds.sw.lat - tempBounds.sw.lat) > delta ||\n Math.abs(bounds.sw.lng - tempBounds.sw.lng) > delta ||\n Math.abs(bounds.ne.lat - tempBounds.ne.lat) > delta ||\n Math.abs(bounds.ne.lng - tempBounds.ne.lng) > delta;\n\n if (hasChanged) {\n this.setState({ pendingBounds: bounds });\n } else {\n this.setState({ pendingBounds: null });\n }\n }\n\n flyMapTo(\n longitude: number,\n latitude: number,\n zoom?: number | null,\n animation: boolean = true\n ) {\n this.ensureAlive();\n this.setState({ center: [latitude, longitude] });\n if (typeof zoom === \"number\") {\n this.setState({ zoom });\n }\n\n if (!this.adapter) return;\n const mapInstance = this.adapter.getMap();\n if (!mapInstance) return;\n\n if (this.currentPlatform === \"google\") {\n this.setFlyToAnimating(false);\n mapInstance.setCenter({ lat: latitude, lng: longitude });\n if (zoom !== null && typeof zoom === \"number\") {\n mapInstance.setZoom(zoom ?? 13);\n }\n return;\n }\n\n // MapLibre/Mapbox\n if (animation === false) {\n this.setFlyToAnimating(false);\n if (mapInstance.jumpTo) {\n mapInstance.jumpTo({\n center: [longitude, latitude],\n ...(zoom !== null && { zoom: zoom ?? 13 }),\n });\n }\n return;\n }\n\n this.setFlyToAnimating(true);\n if (mapInstance.flyTo) {\n mapInstance.flyTo({\n center: [longitude, latitude],\n ...(zoom !== null && { zoom: zoom ?? 13 }),\n });\n }\n }\n\n flyToPOIs(\n pois?: { lat: number; lng: number }[],\n type?: PropertyType,\n animate: boolean = true\n ) {\n this.ensureAlive();\n if (!this.adapter) return;\n const mapInstance = this.adapter.getMap();\n if (!mapInstance) return;\n\n let points = pois;\n if (!points || points.length === 0) {\n points = this.properties\n .filter(\n (x) =>\n x.location !== undefined &&\n (type !== undefined ? x.type === type : true)\n )\n .map((h) => ({\n lat: h.location!.lat,\n lng: h.location!.lon,\n }));\n }\n if (!points || points.length === 0) return;\n\n // Check if this is Google Maps\n\n if (points.length === 1) {\n const poi = points[0];\n if (this.currentPlatform === \"google\") {\n mapInstance.setCenter({ lat: poi.lat, lng: poi.lng });\n mapInstance.setZoom(13);\n } else if (mapInstance.flyTo) {\n mapInstance.flyTo({\n center: [poi.lng, poi.lat],\n zoom: 13,\n });\n }\n } else {\n if (this.currentPlatform === \"google\") {\n // Google Maps\n const LatLngBounds = (window as any).google?.maps?.LatLngBounds;\n if (LatLngBounds) {\n const bounds = new LatLngBounds();\n points.forEach((poi) => {\n bounds.extend({ lat: poi.lat, lng: poi.lng });\n });\n if (animate) {\n this.setFlyToAnimating(true);\n }\n mapInstance.fitBounds(bounds, this.fitBoundsPadding);\n }\n } else if (mapInstance.fitBounds) {\n // MapLibre/Mapbox\n const bounds: [[number, number], [number, number]] = [\n [points[0].lng, points[0].lat],\n [points[0].lng, points[0].lat],\n ];\n\n points.forEach((poi) => {\n bounds[0][0] = Math.min(bounds[0][0], poi.lng);\n bounds[0][1] = Math.min(bounds[0][1], poi.lat);\n bounds[1][0] = Math.max(bounds[1][0], poi.lng);\n bounds[1][1] = Math.max(bounds[1][1], poi.lat);\n });\n\n if (animate) {\n this.setFlyToAnimating(true);\n }\n mapInstance.fitBounds(bounds, {\n padding: this.fitBoundsPadding,\n animate,\n });\n }\n }\n }\n\n getFilters() {\n const filters = { ...this.state.filters };\n // Convert Date objects to ISO strings for API compatibility\n if (filters.checkIn instanceof Date) {\n filters.checkIn = toISO(filters.checkIn);\n }\n if (filters.checkOut instanceof Date) {\n filters.checkOut = toISO(filters.checkOut);\n }\n return filters as FilterSchema;\n }\n\n async pollForPricing({\n pollingLink,\n maxAttempts = 15,\n delayMs = 2000,\n isCancelled,\n price,\n limit,\n }: PollOptions): Promise<{\n completed: boolean;\n pollData?: HotelPricingAPIResponse;\n }> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\"pollForPricing requires API usage. Set useApi to true.\");\n return { completed: false };\n }\n\n if (!pollingLink) {\n return { completed: false };\n }\n\n let completed = false;\n let pollData: HotelPricingAPIResponse | undefined = undefined;\n\n const filters = this.getFilters();\n if (limit) {\n filters.limit = limit;\n }\n\n const body: any = {\n filters,\n pollingLink,\n };\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (isCancelled?.()) {\n return { completed, pollData };\n }\n\n try {\n const pollResp = await fetch(\n `${this.apiUrl}/ta-polling?pollingNumber=${attempt}`,\n {\n method: \"POST\",\n body: JSON.stringify(body),\n headers: {\n \"Content-Type\": \"application/json\",\n ...(this.apiKey && {\n \"X-API-Key\": this.apiKey,\n }),\n },\n }\n );\n\n if (!pollResp.ok) {\n throw new PropertiesFetchError({\n message: `Poll failed: ${pollResp.status}`,\n status: pollResp.status,\n });\n }\n\n pollData = await pollResp.json();\n\n if (isCancelled?.()) {\n return { completed, pollData };\n }\n\n const results = pollData?.success?.results ?? [];\n if (results.length > 0) {\n this.setProperties((prev) => {\n const resultIds = new Set(results.map((h) => h.tripadvisor_id));\n const updatedProperties = prev.filter(\n (property) =>\n property.type !== \"Accommodation\" ||\n resultIds.has(property.tripadvisor_id)\n );\n\n results.forEach((property) => {\n if (!property.location) return;\n if (\n property.pricing?.offer?.price &&\n price &&\n (property.pricing?.offer?.price < price?.min ||\n property.pricing?.offer?.price > price?.max)\n ) {\n property.pricing.availability = \"unavailable\";\n }\n const existingIndex = updatedProperties.findIndex(\n (h) => h.tripadvisor_id === property.tripadvisor_id\n );\n if (existingIndex >= 0) {\n updatedProperties[existingIndex] = property;\n } else {\n updatedProperties.push(property);\n }\n });\n return updatedProperties;\n });\n }\n\n if (pollData?.success?.isComplete) {\n completed = true;\n break;\n }\n } catch (error) {\n this.handleError(error, \"pollForPricing\");\n this.callbacks.onPropertiesLoadError?.(error);\n break;\n }\n\n if (attempt < maxAttempts - 1) {\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n return { completed, pollData };\n }\n\n private setProperties(updater: (prev: Property[]) => Property[]): void {\n const updatedProperties = updater(this.properties);\n this._setProperties(updatedProperties);\n }\n\n private mostCommonTypeFromProperties(properties: Property[]): PropertyType {\n const typeCounts = properties.reduce((counts, property) => {\n counts[property.type] = (counts[property.type] || 0) + 1;\n return counts;\n }, {} as Record<PropertyType, number>);\n\n return Object.entries(typeCounts).reduce((a, b) =>\n typeCounts[a[0] as PropertyType] > typeCounts[b[0] as PropertyType]\n ? a\n : b\n )[0] as PropertyType;\n }\n\n async runPropertiesSearch({\n body,\n beforeApplyProperties,\n smartFiltersClearable,\n onError,\n }: {\n body: InitialRequestBody;\n beforeApplyProperties?: (data: APIResponse) => {\n price?: Price | null;\n limit?: number;\n };\n smartFiltersClearable?: boolean;\n onError?: (error: unknown) => void;\n }): Promise<APIResponse | null> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\n \"runPropertiesSearch requires API usage. Set useApi to true.\"\n );\n onError?.(new Error(\"API usage is disabled\"));\n return null;\n }\n\n this.setState({ firstCallDone: false });\n this.setSearching(true);\n this.clearProperties();\n\n try {\n const data = await fetchProperties<InitialRequestBody, APIResponse>(\n `${this.apiUrl}/properties`,\n body,\n this.apiKey\n );\n\n this.updateActiveLocationFromResponse(data);\n\n let price: Price | null = null;\n let limit: number = 30;\n let primary_type: PropertyType | undefined = data.filters.primary_type;\n\n if (beforeApplyProperties) {\n const result = beforeApplyProperties(data);\n price = result.price ?? null;\n limit = result.limit ?? 30;\n }\n\n // Track if we've already flown to POIs\n const flown = data.properties.some((x) => !!x.location);\n\n // Apply price filtering if price range is specified\n const filteredProperties = price\n ? data.properties.map((x) =>\n x.pricing?.offer\n ? {\n ...x,\n pricing: {\n ...x.pricing,\n availability:\n x.pricing.offer.price &&\n (x.pricing.offer.price < price.min ||\n x.pricing.offer.price > price.max)\n ? (\"unavailable\" as const)\n : x.pricing.availability,\n },\n }\n : x\n )\n : data.properties;\n\n // Apply properties\n this._setProperties(filteredProperties);\n\n // Fly to POIs if properties have locations\n if (flown) {\n this.flyToPOIs(\n data.properties\n .filter(\n (x) =>\n !!x.location &&\n (data.filters.primary_type\n ? x.type === data.filters.primary_type\n : true)\n )\n .map((x) => ({ lat: x.location!.lat, lng: x.location!.lon })),\n undefined,\n body.initial !== true\n );\n }\n\n // Determine and set primary type\n if (\n data.filters.primary_type &&\n data.properties.filter(\n (property) =>\n property.type === data.filters.primary_type &&\n (property.type === \"Accommodation\"\n ? property.pricing?.availability !== \"unavailable\"\n : true)\n ).length > 0\n ) {\n primary_type = data.filters.primary_type;\n this.setPrimaryType(data.filters.primary_type);\n } else if (data.properties.length > 0) {\n const mostCommonType = this.mostCommonTypeFromProperties(\n data.properties\n );\n this.setPrimaryType(mostCommonType);\n primary_type = mostCommonType;\n }\n\n this.setState({ firstCallDone: true });\n\n // Check if we need to poll for pricing\n if (data.isComplete === false && data.pollingLink) {\n const { completed, pollData } = await this.pollForPricing({\n pollingLink: data.pollingLink,\n ...(price && { price }),\n ...(limit && { limit }),\n });\n\n if (\n completed &&\n pollData?.success?.results &&\n pollData.success.results.filter(\n (property) =>\n property.type === data.filters.primary_type &&\n (property.type === \"Accommodation\"\n ? property.pricing?.availability !== \"unavailable\"\n : true)\n ).length === 0 &&\n primary_type &&\n primary_type !== data.filters.primary_type\n ) {\n const mostCommonType = this.mostCommonTypeFromProperties(\n data.properties\n );\n this.setPrimaryType(mostCommonType);\n }\n }\n\n // Fly to POIs if not already done\n if (!flown) {\n if (data.properties.some((x) => !!x.location)) {\n this.flyToPOIs(\n data.properties\n .filter(\n (x) =>\n !!x.location &&\n (data.filters.primary_type\n ? x.type === data.filters.primary_type\n : true)\n )\n .map((x) => ({ lat: x.location!.lat, lng: x.location!.lon })),\n undefined,\n body.initial !== true\n );\n } else if (\n data.filters.location?.latitude &&\n data.filters.location?.longitude\n ) {\n this.flyMapTo(\n data.filters.location.longitude,\n data.filters.location.latitude,\n 12,\n body.initial !== true\n );\n }\n }\n\n return data;\n } catch (error) {\n this.handleError(error, \"runPropertiesSearch\");\n onError?.(error);\n this.callbacks.onPropertiesLoadError?.(error);\n this.clearProperties();\n this.setState({ firstCallDone: true });\n return null;\n } finally {\n this.setSearching(false);\n this.setState({ firstCallDone: true });\n }\n }\n\n async performBoundsSearch(): Promise<APIResponse | null> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\n \"performBoundsSearch requires API usage. Set useApi to true.\"\n );\n return null;\n }\n\n if (!this.state.pendingBounds) {\n return null;\n }\n\n const filters = this.getFilters();\n const body: InitialRequestBody = {\n bounds: this.state.pendingBounds,\n filters,\n };\n\n const priceFilter = filters?.price ?? undefined;\n\n const result = await this.runPropertiesSearch({\n body,\n beforeApplyProperties: () => {\n return { price: priceFilter ?? null };\n },\n });\n\n if (result) {\n this.setBounds(this.state.pendingBounds);\n this.setTempBounds(this.state.pendingBounds);\n this.setPendingBounds(null);\n }\n\n return result;\n }\n\n private updateActiveLocationFromResponse(data: APIResponse) {\n const newLocationId = data.location_id ?? null;\n const newCity = data.filters.location?.city ?? undefined;\n const newCountry = data.filters.location?.country || \"\";\n const newCoordinates = data.filters.location\n ? [data.filters.location.latitude, data.filters.location.longitude]\n : undefined;\n\n if (!newCoordinates) return;\n\n const currentLocation = this.state.activeLocation;\n\n // Check if location has changed\n if (\n newLocationId !== currentLocation?.location_id ||\n newCity !== currentLocation?.city ||\n newCountry !== currentLocation?.country\n ) {\n this.setActiveLocation({\n city: newCity,\n country: newCountry,\n location_id: newLocationId,\n locationName:\n newCity && newCountry\n ? `${newCity}, ${newCountry}`\n : newCountry || \"\",\n coordinates: newCoordinates as [number, number],\n });\n }\n }\n\n async runSmartFilterSearch({\n query,\n filters,\n onProcessFilters,\n onError,\n }: {\n query?: string;\n filters?: SmartFilter[];\n onProcessFilters?: (\n filters: any,\n location_id?: number\n ) => {\n smartFilters?: SmartFilter[];\n price?: Price | null;\n limit?: number;\n language?: string;\n };\n onError?: (error: unknown) => void;\n }): Promise<APIResponse | null> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\n \"runSmartFilterSearch requires API usage. Set useApi to true.\"\n );\n onError?.(new Error(\"API usage is disabled\"));\n return null;\n }\n\n // Build filter payload from smart filters if provided\n let filterPayload = this.getFilters();\n const state = this.getState();\n\n if (filters && filters.length > 0) {\n const amenities = new Set<string>();\n const hotelStyle = new Set<string>();\n let price: { min: number; max: number } | undefined;\n let minRating: number | undefined;\n let starRating: number | undefined;\n let primary_type: PropertyType | undefined;\n let transformed_query: string | undefined;\n let selected_restaurant_price_levels: PriceLevel[] | undefined;\n\n filters.forEach((filter) => {\n switch (filter.type) {\n case \"amenity\":\n amenities.add(filter.value);\n break;\n case \"hotelStyle\":\n hotelStyle.add(filter.value);\n break;\n case \"priceRange\":\n if (filter.priceRange) {\n price = {\n min: filter.priceRange.min,\n max: filter.priceRange.max ?? 0,\n };\n }\n break;\n case \"minRating\":\n minRating = filter.numericValue ?? Number(filter.value);\n break;\n case \"starRating\":\n starRating = filter.numericValue ?? Number(filter.value);\n break;\n case \"primary_type\":\n primary_type = filter.propertyType;\n break;\n case \"transformed_query\":\n transformed_query = filter.value;\n break;\n case \"selected_restaurant_price_levels\":\n selected_restaurant_price_levels = filter.priceLevels;\n break;\n }\n });\n\n filterPayload = {\n ...filterPayload,\n ...(amenities.size > 0 && { amenities: Array.from(amenities) }),\n ...(hotelStyle.size > 0 && { hotelStyle: Array.from(hotelStyle) }),\n ...(price && { price }),\n ...(minRating !== undefined && { minRating }),\n ...(starRating !== undefined && { starRating }),\n ...(primary_type && { primary_type }),\n ...(transformed_query && { transformed_query }),\n ...(selected_restaurant_price_levels && {\n selected_restaurant_price_levels,\n }),\n };\n } else if (!query) {\n // Add default minRating if no filters and no query\n filterPayload.minRating = 4;\n }\n\n const body: InitialRequestBody = {\n filters: filterPayload,\n ...(query && { query }),\n ...(state.bounds\n ? { bounds: state.bounds }\n : state.activeLocation.location_id\n ? { location_id: state.activeLocation.location_id }\n : state.activeLocation.coordinates\n ? {\n latitude: state.activeLocation.coordinates[0],\n longitude: state.activeLocation.coordinates[1],\n }\n : {}),\n };\n\n return this.runPropertiesSearch({\n body,\n beforeApplyProperties: onProcessFilters\n ? (data) => {\n const result = onProcessFilters(data.filters, data.location_id);\n return {\n price: result.price ?? null,\n limit: result.limit ?? 30,\n };\n }\n : undefined,\n smartFiltersClearable: !!query,\n onError,\n });\n }\n\n getClusters(): ClusterDisplayItem[] {\n this.ensureAlive();\n return [...this.clusterItems];\n }\n\n setUseApi(useApi: boolean, autoLoad: boolean = true) {\n this.ensureAlive();\n\n // Update useApi value\n this.useApi = useApi;\n\n // Validate platform restrictions when switching to useApi = false\n if (\n !useApi &&\n this.currentPlatform &&\n this.currentPlatform !== \"maplibre\"\n ) {\n console.warn(\n \"When useApi is false, only maplibre platform is supported. Please switch to maplibre.\"\n );\n }\n\n // Clear properties when disabling API\n if (!useApi) {\n this.clearProperties();\n }\n\n // Auto-load properties if enabled and useApi is turned on\n if (useApi && autoLoad) {\n if (this.options.initialLocationData) {\n this.initializeFromLocationData(this.options.initialLocationData);\n } else if (this.requestBody && this.isMapAttached) {\n this.autoLoadProperties();\n }\n }\n }\n\n setApiKey(apiKey: string | undefined) {\n this.ensureAlive();\n const oldKey = this.apiKey;\n this.apiKey = apiKey;\n\n // If API key changed and map is attached, refresh\n if (oldKey !== this.apiKey && this.isMapAttached) {\n this.refresh();\n\n if (this.useApi) {\n if (this.options.initialLocationData) {\n this.initializeFromLocationData(this.options.initialLocationData);\n } else if (this.requestBody) {\n this.autoLoadProperties();\n }\n }\n }\n }\n\n getApiKey(): string | undefined {\n return this.apiKey;\n }\n\n refresh() {\n this.ensureAlive();\n if (!this.adapter) return;\n\n const viewState = this.safeExtractViewState();\n const primaryType = this.resolvePrimaryType();\n\n this.clusterItems = clusterMarkers({\n primaryType,\n markers: this.properties,\n map: this.adapter,\n selectedMarkerId: this.selectedMarkerId,\n zoom: viewState?.zoom ?? 0,\n });\n\n const markerManager = this.adapter.getMarkerManager();\n markerManager.render(this.clusterItems, primaryType, this.selectedMarkerId);\n\n this.options.onClusterUpdate?.(this.clusterItems, viewState);\n }\n\n destroy() {\n if (this.destroyed) {\n return;\n }\n if (this.adapter) {\n const markerManager = this.adapter.getMarkerManager();\n markerManager.destroy();\n this.adapter.cleanup();\n }\n\n this.clusterItems = [];\n this.properties = [];\n this.destroyed = true;\n this.isMapAttached = false;\n }\n\n private resolvePrimaryType(): PropertyType {\n return (\n this.primaryType ??\n this.properties.find((marker) => marker.type)?.type ??\n DEFAULT_PRIMARY_TYPE\n );\n }\n\n private safeExtractViewState(): ViewStateSnapshot | null {\n if (!this.adapter) return null;\n try {\n return extractViewState(this.adapter);\n } catch {\n return null;\n }\n }\n\n private ensureAlive() {\n if (this.destroyed) {\n throw new Error(\"MapFirstCore instance has been destroyed\");\n }\n }\n}\n\nfunction isMapLibreOptions(\n options: MapFirstOptions\n): options is MapLibreOptions {\n return (options as MapLibreOptions).platform === \"maplibre\";\n}\n\nfunction isGoogleMapsOptions(\n options: MapFirstOptions\n): options is GoogleMapsOptions {\n return (options as GoogleMapsOptions).platform === \"google\";\n}\n\nfunction isMapboxOptions(options: MapFirstOptions): options is MapboxOptions {\n return (options as MapboxOptions).platform === \"mapbox\";\n}\n"],"mappings":"AACyB,SAARA,EAA6BC,EAAK,CAAE,SAAAC,CAAS,EAAI,CAAC,EAAG,CAC1D,GAAI,CAACD,GAAO,OAAO,UAAa,YAAa,OAE7C,IAAME,EAAO,SAAS,MAAQ,SAAS,qBAAqB,MAAM,EAAE,CAAC,EAC/DC,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,KAAO,WAETF,IAAa,OACXC,EAAK,WACPA,EAAK,aAAaC,EAAOD,EAAK,UAAU,EAK1CA,EAAK,YAAYC,CAAK,EAGpBA,EAAM,WACRA,EAAM,WAAW,QAAUH,EAE3BG,EAAM,YAAY,SAAS,eAAeH,CAAG,CAAC,CAElD,CCvB8BI,EAAY;AAAA,CAAgxH,ECI7zH,SAASC,EACdC,EACAC,EACAC,EACAC,EACA,CATF,IAAAC,EAAAC,EAAAC,EAUE,GAAI,OAAO,UAAa,YACtB,OAAO,KAGT,IAAMC,EAASP,EAAK,OACdQ,EAAgBD,EAAO,OAASN,EAChCQ,EAAaP,IAAqBK,EAAO,eAEzCG,EADkBH,EAAO,OAAS,mBAEnBF,GAAAD,EAAAG,EAAO,UAAP,YAAAH,EAAgB,QAAhB,YAAAC,EAAuB,gBAAiB,YAGvDM,EAAY,SAAS,cAAc,KAAK,EAC9CA,EAAU,UAAY,gCACtBA,EAAU,MAAM,OAASF,EAAa,KAAOD,EAAgB,IAAM,IAEnE,IAAMI,EAAS,SAAS,cAAc,KAAK,EAC3C,OAAAA,EAAO,UAAYF,EACf,gEACA,+DACED,EACI,gCACCD,EAED,GADA,kCAEN,GACJI,EAAO,OAAQN,EAAAC,EAAO,OAAP,KAAAD,EAAe,OAAOC,EAAO,cAAc,EAE1DK,EAAO,iBAAiB,QAAUC,GAAQ,CACxCA,EAAI,gBAAgB,EACfH,GACHP,GAAA,MAAAA,EAAgBI,EAEpB,CAAC,EAEDI,EAAU,YAAYC,CAAM,EACrBD,CACT,CC3CA,IAAMG,GAAY,s3DAEZC,GAAiB,k2DAEjBC,GAAgB,+xBAEhBC,GAAiB,oiBAEvB,SAASC,GAAuBC,EAAsB,CAKpD,MAAO,QAJgBA,EACpB,YAAY,EACZ,QAAQ,OAAQ,EAAE,EAClB,QAAQ,KAAM,EAAE,CACU,OAC/B,CAEA,SAASC,GAAmBC,EAA+B,CApB3D,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAqBE,IAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,+BAEjB,IAAMC,EAAST,EAAO,QAAU,EAC1BU,EAAUV,EAAO,SAAW,EAC5BW,GACJR,GAAAD,GAAAD,EAAAD,EAAO,UAAP,YAAAC,EAAgB,QAAhB,YAAAC,EAAuB,eAAvB,KAAAC,EAAuCH,EAAO,YAC1CY,GAAML,GAAAF,GAAAD,EAAAJ,EAAO,UAAP,YAAAI,EAAgB,QAAhB,YAAAC,EAAuB,WAAvB,KAAAE,GAAmCD,EAAAN,EAAO,OAAP,YAAAM,EAAa,YAAY,KAGlEO,EAAc,IAAM,CACxB,IAAMC,EAAY,KAAK,MAAML,CAAM,EAC7BM,EAAcN,EAAS,GAAK,GAC5BO,EAAQ,CAAC,EAEf,QAASC,EAAI,EAAGA,EAAIH,EAAWG,IAC7BD,EAAM,KAAK,4CAAuC,EAEhDD,GACFC,EAAM,KAAK,4CAAuC,EAEpD,IAAME,EAAa,EAAIF,EAAM,OAC7B,QAASC,EAAI,EAAGA,EAAIC,EAAYD,IAC9BD,EAAM,KAAK,yCAAoC,EAEjD,OAAOA,EAAM,KAAK,EAAE,CACtB,EAEMG,EAAWtB,GAAuBG,EAAO,IAAI,EAEnD,OAAAQ,EAAK,UAAY;AAAA;AAAA,aAENW,CAAQ;AAAA,aACRnB,EAAO,IAAI;AAAA;AAAA;AAAA;AAAA,kDAI0BA,EAAO,IAAI;AAAA;AAAA,qCAExBS,EAAO,QAAQ,CAAC,CAAC;AAAA,8BACxBI,EAAY,CAAC;AAAA,iCACVH,CAAO;AAAA;AAAA,QAGhCV,EAAO,OAAS,iBAAmBW,EAC/B;AAAA;AAAA,gCAEoBA,CAAY;AAAA;AAAA,QAGhC,EACN;AAAA,QAEEC,EACI;AAAA;AAAA,kBAEMA,CAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQT,EACN;AAAA;AAAA,IAIGJ,CACT,CAEA,SAASY,EACPZ,EACAa,EACAC,EACA,CAEA,IAAMC,EAAaF,EAAc,sBAAsB,EACjDG,EAAgBF,EAAa,sBAAsB,EAEnDG,EAAY,IACZC,EAAa,IACbC,EAAS,GAGTC,EAAaJ,EAAc,MAAQD,EAAW,MAC9CM,EAAYN,EAAW,KAAOC,EAAc,KAC5CM,EAAcN,EAAc,OAASD,EAAW,OAChDQ,EAAWR,EAAW,IAAMC,EAAc,IAG5CQ,EACFT,EAAW,KAAOC,EAAc,KAAOD,EAAW,MAAQ,EAAIE,EAAY,EACxEQ,EAAMV,EAAW,IAAMC,EAAc,IAAMD,EAAW,OAASI,EAG/DK,EAAO,EACTA,EAAO,EACEA,EAAOP,EAAYD,EAAc,QAC1CQ,EAAOR,EAAc,MAAQC,EAAY,GAIvCK,EAAcJ,EAAaC,GAAUI,EAAWD,IAElDG,EAAMV,EAAW,IAAMC,EAAc,IAAME,EAAaC,GAG1DnB,EAAK,MAAM,KAAO,GAAGwB,CAAI,KACzBxB,EAAK,MAAM,IAAM,GAAGyB,CAAG,IACzB,CAEO,SAASC,EACdC,EACAC,EACAC,EACAC,EACA,CA3IF,IAAArC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EA4IE,GAAI,OAAO,UAAa,YACtB,OAAO,KAGT,IAAMP,EAASmC,EAAK,OACdI,EAAgBvC,EAAO,OAASoC,EAChCI,EAAaH,IAAqBrC,EAAO,eACzCyC,EAAkBzC,EAAO,OAAS,gBAClC0C,GAAWxC,GAAAD,EAAAD,EAAO,UAAP,YAAAC,EAAgB,QAAhB,YAAAC,EAAuB,aAClCyC,EAAYF,GAAmB,CAACC,EAGhCE,GAAe,IAAM,CACzB,GAAI5C,EAAO,SAAW,QAAaA,EAAO,SAAW,KAAM,OAAO,KAClE,IAAM6C,EACJ,OAAO7C,EAAO,QAAW,SAAWA,EAAO,OAAS,OAAOA,EAAO,MAAM,EAC1E,OAAI,OAAO,MAAM6C,CAAO,GAAKA,GAAW,EAAU,KAC3CA,EAAQ,QAAQ,CAAC,CAC1B,GAAG,EAEGC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,uBACjBA,EAAK,MAAM,OAASN,EAAa,KAAOD,EAAgB,KAAO,KAE/D,IAAMQ,EAAO,SAAS,cAAc,KAAK,EAazC,GAZAA,EAAK,UAAYJ,EACb,oDACA,mDACEH,EACI,4BACCD,EAED,GADA,8BAEN,GAIA,CAACI,KAAcxC,EAAAH,EAAO,SAAP,MAAAG,EAAe,QAAUyC,GAAc,CACxD,IAAMI,EAAQ,SAAS,cAAc,KAAK,EAO1C,GANAA,EAAM,UAAY,wBACbT,IACHS,EAAM,MAAM,QAAU,OAExBA,EAAM,UAAY,yBAEd5C,EAAAJ,EAAO,SAAP,MAAAI,EAAe,QAAUJ,EAAO,OAAO,CAAC,EAAE,KAAM,CAClD,IAAMiD,EAAiB,SAAS,cAAc,KAAK,EACnDA,EAAe,UAAY,kCAE3B,IAAMC,EAAY,SAAS,cAAc,KAAK,EAC9CA,EAAU,UAAY,6BACtBA,EAAU,UAAYxD,GAEtB,IAAMyD,EAAW,SAAS,cAAc,KAAK,EAC7CA,EAAS,UAAY,4DAA4DnD,EAAO,OAAO,CAAC,EAAE,IAAI,GAEtG,IAAMoD,EAAa,SAAS,cAAc,KAAK,EAC/CA,EAAW,UAAY,8BACvBA,EAAW,UAAY3D,GAEvBwD,EAAe,YAAYC,CAAS,EACpCD,EAAe,YAAYE,CAAQ,EACnCF,EAAe,YAAYG,CAAU,EACrCJ,EAAM,YAAYC,CAAc,CAClC,MAAWL,IACTI,EAAM,UAAY,qDAClBA,EAAM,YAAcJ,GAGtBG,EAAK,YAAYC,CAAK,CACxB,CAGA,IAAMK,EAAU,SAAS,cAAc,MAAM,EAmB7C,GAlBAA,EAAQ,UAAY,0BAChBZ,EACFY,EAAQ,aAAc9C,GAAAD,GAAAD,EAAAL,EAAO,UAAP,YAAAK,EAAgB,QAAhB,YAAAC,EAAuB,eAAvB,KAAAC,EAAuC,SACpDP,EAAO,OAAS,cACzBqD,EAAQ,UAAY1D,GACXK,EAAO,OAAS,eACzBqD,EAAQ,UAAYzD,IAEtBmD,EAAK,YAAYM,CAAO,EAExBN,EAAK,iBAAiB,QAAUO,GAAQ,CACtCA,EAAI,gBAAgB,EACfX,GACHL,GAAA,MAAAA,EAAgBtC,EAEpB,CAAC,EAGG,CAAC2C,EAAW,CACd,IAAMY,EAAexD,GAAmBC,CAAM,EAC1CwD,EAAqD,KACrDC,EAAoD,KACpDC,EAAqC,KAEnCC,EAAc,IAAM,CACpBH,IACF,aAAaA,CAAY,EACzBA,EAAe,MAEbC,IACF,aAAaA,CAAW,EACxBA,EAAc,MAEZC,IACF,qBAAqBA,CAAmB,EACxCA,EAAsB,MAEpBH,EAAa,eACfA,EAAa,OAAO,CAExB,EAEMK,EAAqB,IAAM,CAC/B,GAAIL,EAAa,cAAe,CAC9B,IAAIjC,EAAewB,EAAK,cACxB,KACExB,GACA,iBAAiBA,CAAY,EAAE,WAAa,UAE5CA,EAAeA,EAAa,cAG1BA,IACFF,EAAamC,EAAcT,EAAMxB,CAAY,EAC7CoC,EAAsB,sBAAsBE,CAAkB,EAElE,CACF,EAEMC,EAAW,CAACC,EAAY,KAAU,CAClCL,IACF,aAAaA,CAAW,EACxBA,EAAc,MAGhB,IAAMM,EAAS,IAAM,CAEnB,IAAIzC,EAAewB,EAAK,cACxB,KACExB,GACA,iBAAiBA,CAAY,EAAE,WAAa,UAE5CA,EAAeA,EAAa,cAG1BA,IACFA,EAAa,YAAYiC,CAAY,EACrCnC,EAAamC,EAAcT,EAAMxB,CAAY,EAE7CoC,EAAsB,sBAAsBE,CAAkB,EAElE,EAEIE,EACFC,EAAO,EAEPP,EAAe,WAAWO,EAAQ,GAAG,CAEzC,EAEMC,EAAW,IAAM,CAEjBxB,IAEAgB,IACF,aAAaA,CAAY,EACzBA,EAAe,MAEbE,IACF,qBAAqBA,CAAmB,EACxCA,EAAsB,MAExBD,EAAc,WAAW,IAAM,CACzBF,EAAa,eACfA,EAAa,OAAO,CAExB,EAAG,GAAG,EACR,EAGIf,GACFqB,EAAS,EAAI,EAGfd,EAAK,iBAAiB,aAAc,IAAMc,EAAS,EAAK,CAAC,EACzDd,EAAK,iBAAiB,aAAciB,CAAQ,EAG5CT,EAAa,iBAAiB,aAAc,IAAM,CAC5CE,IACF,aAAaA,CAAW,EACxBA,EAAc,MAGZ,CAACC,GAAuBH,EAAa,gBACvCG,EAAsB,sBAAsBE,CAAkB,EAElE,CAAC,EAEDL,EAAa,iBAAiB,aAAcS,CAAQ,EAGpD,IAAMC,EAAW,IAAI,iBAAkBC,GAAc,CACnD,QAAWC,KAAYD,EACrB,QAAWE,KAAeD,EAAS,aACjC,GAAIC,IAAgBtB,GAAQsB,EAAY,SAAStB,CAAI,EAAG,CACtDa,EAAY,EACZM,EAAS,WAAW,EACpB,MACF,CAGN,CAAC,EAGD,GAAInB,EAAK,cACPmB,EAAS,QAAQnB,EAAK,cAAe,CAAE,UAAW,GAAM,QAAS,EAAK,CAAC,MAClE,CAEL,IAAMuB,EAAc,YAAY,IAAM,CAChCvB,EAAK,gBACPmB,EAAS,QAAQnB,EAAK,cAAe,CACnC,UAAW,GACX,QAAS,EACX,CAAC,EACD,cAAcuB,CAAW,EAE7B,EAAG,GAAG,CACR,CACF,CAEA,OAAAvB,EAAK,YAAYC,CAAI,EACdD,CACT,CClXO,SAASwB,EACdC,EACAC,EACAC,EACAC,EACA,CAEA,IAAMC,EAAOJ,EACbI,EAAK,MAAM,OAASF,EAAa,KAAOD,EAAgB,KAAO,KAG/D,IAAMI,EAAOD,EAAK,cAAc,uBAAuB,EACnDC,IACEF,EACFE,EAAK,UAAY,oDAEjBA,EAAK,UAAY,mDACfH,EACI,4BACCD,EAED,GADA,8BAEN,IAKJ,IAAMK,EAAQF,EAAK,cAAc,wBAAwB,EACrDE,aAAiB,cACnBA,EAAM,MAAM,QAAU,CAACL,GAAiB,CAACC,EAAa,MAAQ,GAElE,CAKO,SAASK,EACdP,EACAC,EACAC,EACAC,EACA,CAEA,IAAMK,EAAYR,EAClBQ,EAAU,MAAM,OAASN,EAAa,KAAOD,EAAgB,IAAM,IAGnE,IAAMQ,EAASD,EAAU,cAAc,6BAA6B,EAChEC,IACEN,EACFM,EAAO,UACL,gEAEFA,EAAO,UAAY,+DACjBP,EACI,gCACCD,EAED,GADA,kCAEN,GAGN,CAKO,SAASS,EAAuBC,EAA4B,CACjE,IAAMC,EAAQD,EAAI,MAAM,yBAAyB,EACjD,OAAOC,EAAQ,SAASA,EAAM,CAAC,EAAG,EAAE,EAAI,IAC1C,CC5DO,IAAeC,EAAf,KAAgD,CAOrD,YAAYC,EAAkBC,EAA4C,CAJ1E,KAAU,YAAc,IAAI,IAC5B,KAAU,YAAsB,gBAChC,KAAU,iBAAkC,KAG1C,KAAK,YAAcD,EACnB,KAAK,cAAgBC,CACvB,CAEA,OACEC,EACAC,EACAC,EACA,CAjCJ,IAAAC,EAAAC,EAAAC,EAAAC,EAkCQL,GAAeA,IAAgB,KAAK,cACtC,KAAK,YAAcA,GAEjBC,IAAqB,SACvB,KAAK,iBAAmBA,GAI1B,IAAMK,EAAU,IAAI,IAAIP,EAAM,IAAKQ,GAASA,EAAK,GAAG,CAAC,EAGrD,OAAW,CAACC,EAAKC,CAAK,IAAK,KAAK,YAAY,QAAQ,EAC7CH,EAAQ,IAAIE,CAAG,IAClB,KAAK,oBAAoBC,EAAM,MAAM,EACrC,KAAK,YAAY,OAAOD,CAAG,GAK/B,QAAWD,KAAQR,EAAO,CACxB,IAAMW,EAASC,GAAWJ,EAAK,OAAO,QAAQ,EAC9C,GAAI,CAACG,EAAQ,SAEb,IAAME,EAAW,KAAK,YAAY,IAAIL,EAAK,GAAG,EAE9C,GAAIK,EAEF,GAAI,CACF,KAAK,qBAAqBA,EAAS,OAAQF,CAAM,CACnD,MAAQ,CAEN,KAAK,oBAAoBE,EAAS,MAAM,EACxC,KAAK,YAAY,OAAOL,EAAK,GAAG,EAChC,KAAK,mBAAmBA,EAAMG,CAAM,CACtC,KACK,CAEL,IAAMG,EAAWN,EAAK,OAAO,eACzBO,EACAC,EAEJ,OAAW,CAACP,EAAKC,CAAK,IAAK,KAAK,YAAY,QAAQ,EAClD,GACEO,EAAuBR,CAAG,IAAMK,GAChCJ,EAAM,OAASF,EAAK,KACpB,CACAO,EAAgBL,EAChBM,EAAcP,EACd,KACF,CAGF,GAAIM,GAAiBC,EAAa,CAEhC,IAAME,EAAgBV,EAAK,OAAO,OAAS,KAAK,YAC1CW,EACJ,KAAK,mBAAqBX,EAAK,OAAO,eAClCY,EAAkBZ,EAAK,OAAO,OAAS,gBACvCa,EACJb,EAAK,OAAS,UACVY,GAAmB,GAAChB,GAAAD,EAAAK,EAAK,OAAO,UAAZ,YAAAL,EAAqB,QAArB,MAAAC,EAA4B,cAChDgB,KACAd,GAAAD,EAAAG,EAAK,OAAO,UAAZ,YAAAH,EAAqB,QAArB,YAAAC,EAA4B,gBAAiB,YAE7CgB,EAAU,KAAK,iBAAiBP,EAAc,MAAM,EACtDO,IACEd,EAAK,OAAS,UAChBe,EACED,EACAJ,EACAC,EACAE,CACF,EAEAG,EACEF,EACAJ,EACAC,EACAE,CACF,GAKJ,KAAK,mBACHN,EAAc,OACdP,EACAU,EACAC,CACF,EAGA,KAAK,YAAY,OAAOH,CAAW,EACnC,KAAK,YAAY,IAAIR,EAAK,IAAKO,CAAa,EAG5C,GAAI,CACF,KAAK,qBAAqBA,EAAc,OAAQJ,CAAM,CACxD,MAAQ,CAER,CACF,MAEE,KAAK,mBAAmBH,EAAMG,CAAM,CAExC,CACF,CACF,CAEA,SAAU,CACR,QAAWD,KAAS,KAAK,YAAY,OAAO,EAC1C,KAAK,oBAAoBA,EAAM,MAAM,EAEvC,KAAK,YAAY,MAAM,CACzB,CAEU,mBACRF,EACAG,EACA,CACA,IAAMW,EACJd,EAAK,OAAS,UACViB,EACEjB,EACA,KAAK,YACL,KAAK,iBACL,KAAK,aACP,EACAkB,EACElB,EACA,KAAK,YACL,KAAK,iBACL,KAAK,aACP,EAEN,GAAI,CAACc,EAAS,OAEd,IAAMJ,EAAgBV,EAAK,OAAO,OAAS,KAAK,YAC1CW,EAAa,KAAK,mBAAqBX,EAAK,OAAO,eAEzD,GAAI,CACF,IAAMmB,EAAS,KAAK,aAClBL,EACAX,EACAH,EACAU,EACAC,CACF,EACIQ,GACF,KAAK,YAAY,IAAInB,EAAK,IAAK,CAC7B,IAAKA,EAAK,IACV,OAAAmB,EACA,KAAMnB,EAAK,KACX,SAAUA,EAAK,OAAS,MAAQA,EAAK,SAAW,MAClD,CAAC,CAEL,OAASoB,EAAO,CACd,QAAQ,MAAM,wBAAyBA,CAAK,CAC9C,CACF,CAoBU,mBACRD,EACAnB,EACAU,EACAC,EACM,CAER,CACF,EAEA,SAASP,GAAWiB,EAA2C,CAI7D,OAHI,OAAOA,GAAA,YAAAA,EAAU,MAAQ,UAAY,OAAOA,GAAA,YAAAA,EAAU,MAAQ,UAG9D,OAAO,MAAMA,EAAS,GAAG,GAAK,OAAO,MAAMA,EAAS,GAAG,EAClD,KAEF,CAAE,IAAKA,EAAS,IAAK,IAAKA,EAAS,GAAI,CAChD,CC/MO,IAAMC,EAAN,cAAoCC,CAAwC,CAGjF,YAAYC,EAAuC,CA3BrD,IAAAC,EA4BI,MAAMD,EAAQ,YAAaA,EAAQ,aAAa,EAChD,KAAK,YAAaC,EAAAD,EAAQ,aAAR,YAAAC,EAAoB,MACxC,CAEA,OACEC,EACAC,EACAC,EACA,CACK,KAAK,YAGV,MAAM,OAAOF,EAAOC,EAAaC,CAAgB,CACnD,CAEU,aACRC,EACAC,EACAC,EAC6B,CAC7B,OAAK,KAAK,WAEH,IAAI,KAAK,WAAW,CACzB,QAAAF,EACA,OAAQE,EAAK,OAAS,UAAY,SAAW,QAC/C,CAAC,EACE,UAAU,CAACD,EAAO,IAAKA,EAAO,GAAG,CAAC,EAClC,MAAM,KAAK,WAAW,EAPI,IAQ/B,CAEU,oBAAoBE,EAAoC,CAChE,GAAI,CACFA,EAAO,OAAO,CAChB,MAAQ,CAER,CACF,CAEU,qBACRA,EACAF,EACM,CACNE,EAAO,UAAU,CAACF,EAAO,IAAKA,EAAO,GAAG,CAAC,CAC3C,CAEU,iBAAiBE,EAAkD,CAC3E,OAAOA,EAAO,WAAW,CAC3B,CACF,EC9DO,IAAMC,EAAN,cAAsCC,CAA0C,CAGrF,YAAYC,EAAyC,CACnD,MAAMA,EAAQ,YAAaA,EAAQ,aAAa,EAChD,KAAK,OAASA,EAAQ,MACxB,CAEA,OACEC,EACAC,EACAC,EACA,CA1BJ,IAAAC,EAAAC,EA2BI,GAAI,GAACA,GAAAD,EAAA,KAAK,SAAL,YAAAA,EAAa,SAAb,MAAAC,EAAqB,uBAAuB,CAC/C,QAAQ,KAAK,qCAAqC,EAClD,MACF,CACA,MAAM,OAAOJ,EAAOC,EAAaC,CAAgB,CACnD,CAEU,aACRG,EACAC,EACAC,EACAC,EACAC,EAC+B,CAxCnC,IAAAN,EAAAC,EAyCI,GAAI,GAACA,GAAAD,EAAA,KAAK,SAAL,YAAAA,EAAa,SAAb,MAAAC,EAAqB,uBAAuB,OAAO,KAExD,IAAMM,EACJH,EAAK,OAAS,UACVE,EACE,GACAD,EACA,GACA,GACFC,EACA,GACAD,EACA,EACA,EAEN,OAAO,IAAI,KAAK,OAAO,OAAO,sBAAsB,CAClD,IAAK,KAAK,YACV,SAAU,CAAE,IAAKF,EAAO,IAAK,IAAKA,EAAO,GAAI,EAC7C,QAASD,EACT,OAAAK,CACF,CAAC,CACH,CAEU,oBAAoBC,EAAsC,CAClE,GAAI,CACFA,EAAO,IAAM,IACf,OAASC,EAAO,CACd,QAAQ,MAAM,wBAAyBA,CAAK,CAC9C,CACF,CAEU,qBACRD,EACAL,EACM,CACNK,EAAO,SAAW,CAAE,IAAKL,EAAO,IAAK,IAAKA,EAAO,GAAI,CACvD,CAEU,iBACRK,EACoB,CACpB,IAAMN,EAAUM,EAAO,QACvB,OAAON,aAAmB,YAAcA,EAAU,IACpD,CAEU,mBACRM,EACAJ,EACAC,EACAC,EACM,CACN,IAAMC,EACJH,EAAK,OAAS,UACVE,EACE,GACAD,EACA,GACA,GACFC,EACA,GACAD,EACA,EACA,EACNG,EAAO,OAASD,CAClB,CACF,EClFO,IAAMG,EAAN,cAAkCC,CAAsC,CAG7E,YAAYC,EAAqC,CA3BnD,IAAAC,EA4BI,MAAMD,EAAQ,YAAaA,EAAQ,aAAa,EAChD,KAAK,YAAaC,EAAAD,EAAQ,WAAR,YAAAC,EAAkB,MACtC,CAEA,OACEC,EACAC,EACAC,EACA,CACK,KAAK,YAGV,MAAM,OAAOF,EAAOC,EAAaC,CAAgB,CACnD,CAEU,aACRC,EACAC,EACAC,EAC2B,CAC3B,OAAK,KAAK,WAEH,IAAI,KAAK,WAAW,CACzB,QAAAF,EACA,OAAQE,EAAK,OAAS,UAAY,SAAW,QAC/C,CAAC,EACE,UAAU,CAACD,EAAO,IAAKA,EAAO,GAAG,CAAC,EAClC,MAAM,KAAK,WAAW,EAPI,IAQ/B,CAEU,oBAAoBE,EAAkC,CAC9D,GAAI,CACFA,EAAO,OAAO,CAChB,MAAQ,CAER,CACF,CAEU,qBACRA,EACAF,EACM,CACNE,EAAO,UAAU,CAACF,EAAO,IAAKA,EAAO,GAAG,CAAC,CAC3C,CAEU,iBAAiBE,EAAgD,CACzE,OAAOA,EAAO,WAAW,CAC3B,CACF,ECvDO,IAAeC,EAAf,KAA0B,CAG/B,YAAYC,EAAU,CACpB,KAAK,IAAMA,CACb,CAMA,QAAc,CACZ,OAAO,KAAK,GACd,CA8BA,wBAAwBC,EAAgC,CACtD,GAAI,OAAO,QAAW,aAAe,CAAC,OAAO,qBAC3C,OAGF,IAAMC,EAAY,KAAK,aAAa,EACpC,GAAI,CAACA,EACH,OAGF,IAAMC,EAAW,IAAI,qBAClBC,GAAY,CACXA,EAAQ,QAASC,GAAU,CACrBA,EAAM,iBACRJ,EAAa,EACbE,EAAS,WAAW,EAExB,CAAC,CACH,EACA,CAAE,UAAW,EAAI,CACnB,EAEAA,EAAS,QAAQD,CAAS,EAG1B,IAAMI,EAAU,IAAMH,EAAS,WAAW,EACpCI,EAAkB,KAAK,QAAQ,KAAK,IAAI,EAC9C,KAAK,QAAU,IAAM,CACnBD,EAAQ,EACRC,EAAgB,CAClB,CACF,CAsCF,ECjIO,IAAMC,EAAN,cAA8BC,CAAW,CAI9C,YAAYC,EAAU,CACpB,MAAMA,CAAG,EAHX,KAAQ,WAAgC,CAAC,CAIzC,CAEA,WAAWC,EAKR,CACD,YAAK,cAAgB,IAAIC,EAAsB,CAC7C,YAAa,KAAK,IAClB,WAAYD,EAAQ,WACpB,cAAeA,EAAQ,aACzB,CAAC,EAEGA,EAAQ,WACV,KAAK,qBAAqBA,EAAQ,SAAS,EAGzCA,EAAQ,cACV,KAAK,qBAAqBA,EAAQ,YAAY,EAGzC,KAAK,aACd,CAEQ,qBAAqBE,EAA2C,CACtE,GAAI,CAAC,KAAK,KAAO,OAAO,KAAK,IAAI,IAAO,WACtC,OAGF,IAAMC,EAAgB,IAAM,CAC1B,IAAMC,EAAS,KAAK,aAAa,EACjCF,EAAaE,CAAM,CACrB,EAGMC,EAAa,IAAM,CACvB,IAAMD,EAAS,KAAK,aAAa,EACjCF,EAAaE,CAAM,CACrB,EAEI,KAAK,IAAI,QAAU,KAAK,IAAI,OAAO,EACrCC,EAAW,GAEX,KAAK,IAAI,KAAK,OAAQA,CAAU,EAChC,KAAK,WAAW,KAAK,IAAM,CACrB,OAAO,KAAK,IAAI,KAAQ,YAC1B,KAAK,IAAI,IAAI,OAAQA,CAAU,CAEnC,CAAC,GAGH,KAAK,IAAI,GAAG,UAAWF,CAAa,EACpC,KAAK,WAAW,KAAK,IAAM,CACrB,OAAO,KAAK,IAAI,KAAQ,YAC1B,KAAK,IAAI,IAAI,UAAWA,CAAa,CAEzC,CAAC,CACH,CAEQ,qBAAqBG,EAAuB,CAClD,GAAI,CAAC,KAAK,KAAO,OAAO,KAAK,IAAI,IAAO,WACtC,OAEa,CAAC,OAAQ,OAAQ,UAAW,QAAS,QAAQ,EACrD,QAASC,GAAc,CAC5B,KAAK,IAAI,GAAGA,EAAWD,CAAS,EAChC,KAAK,WAAW,KAAK,IAAM,CACrB,OAAO,KAAK,IAAI,KAAQ,YAC1B,KAAK,IAAI,IAAIC,EAAWD,CAAS,CAErC,CAAC,CACH,CAAC,CACH,CAEA,kBAAmB,CACjB,OAAO,KAAK,aACd,CAEA,cAAmC,CAzFrC,IAAAE,EAAAC,EA0FI,QAAOA,GAAAD,EAAA,KAAK,MAAL,YAAAA,EAAU,eAAV,YAAAC,EAAA,KAAAD,KAA8B,IACvC,CAEA,SAAU,CACR,QAAWE,KAAW,KAAK,WACzB,GAAI,CACFA,EAAQ,CACV,MAAQ,CAER,CAEF,KAAK,WAAW,OAAS,CAC3B,CAEA,QAAc,CACZ,OAAO,KAAK,GACd,CAEA,WAAoB,CAClB,IAAMC,EAAS,KAAK,IAAI,UAAU,EAClC,MAAO,CAAE,IAAKA,EAAO,IAAK,IAAKA,EAAO,GAAI,CAC5C,CAEA,SAAkB,CAChB,OAAO,KAAK,IAAI,QAAQ,CAC1B,CAEA,YAAqB,CACnB,OAAO,KAAK,IAAI,WAAW,CAC7B,CAEA,UAAmB,CACjB,OAAO,KAAK,IAAI,SAAS,CAC3B,CAEA,cAA0B,CACxB,IAAMP,EAAS,KAAK,IAAI,UAAU,EAC5BQ,EAAKR,EAAO,aAAa,EACzBS,EAAKT,EAAO,aAAa,EAC/B,MAAO,CACL,GAAI,CAAE,IAAKQ,EAAG,IAAK,IAAKA,EAAG,GAAI,EAC/B,GAAI,CAAE,IAAKC,EAAG,IAAK,IAAKA,EAAG,GAAI,CACjC,CACF,CAEA,QAAQC,EAA0B,CAChC,OAAO,KAAK,IAAI,QAAQ,CAAE,IAAKA,EAAO,CAAC,EAAG,IAAKA,EAAO,CAAC,CAAE,CAAC,CAC5D,CAEA,GAAGC,EAAeC,EAAyC,CACzD,KAAK,IAAI,GAAGD,EAAOC,CAAO,CAC5B,CAEA,IAAID,EAAeC,EAAyC,CAC1D,KAAK,IAAI,IAAID,EAAOC,CAAO,CAC7B,CAEA,QAAe,CACb,KAAK,IAAI,OAAO,CAClB,CAEA,QAAe,CACb,KAAK,QAAQ,EACb,KAAK,IAAI,OAAO,CAClB,CACF,ECpJO,IAAMC,EAAN,cAAgCC,CAAW,CAKhD,YAAYC,EAAU,CACpB,MAAMA,CAAG,EAHX,KAAQ,WAAgC,CAAC,EAIvC,KAAK,sBAAsB,CAC7B,CAEA,WAAWC,EAKR,CACD,YAAK,cAAgB,IAAIC,EAAwB,CAC/C,YAAa,KAAK,IAClB,OAAQD,EAAQ,OAChB,cAAeA,EAAQ,aACzB,CAAC,EAEGA,EAAQ,WACV,KAAK,qBAAqBA,EAAQ,SAAS,EAGzCA,EAAQ,cACV,KAAK,qBAAqBA,EAAQ,aAAcA,EAAQ,MAAM,EAGzD,KAAK,aACd,CAEQ,qBACNE,EACAC,EACA,CACA,GAAI,CAAC,KAAK,IACR,OAGF,IAAMC,EAAa,IAAM,CACvB,IAAMC,EAAS,KAAK,aAAa,EACjCH,EAAaG,CAAM,CACrB,EAGAD,EAAW,EAEX,IAAME,EAAWH,EAAO,MAAM,YAAY,KAAK,IAAK,OAAQC,CAAU,EACtE,KAAK,WAAW,KAAK,IAAM,CACzBD,EAAO,MAAM,eAAeG,CAAQ,CACtC,CAAC,CACH,CAEQ,qBAAqBC,EAAuB,CAClD,IAAMC,EAAS,CACb,iBACA,eACA,OACA,kBACA,cACF,EACMC,EAAmB,CAAC,EAE1BD,EAAO,QAASE,GAAc,CAC5B,IAAMJ,EAAW,KAAK,IAAI,YAAYI,EAAWH,CAAS,EAC1DE,EAAU,KAAKH,CAAQ,CACzB,CAAC,EAED,KAAK,WAAW,KAAK,IAAM,CACzBG,EAAU,QAASH,GAAa,CAC9B,GAAI,CACFA,EAAS,OAAO,CAClB,MAAQ,CAER,CACF,CAAC,CACH,CAAC,CACH,CAEA,kBAAmB,CACjB,OAAO,KAAK,aACd,CAEA,cAAmC,CA5FrC,IAAAK,EAAAC,EA6FI,QAAOA,GAAAD,EAAA,KAAK,MAAL,YAAAA,EAAU,SAAV,YAAAC,EAAA,KAAAD,KAAwB,IACjC,CAEA,SAAU,CACR,QAAWE,KAAW,KAAK,WACzB,GAAI,CACFA,EAAQ,CACV,MAAQ,CAER,CAEF,KAAK,WAAW,OAAS,CAC3B,CAEQ,uBAAwB,CA3GlC,IAAAF,EA4GI,IAAMG,GAAcH,EAAA,WAAmB,SAAnB,YAAAA,EAA2B,KAC/C,GAAI,CAACG,EAAY,OAGjB,IAAMC,EAAcD,EAAW,YAC1BC,IAEL,KAAK,YAAc,IAAIA,EACvB,KAAK,YAAY,KAAO,UAAY,CAAC,EACrC,KAAK,YAAY,OAAO,KAAK,GAAG,EAClC,CAEA,QAAc,CACZ,OAAO,KAAK,GACd,CAEA,WAAoB,CAClB,IAAMC,EAAS,KAAK,IAAI,UAAU,EAClC,OAAKA,EAGE,CAAE,IAAKA,EAAO,IAAI,EAAG,IAAKA,EAAO,IAAI,CAAE,EAFrC,CAAE,IAAK,EAAG,IAAK,CAAE,CAG5B,CAEA,SAAkB,CApIpB,IAAAL,EAqII,OAAOA,EAAA,KAAK,IAAI,QAAQ,IAAjB,KAAAA,EAAsB,CAC/B,CAEA,YAAqB,CAxIvB,IAAAA,EAyII,OAAOA,EAAA,KAAK,IAAI,WAAW,IAApB,KAAAA,EAAyB,CAClC,CAEA,UAAmB,CA5IrB,IAAAA,EA6II,OAAOA,EAAA,KAAK,IAAI,QAAQ,IAAjB,KAAAA,EAAsB,CAC/B,CAEA,cAA0B,CACxB,IAAMN,EAAS,KAAK,IAAI,UAAU,EAClC,GAAI,CAACA,EACH,MAAO,CACL,GAAI,CAAE,IAAK,EAAG,IAAK,CAAE,EACrB,GAAI,CAAE,IAAK,EAAG,IAAK,CAAE,CACvB,EAEF,IAAMY,EAAKZ,EAAO,aAAa,EACzBa,EAAKb,EAAO,aAAa,EAC/B,MAAO,CACL,GAAI,CAAE,IAAKY,EAAG,IAAI,EAAG,IAAKA,EAAG,IAAI,CAAE,EACnC,GAAI,CAAE,IAAKC,EAAG,IAAI,EAAG,IAAKA,EAAG,IAAI,CAAE,CACrC,CACF,CAEA,QAAQC,EAAoD,CAhK9D,IAAAR,EAiKI,GAAI,CAAC,KAAK,YACR,MAAO,CAAE,EAAG,EAAG,EAAG,CAAE,EAGtB,IAAMS,EAAa,KAAK,YAAY,cAAc,EAClD,GAAI,CAACA,EACH,MAAO,CAAE,EAAG,EAAG,EAAG,CAAE,EAGtB,IAAMN,GAAcH,EAAA,WAAmB,SAAnB,YAAAA,EAA2B,KAC/C,GAAI,CAACG,EACH,MAAO,CAAE,EAAG,EAAG,EAAG,CAAE,EAGtB,IAAMO,EAAS,IAAIP,EAAW,OAAOK,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,EACnDG,EAAQF,EAAW,2BAA2BC,CAAM,EAE1D,OAAKC,EAIE,CACL,EAAGA,EAAM,EACT,EAAGA,EAAM,CACX,EANS,CAAE,EAAG,EAAG,EAAG,CAAE,CAOxB,CAEA,GAAGC,EAAeC,EAAyC,CACzD,KAAK,IAAI,YAAYD,EAAOC,CAAO,CACrC,CAEA,IAAID,EAAeC,EAAyC,CAhM9D,IAAAb,EAiMI,IAAMG,GAAcH,EAAA,WAAmB,SAAnB,YAAAA,EAA2B,KAC3CG,GAAA,MAAAA,EAAY,OACdA,EAAW,MAAM,eAAe,KAAK,IAAKS,CAAK,CAEnD,CAEA,QAAe,CAvMjB,IAAAZ,EAwMI,IAAMG,GAAcH,EAAA,WAAmB,SAAnB,YAAAA,EAA2B,KAC3CG,GAAA,MAAAA,EAAY,OACdA,EAAW,MAAM,QAAQ,KAAK,IAAK,QAAQ,CAE/C,CAEA,QAAe,CACb,KAAK,QAAQ,EAET,KAAK,cACP,KAAK,YAAY,OAAO,IAAI,EAC5B,KAAK,YAAc,KAIvB,CACF,ECpNO,IAAMW,EAAN,cAA4BC,CAAW,CAI5C,YAAYC,EAAU,CACpB,MAAMA,CAAG,EAHX,KAAQ,WAAgC,CAAC,CAIzC,CAEA,WAAWC,EAKR,CACD,YAAK,cAAgB,IAAIC,EAAoB,CAC3C,YAAa,KAAK,IAClB,SAAUD,EAAQ,SAClB,cAAeA,EAAQ,aACzB,CAAC,EAEGA,EAAQ,WACV,KAAK,qBAAqBA,EAAQ,SAAS,EAGzCA,EAAQ,cACV,KAAK,qBAAqBA,EAAQ,YAAY,EAGzC,KAAK,aACd,CAEQ,qBAAqBE,EAA2C,CACtE,GAAI,CAAC,KAAK,KAAO,OAAO,KAAK,IAAI,IAAO,WACtC,OAGF,IAAMC,EAAgB,IAAM,CAC1B,IAAMC,EAAS,KAAK,aAAa,EACjCF,EAAaE,CAAM,CACrB,EAGMC,EAAa,IAAM,CACvB,IAAMD,EAAS,KAAK,aAAa,EAEjCF,EAAaE,CAAM,CACrB,EAEI,KAAK,IAAI,QAAU,KAAK,IAAI,OAAO,EACrCC,EAAW,GAEX,KAAK,IAAI,KAAK,OAAQA,CAAU,EAChC,KAAK,WAAW,KAAK,IAAM,CACrB,OAAO,KAAK,IAAI,KAAQ,YAC1B,KAAK,IAAI,IAAI,OAAQA,CAAU,CAEnC,CAAC,GAGH,KAAK,IAAI,GAAG,UAAWF,CAAa,EACpC,KAAK,WAAW,KAAK,IAAM,CACrB,OAAO,KAAK,IAAI,KAAQ,YAC1B,KAAK,IAAI,IAAI,UAAWA,CAAa,CAEzC,CAAC,CACH,CAEQ,qBAAqBG,EAAuB,CAClD,GAAI,CAAC,KAAK,KAAO,OAAO,KAAK,IAAI,IAAO,WACtC,OAEa,CAAC,OAAQ,OAAQ,UAAW,QAAS,QAAQ,EACrD,QAASC,GAAc,CAC5B,KAAK,IAAI,GAAGA,EAAWD,CAAS,EAChC,KAAK,WAAW,KAAK,IAAM,CACrB,OAAO,KAAK,IAAI,KAAQ,YAC1B,KAAK,IAAI,IAAIC,EAAWD,CAAS,CAErC,CAAC,CACH,CAAC,CACH,CAEA,kBAAmB,CACjB,OAAO,KAAK,aACd,CAEA,cAAmC,CA1FrC,IAAAE,EAAAC,EA2FI,QAAOA,GAAAD,EAAA,KAAK,MAAL,YAAAA,EAAU,eAAV,YAAAC,EAAA,KAAAD,KAA8B,IACvC,CAEA,SAAU,CACR,QAAWE,KAAW,KAAK,WACzB,GAAI,CACFA,EAAQ,CACV,MAAQ,CAER,CAEF,KAAK,WAAW,OAAS,CAC3B,CAEA,QAAc,CACZ,OAAO,KAAK,GACd,CAEA,WAAoB,CAClB,IAAMC,EAAS,KAAK,IAAI,UAAU,EAClC,MAAO,CAAE,IAAKA,EAAO,IAAK,IAAKA,EAAO,GAAI,CAC5C,CAEA,SAAkB,CAChB,OAAO,KAAK,IAAI,QAAQ,CAC1B,CAEA,YAAqB,CACnB,OAAO,KAAK,IAAI,WAAW,CAC7B,CAEA,UAAmB,CACjB,OAAO,KAAK,IAAI,SAAS,CAC3B,CAEA,cAA0B,CACxB,IAAMP,EAAS,KAAK,IAAI,UAAU,EAC5BQ,EAAKR,EAAO,aAAa,EACzBS,EAAKT,EAAO,aAAa,EAC/B,MAAO,CACL,GAAI,CAAE,IAAKQ,EAAG,IAAK,IAAKA,EAAG,GAAI,EAC/B,GAAI,CAAE,IAAKC,EAAG,IAAK,IAAKA,EAAG,GAAI,CACjC,CACF,CAEA,QAAQC,EAA0B,CAChC,OAAO,KAAK,IAAI,QAAQ,CAAE,IAAKA,EAAO,CAAC,EAAG,IAAKA,EAAO,CAAC,CAAE,CAAC,CAC5D,CAEA,GAAGC,EAAeC,EAAyC,CACzD,KAAK,IAAI,GAAGD,EAAOC,CAAO,CAC5B,CAEA,IAAID,EAAeC,EAAyC,CAC1D,KAAK,IAAI,IAAID,EAAOC,CAAO,CAC7B,CAEA,QAAe,CACb,KAAK,IAAI,OAAO,CAClB,CAEA,QAAe,CACb,KAAK,QAAQ,EACb,KAAK,IAAI,OAAO,CAClB,CACF,ECnHO,SAASC,EAAiBC,EAA4C,CAC3E,IAAMC,EAASD,EAAY,UAAU,EACrC,MAAO,CACL,UAAWC,EAAO,IAClB,SAAUA,EAAO,IACjB,KAAMD,EAAY,QAAQ,EAC1B,QAASA,EAAY,WAAW,EAChC,MAAOA,EAAY,SAAS,CAC9B,CACF,CAEA,IAAME,GAGD,CACH,CAAE,KAAM,EAAG,UAAW,GAAI,EAC1B,CAAE,KAAM,EAAG,UAAW,GAAI,EAC1B,CAAE,KAAM,GAAI,UAAW,EAAG,EAC1B,CAAE,KAAM,GAAI,UAAW,EAAG,EAC1B,CAAE,KAAM,GAAI,UAAW,EAAG,EAC1B,CAAE,KAAM,GAAI,UAAW,EAAG,CAC5B,EAEA,SAASC,EAA0BC,EAAc,CAC/C,QAAWC,KAAcH,GACvB,GAAIE,GAAQC,EAAW,KACrB,OAAOA,EAAW,UAGtB,MAAO,GACT,CAEO,SAASC,EAAe,CAC7B,YAAAC,EACA,QAAAC,EACA,IAAAC,EACA,iBAAAC,EACA,KAAAN,EACA,qBAAAO,EACA,wBAAAC,CACF,EAAwC,CACtC,GAAI,CAACJ,EAAQ,OAAQ,MAAO,CAAC,EAC7B,GAAI,CAACC,EACH,OAAOD,EAAQ,IAAKK,IAAY,CAC9B,KAAM,UACN,OAAAA,EACA,IAAK,WAAWA,EAAO,cAAc,EACvC,EAAE,EAGJ,IAAMC,EAA+BN,EAClC,IAAI,CAACK,EAAQE,IAAU,CACtB,IAAMC,EAAWH,EAAO,SACxB,GACE,OAAOG,GAAA,YAAAA,EAAU,MAAQ,UACzB,OAAOA,GAAA,YAAAA,EAAU,MAAQ,SAEzB,OAAO,KAET,GAAM,CAAE,EAAAC,EAAG,EAAAC,CAAE,EAAIT,EAAI,QAAQ,CAACO,EAAS,IAAKA,EAAS,GAAG,CAAC,EACzD,MAAO,CAAE,OAAAH,EAAQ,MAAAE,EAAO,EAAAE,EAAG,EAAAC,CAAE,CAC/B,CAAC,EACA,OAAQC,GAAoC,EAAQA,CAAM,EAE7D,GAAI,CAACL,EAAU,OACb,MAAO,CAAC,EAGV,IAAMM,EAAYjB,EAA0BC,CAAI,EAC1CiB,EAAeC,GAA6BlB,CAAI,EAChDmB,EAAST,EAAU,IAAI,CAACU,EAAGC,IAAQA,CAAG,EAEtCC,EAAQC,GACRJ,EAAOI,CAAC,IAAMA,EAAUA,GAC5BJ,EAAOI,CAAC,EAAID,EAAKH,EAAOI,CAAC,CAAC,EACnBJ,EAAOI,CAAC,GAGXC,EAAQ,CAACC,EAAWC,IAAc,CACtC,IAAMC,EAAQL,EAAKG,CAAC,EACdG,EAAQN,EAAKI,CAAC,EAChBC,IAAUC,IACdT,EAAOS,CAAK,EAAID,EAClB,EAEA,QAASJ,EAAI,EAAGA,EAAIb,EAAU,OAAQa,GAAK,EACzC,QAASM,EAAIN,EAAI,EAAGM,EAAInB,EAAU,OAAQmB,GAAK,EAAG,CAChD,IAAMC,EAAKpB,EAAUa,CAAC,EAAE,EAAIb,EAAUmB,CAAC,EAAE,EACnCE,EAAKrB,EAAUa,CAAC,EAAE,EAAIb,EAAUmB,CAAC,EAAE,EACrC,KAAK,MAAMC,EAAIC,CAAE,GAAKf,GACxBQ,EAAMD,EAAGM,CAAC,CAEd,CAGF,IAAMG,EAAS,IAAI,IACnB,QAAWC,KAAQvB,EAAW,CAC5B,IAAMwB,EAAOZ,EAAKW,EAAK,KAAK,EACtBE,EAAQH,EAAO,IAAIE,CAAI,EACzBC,EACFA,EAAM,KAAKF,CAAI,EAEfD,EAAO,IAAIE,EAAM,CAACD,CAAI,CAAC,CAE3B,CAEA,IAAMG,EAAkC,CAAC,EAEzC,OAAAJ,EAAO,QAASK,GAAe,CArJjC,IAAAC,EAAAC,EAsJI,GAAIF,EAAW,SAAW,EAAG,CAC3B,GAAM,CAAC,CAAE,OAAA5B,CAAO,CAAC,EAAI4B,EACfG,EAAY/B,EAAO,OAASN,EAC5BsC,EAAanC,IAAqBG,EAAO,eAC/C2B,EAAU,KAAK,CACb,KAAM,UACN,OAAA3B,EACA,IAAK,WAAWA,EAAO,cAAc,KAAK+B,EAAY,EAAI,CAAC,KACzDC,EAAa,EAAI,CACnB,KAAIH,EAAA7B,EAAO,UAAP,YAAA6B,EAAgB,YAAY,EAClC,CAAC,EACD,MACF,CAEA,IAAMI,EAAS,CAAC,GAAGL,CAAU,EAAE,KAAK,CAACZ,EAAGC,IACtCiB,GAAejB,EAAE,OAAQD,EAAE,OAAQtB,CAAW,CAChD,EACM,CAACyC,EAAS,GAAGC,CAAI,EAAIH,EACrBI,EAAmBF,EAAQ,OAAO,OAASzC,EAC3C4C,EACJzC,IAAqBsC,EAAQ,OAAO,eAStC,GARAR,EAAU,KAAK,CACb,KAAM,UACN,OAAQQ,EAAQ,OAChB,IAAK,WAAWA,EAAQ,OAAO,cAAc,KAC3CE,EAAmB,EAAI,CACzB,KAAKC,EAAoB,EAAI,CAAC,KAAIR,EAAAK,EAAQ,OAAO,UAAf,YAAAL,EAAwB,YAAY,EACxE,CAAC,EAEG,CAACM,EAAK,OAAQ,OAElB,IAAMG,EAAmC,CAAC,EACpCC,EAA+B,CAAC,EAkCtC,GAhCAJ,EAAK,QAASZ,GAAS,CAxL3B,IAAAK,EAyLM,GAAIhC,GAAoB2B,EAAK,OAAO,iBAAmB3B,EAAkB,CACvE,IAAMkC,EAAYP,EAAK,OAAO,OAAS9B,EACvCiC,EAAU,KAAK,CACb,KAAM,UACN,OAAQH,EAAK,OACb,IAAK,WAAWA,EAAK,OAAO,cAAc,KACxCO,EAAY,EAAI,CAClB,QAAOF,EAAAL,EAAK,OAAO,UAAZ,YAAAK,EAAqB,YAAY,EAC1C,CAAC,EACD,MACF,CAEIY,GAAWN,EAASX,CAAI,GAAKhB,EAC/B+B,EAAc,KAAKf,CAAI,EAEvBgB,EAAU,KAAKhB,CAAI,CAEvB,CAAC,EAEDe,EAAc,QAASf,GAAS,CA5MpC,IAAAK,EA6MM,IAAME,EAAYP,EAAK,OAAO,OAAS9B,EACvCiC,EAAU,KAAK,CACb,KAAM,MACN,OAAQH,EAAK,OACb,IAAK,OAAOA,EAAK,OAAO,cAAc,KAAKO,EAAY,EAAI,CAAC,QAC1DF,EAAAL,EAAK,OAAO,UAAZ,YAAAK,EAAqB,YACvB,GACA,SAAUM,EAAQ,OAAO,cAC3B,CAAC,CACH,CAAC,EAEGK,EAAU,OAAQ,CACpB,IAAME,EAAWjD,EAAe,CAC9B,QAAS+C,EAAU,IAAKhB,GAASA,EAAK,MAAM,EAC5C,IAAA5B,EACA,iBAAAC,EACA,KAAAN,EACA,YAAAG,EACA,qBAAAI,EACA,wBAAAC,CACF,CAAC,EACD4B,EAAU,KAAK,GAAGe,CAAQ,CAC5B,CACF,CAAC,EAEMf,CACT,CAEA,SAASc,GAAWzB,EAAoBC,EAAoB,CAC1D,OAAO,KAAK,MAAMD,EAAE,EAAIC,EAAE,EAAGD,EAAE,EAAIC,EAAE,CAAC,CACxC,CAEA,SAASR,GAA6BlB,EAAc,CAClD,IAAMoD,EAAOrD,EAA0BC,CAAI,EAC3C,OAAO,KAAK,IAAI,GAAIoD,CAAI,CAC1B,CAEA,SAAST,GAAelB,EAAaC,EAAavB,EAA2B,CAlP7E,IAAAmC,EAAAC,EAmPE,IAAMc,EAAa5B,EAAE,OAAStB,EACxBmD,EAAa5B,EAAE,OAASvB,EAC9B,GAAIkD,GAAc,CAACC,EAAY,MAAO,GACtC,GAAI,CAACD,GAAcC,EAAY,MAAO,GAEtC,IAAMC,EAAaC,EAAc/B,CAAC,EAAI+B,EAAc9B,CAAC,EACrD,GAAI6B,IAAe,EAAG,OAAOA,EAE7B,IAAME,EAAYC,EAAajC,CAAC,EAAIiC,EAAahC,CAAC,EAClD,GAAI+B,IAAc,EAAG,OAAOA,EAE5B,IAAME,IAAerB,EAAAb,EAAE,UAAF,KAAAa,EAAa,KAAMC,EAAAb,EAAE,UAAF,KAAAa,EAAa,GACrD,OAAIoB,IAAgB,EAAUA,EAEvBlC,EAAE,eAAiBC,EAAE,cAC9B,CAEA,SAAS8B,EAAc/C,EAAkB,CACvC,GAAI,OAAOA,EAAO,QAAW,SAAU,OAAOA,EAAO,OACrD,GAAIA,EAAO,SAAW,QAAaA,EAAO,SAAW,KAAM,MAAO,KAClE,IAAMmD,EAAS,OAAOnD,EAAO,MAAM,EACnC,OAAO,OAAO,MAAMmD,CAAM,EAAI,KAAYA,CAC5C,CAEA,SAASF,EAAajD,EAAkB,CA3QxC,IAAA6B,EAAAC,EAAAsB,EA4QE,GAAI,GAACtB,GAAAD,EAAA7B,EAAO,UAAP,YAAA6B,EAAgB,QAAhB,MAAAC,EAAuB,OAAO,MAAO,KAC1C,IAAMuB,EAAU,SACbD,EAAApD,EAAO,QAAQ,MAAM,eAArB,KAAAoD,EAAqC,KACnC,QAAQ,cAAe,EAAE,EACzB,QAAQ,KAAM,EAAE,CACrB,EACA,OAAO,OAAO,MAAMC,CAAO,EAAI,KAAYA,CAC7C,CCpPO,SAASC,GACdC,EACe,CACf,IAAMC,EAAyB,CAAC,EAGhC,OAAID,EAAW,WAAa,MAAM,QAAQA,EAAW,SAAS,GAC5DA,EAAW,UAAU,QAASE,GAAoB,CAChDD,EAAQ,KAAK,CACX,GAAI,WAAWC,CAAO,GACtB,MAAOA,EACP,KAAM,UACN,MAAOA,CACT,CAAC,CACH,CAAC,EAICF,EAAW,YAAc,MAAM,QAAQA,EAAW,UAAU,GAC9DA,EAAW,WAAW,QAASG,GAAkB,CAC/CF,EAAQ,KAAK,CACX,GAAI,cAAcE,CAAK,GACvB,MAAOA,EACP,KAAM,aACN,MAAOA,CACT,CAAC,CACH,CAAC,EAICH,EAAW,OACbC,EAAQ,KAAK,CACX,GAAI,aACJ,MAAO,cACP,KAAM,aACN,MAAO,GAAGD,EAAW,MAAM,GAAG,IAAIA,EAAW,MAAM,GAAG,GACtD,WAAYA,EAAW,KACzB,CAAC,EAKD,OAAOA,EAAW,WAAc,UAChC,OAAO,SAASA,EAAW,SAAS,GAEpCC,EAAQ,KAAK,CACX,GAAI,YACJ,MAAO,GAAGD,EAAW,SAAS,IAC9B,KAAM,YACN,MAAO,OAAOA,EAAW,SAAS,EAClC,aAAcA,EAAW,SAC3B,CAAC,EAKD,OAAOA,EAAW,YAAe,UACjC,OAAO,SAASA,EAAW,UAAU,GAErCC,EAAQ,KAAK,CACX,GAAI,aACJ,MAAO,GAAGD,EAAW,UAAU,SAC/B,KAAM,aACN,MAAO,OAAOA,EAAW,UAAU,EACnC,aAAcA,EAAW,UAC3B,CAAC,EAICA,EAAW,mBACbC,EAAQ,KAAK,CACX,GAAI,oBACJ,MAAOD,EAAW,kBAClB,KAAM,oBACN,MAAOA,EAAW,iBACpB,CAAC,EAICA,EAAW,kCACbC,EAAQ,KAAK,CACX,GAAI,mCACJ,MAAOD,EAAW,iCAAiC,KAAK,IAAI,EAC5D,KAAM,mCACN,MAAOA,EAAW,iCAAiC,KAAK,IAAI,EAC5D,YAAaA,EAAW,gCAC1B,CAAC,EAGIC,CACT,CAmBO,SAASG,GAAoBH,EAA+B,CACjE,OAAOA,EAAQ,IAAKI,GAAW,CAC7B,IAAMC,EAAyB,CAC7B,GAAID,EAAO,GACX,MACE,OAAOA,EAAO,OAAU,SACpBA,EAAO,MACP,OAAOA,EAAO,OAAS,EAAE,EAC/B,KAAMA,EAAO,KACb,MAAOA,EAAO,KAChB,EAMA,GAJIA,EAAO,eAAiB,SAC1BC,EAAU,aAAeD,EAAO,cAG9BA,EAAO,WAAY,CAErB,IAAME,EAAMF,EAAO,WAAW,IACxBG,EAAMH,EAAO,WAAW,IAC1BE,IAAQ,SACVD,EAAU,WAAa,CACrB,IAAAC,EACA,GAAIC,IAAQ,QAAa,CAAE,IAAAA,CAAI,CACjC,EAEJ,CAEA,OAAIH,EAAO,cACTC,EAAU,YAAcD,EAAO,aAG1BC,CACT,CAAC,CACH,CC1GA,IAAMG,GAAwC,CAC5C,KAAM,0BACN,KAAM,8BACR,EAGaC,EAAN,cAAmC,KAAM,CAI9C,YAAY,CACV,QAAAC,EACA,OAAAC,EACA,KAAAC,CACF,EAIG,CACD,MAAMF,CAAO,EACb,KAAK,KAAO,uBACZ,KAAK,OAASC,EACd,KAAK,KAAOC,CACd,CACF,EAaA,eAAsBC,GACpBC,EACAC,EACAC,EACA,CAAE,OAAAC,CAAO,EAA4B,CAAC,EAClB,CA9GtB,IAAAC,EAAAC,EA+GE,IAAMC,EAAW,MAAM,MAAMN,EAAK,CAChC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,GAAIE,GAAU,CACZ,YAAaA,CACf,CACF,EACA,KAAM,KAAK,UAAUD,CAAI,EACzB,OAAAE,CACF,CAAC,EAED,GAAI,CAACG,EAAS,GAAI,CAChB,IAAIV,EAAU,wBAAwBU,EAAS,MAAM,GACjDR,EACJ,GAAI,CACF,IAAMS,EAAa,MAAMD,EAAS,KAAK,EACvCV,GAAUS,GAAAD,EAAAG,EAAU,SAAV,KAAAH,EAAoBG,EAAU,QAA9B,KAAAF,EAAuCT,EACjDE,EAAOS,EAAU,IACnB,MAAQ,CAER,CACA,MAAM,IAAIZ,EAAqB,CAAE,QAAAC,EAAS,OAAQU,EAAS,OAAQ,KAAAR,CAAK,CAAC,CAC3E,CAEA,OAAQ,MAAMQ,EAAS,KAAK,CAC9B,CAEA,SAASE,GAAMC,EAA6B,CAC1C,OAAI,OAAOA,GAAS,SAAiBA,EAC9BA,EAAK,YAAY,EAAE,MAAM,EAAG,EAAE,CACvC,CAwFA,IAAMC,GAAqC,gBAG3C,SAASC,IAAqD,CAE5D,IAAMC,EAAO,IAAI,KAAK,KAAK,IAAI,EAAI,KAAU,EACvCC,GAAqB,EAAID,EAAK,OAAO,EAAI,GAAK,EAC9CE,EAAU,IAAI,KAAKF,EAAK,QAAQ,EAAIC,EAAoB,KAAK,EAC7DE,EAAWD,EAAQ,OAAO,EAC1BE,EAAmBD,IAAa,EAAI,EAAI,EAAIA,EAC5CE,EAAW,IAAI,KAAKH,EAAQ,QAAQ,GAAKE,EAAmB,GAAK,KAAK,EAC5E,MAAO,CAAE,QAAAF,EAAS,SAAAG,CAAS,CAC7B,CAEO,IAAMC,GAAN,KAAmB,CA2BxB,YAA6BC,EAA0B,CAA1B,aAAAA,EA1B7B,KAAQ,QAA6B,KACrC,KAAQ,WAAyB,CAAC,EAElC,KAAQ,iBAAkC,KAC1C,KAAQ,UAAY,GACpB,KAAQ,aAAqC,CAAC,EAC9C,KAAQ,cAAgB,GA3P1B,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EA6RI,GAbA,KAAK,WAAa,CAAC,IAAIf,EAAAD,EAAQ,aAAR,KAAAC,EAAsB,CAAC,CAAE,EAChD,KAAK,YAAcD,EAAQ,YAC3B,KAAK,kBAAmBE,EAAAF,EAAQ,mBAAR,KAAAE,EAA4B,KAGpD,KAAK,QAASC,EAAAH,EAAQ,SAAR,KAAAG,EAAkB,GAChC,KAAK,aAAcC,EAAAJ,EAAQ,cAAR,KAAAI,EAAuB,OAC1C,KAAK,QAASC,EAAAL,EAAQ,SAAR,KAAAK,EAAkBY,GAAS,KAAK,WAAW,EACzD,KAAK,OAASjB,EAAQ,OACtB,KAAK,YAAcA,EAAQ,YAC3B,KAAK,gBAAkBA,EAAQ,SAG3B,CAAC,KAAK,QAAUA,EAAQ,UAAYA,EAAQ,WAAa,WAC3D,MAAM,IAAI,MACR,sGACF,EAIF,IAAMkB,EAAeC,GAAoBnB,CAAO,EAGhD,KAAK,iBAAmB,CACtB,KAAKO,GAAAD,EAAAN,EAAQ,mBAAR,YAAAM,EAA0B,MAA1B,KAAAC,EAAkCW,EAAe,EAAI,GAC1D,QAAQT,GAAAD,EAAAR,EAAQ,mBAAR,YAAAQ,EAA0B,SAA1B,KAAAC,EAAqCS,EAAe,EAAI,IAChE,MAAMP,GAAAD,EAAAV,EAAQ,mBAAR,YAAAU,EAA0B,OAA1B,KAAAC,EAAmCO,EAAe,EAAI,GAC5D,OAAOL,GAAAD,EAAAZ,EAAQ,mBAAR,YAAAY,EAA0B,QAA1B,KAAAC,EAAoCK,EAAe,EAAI,EAChE,EAGA,IAAME,EAAe5B,GAAgB,EAGrC,KAAK,MAAQ,CACX,OAAQ,CAAC,EAAG,CAAC,EACb,KAAM,EACN,OAAQ,KACR,cAAe,KACf,WAAY,KACZ,WAAY,KAAK,WACjB,SAASsB,EAAA,KAAK,cAAL,KAAAA,EAAoBvB,GAC7B,mBAAoB,KAAK,iBACzB,eAAgB,GAChB,YAAa,GACb,cAAe,GACf,QAAS,CACP,QAAS6B,EAAa,QACtB,SAAUA,EAAa,SACvB,UAAW,EACX,SAAU,EACV,KAAIL,EAAAf,EAAQ,sBAAR,YAAAe,EAA6B,WAAY,CAC3C,SAAUf,EAAQ,oBAAoB,QACxC,CACF,EACA,eAAgB,CACd,QAAS,GACT,YAAa,KACb,aAAc,GACd,YAAa,CAAC,EAAG,CAAC,CACpB,EACA,iBAAkB,GAClB,GAAGA,EAAQ,KACb,EAEA,KAAK,WAAYgB,EAAAhB,EAAQ,YAAR,KAAAgB,EAAqB,CAAC,EAGnC,KAAK,eAAehB,CAAO,IAC7B,KAAK,QAAU,KAAK,cAAcA,CAAO,EACzC,KAAK,cAAgB,GACrB,KAAK,QAAQ,GAIXA,EAAQ,oBACV,KAAK,2BAA2BA,EAAQ,mBAAmB,EAClD,KAAK,aAAe,KAAK,eAClC,KAAK,mBAAmB,CAE5B,CAEQ,eAAeA,EAAmC,CAExD,MADI,eAAaA,GAAWA,EAAQ,SAChC,gBAAiBA,GAAWA,EAAQ,YAE1C,CAEA,MAAc,2BACZqB,EACe,CACf,GAAI,CAAC,KAAK,OAAQ,CAChB,QAAQ,KACN,oEACF,EACA,MACF,CACA,GAAI,CACF,GAAM,CAAE,KAAAC,EAAM,QAAAC,EAAS,MAAAC,CAAM,EAAIH,EAE7BI,EAAmB,CACrB,QAAS,KAAK,WAAW,EACzB,QAAS,EACX,EAGA,GAAKH,GAAQC,GAAYA,EAAS,CAChC,IAAMG,EAAc,MAAM,MACxB,GAAG,KAAK,MAAM,uBAAuB,mBAAmBH,CAAQ,CAAC,GAC/DD,EAAO,SAAS,mBAAmBA,CAAI,CAAC,GAAK,EAC/C,GACA,CACE,QAAS,CACP,GAAI,KAAK,QAAU,CACjB,YAAa,KAAK,MACpB,CACF,CACF,CACF,EAEA,GAAII,EAAY,GAAI,CAClB,IAAMC,EAAU,MAAMD,EAAY,KAAK,EAEnCE,EAAYN,EAEdK,EAAQ,eACRA,EAAQ,YACRA,EAAQ,gBAAkBA,EAAQ,aAElCC,EAAY,QAEVD,EAAQ,gBAAeC,EAAYD,EAAQ,eAE/C,IAAME,EAAeF,EAAQ,YAAcJ,EAE3CE,EAAc,CACZ,GAAGA,EACH,KAAMG,EACN,QAASC,EACT,YAAaF,EAAQ,YACrB,UAAWA,EAAQ,UACnB,SAAUA,EAAQ,QACpB,EAGA,KAAK,kBAAkB,CACrB,KAAMC,EACN,QAASC,EACT,YAAaF,EAAQ,YACrB,aACEC,GAAaC,EACT,GAAGD,CAAS,KAAKC,CAAY,GAC7BA,GAAgB,GACtB,YAAa,CAACF,EAAQ,SAAUA,EAAQ,SAAS,CACnD,CAAC,EAGD,KAAK,SAAS,CACZ,OAAQ,CAACA,EAAQ,SAAUA,EAAQ,SAAS,EAC5C,KAAM,EACR,CAAC,CACH,MACE,KAAK,YACH,IAAI,MAAM,6BAA6BD,EAAY,UAAU,EAAE,EAC/D,4BACF,CAEJ,MAAWF,IACTC,EAAY,MAAQD,GAGtB,KAAK,YAAcC,EAGf,KAAK,eACP,MAAM,KAAK,mBAAmB,CAElC,OAASK,EAAO,CACd,KAAK,YAAYA,EAAO,4BAA4B,CACtD,CACF,CAEA,MAAc,oBAAoC,CAChD,GAAI,CAAC,KAAK,OAAQ,CAChB,QAAQ,KACN,4DACF,EACA,MACF,CACA,GAAI,CAAC,KAAK,YAAa,OAGvB,IAAMC,EAAyC,CAC7C,QAAS,KAAK,WAAW,EACzB,QAAS,GACT,GAAG,KAAK,WACV,EAEA,MAAM,KAAK,oBAAoB,CAC7B,KAAMA,EACN,QAAUD,GAAU,CAxd1B,IAAA7B,EAAAC,EAydQ,KAAK,YAAY4B,EAAO,oBAAoB,GAC5C5B,GAAAD,EAAA,KAAK,WAAU,wBAAf,MAAAC,EAAA,KAAAD,EAAuC6B,EACzC,CACF,CAAC,CACH,CAEA,UACEE,EACAC,EAOM,CAEN,GAAI,CAAC,KAAK,QAAUA,EAAO,WAAa,WACtC,MAAM,IAAI,MACR,sGACF,EAGF,GAAI,KAAK,gBACP,QAAQ,KAAK,uDAAuD,EAChE,KAAK,SAAS,CAChB,IAAMC,EAAgB,KAAK,QAAQ,iBAAiB,EACpDA,GAAA,MAAAA,EAAe,UACf,KAAK,QAAQ,QAAQ,CACvB,CAGF,IAAMC,EAAqB,CACzB,GAAG,KAAK,QACR,SAAUF,EAAO,SACjB,YAAAD,EACA,WAAYC,EAAO,WACnB,OAAQA,EAAO,OACf,SAAUA,EAAO,SACjB,cAAeA,EAAO,aACxB,EAEA,KAAK,gBAAkBA,EAAO,SAC9B,KAAK,QAAU,KAAK,cAAcE,CAAa,EAC/C,KAAK,cAAgB,GACrB,KAAK,QAAQ,EAGT,KAAK,aAAe,CAAC,KAAK,MAAM,eAClC,KAAK,mBAAmB,CAE5B,CAEQ,cAAcnC,EAA6C,CACjE,OAAIoC,GAAkBpC,CAAO,GAAKA,EAAQ,YACjC,KAAK,kBAAkB,IAAIqC,EAAgBrC,EAAQ,WAAW,EAAG,CACtE,WAAYA,EAAQ,WACpB,cAAeA,EAAQ,aACzB,CAAC,EAECmB,GAAoBnB,CAAO,GAAKA,EAAQ,YACnC,KAAK,kBACV,IAAIsC,EAAkBtC,EAAQ,WAAW,EACzC,CAAE,OAAQA,EAAQ,OAAQ,cAAeA,EAAQ,aAAc,CACjE,EAEEuC,GAAgBvC,CAAO,GAAKA,EAAQ,YAC/B,KAAK,kBAAkB,IAAIwC,EAAcxC,EAAQ,WAAW,EAAG,CACpE,SAAUA,EAAQ,SAClB,cAAeA,EAAQ,aACzB,CAAC,EAEC,YAAaA,GAAWA,EAAQ,QAC3BA,EAAQ,QAEV,IACT,CAEQ,kBAAkByC,EAAqBR,EAAyB,CAviB1E,IAAAhC,EAwiBI,IAAMyC,GAAmBzC,EAAA,KAAK,QAAQ,oBAAb,KAAAA,EAAkC,GAC3D,OAAAwC,EAAQ,WAAW,CACjB,GAAGR,EACH,cAAgBU,GAAqB,CA3iB3C,IAAA1C,EA4iBY0C,EAAO,UACT,KAAK,SAASA,EAAO,SAAS,IAAKA,EAAO,SAAS,IAAK,EAAE,EAIxDA,EAAO,OAAS,KAAK,aACvB,KAAK,eAAeA,EAAO,IAAI,EAE7BD,GACF,KAAK,kBACHC,EAAO,iBAAmB,KAAK,iBAC3B,KACAA,EAAO,cACb,GAEF1C,EAAAgC,EAAO,gBAAP,MAAAhC,EAAA,KAAAgC,EAAuBU,EACzB,EACA,UAAW,IAAM,KAAK,QAAQ,EAC9B,aAAeC,GAAsB,CAE/B,KAAK,MAAM,aAAe,MAC5B,KAAK,cAAcA,CAAM,EACzB,KAAK,iBAAiB,IAAI,GAE1B,KAAK,iBAAiBA,CAAM,CAEhC,CACF,CAAC,EAGG,KAAK,QACPH,EAAQ,wBAAwB,IAAM,CAKpC,QAAQ,IAAI,4BAA4B,CAC1C,CAAC,EAGIA,CACT,CAEA,eAAeI,EAAwB,CAvlBzC,IAAA5C,EAAAC,EAwlBI,KAAK,YAAY,EACjB,KAAK,WAAa,CAChB,GAAG2C,EAAW,OAAQC,GAAG,CA1lB/B,IAAA7C,EA2lBQ,OAAA6C,EAAE,OAAS,kBACP7C,EAAA6C,EAAE,UAAF,YAAA7C,EAAW,gBAAiB,cAC5B,GACN,CACF,EACA,KAAK,YAAY,CACf,WAAY,KAAK,UACnB,CAAC,GACDC,GAAAD,EAAA,KAAK,WAAU,qBAAf,MAAAC,EAAA,KAAAD,EAAoC4C,GACpC,KAAK,QAAQ,CACf,CAEA,YAAYE,EAAoB,CAvmBlC,IAAA9C,EAAAC,EAwmBI,KAAK,YAAY,EACjB,KAAK,WAAa,CAAC,GAAG,KAAK,WAAY6C,CAAQ,EAC/C,KAAK,YAAY,CAAE,WAAY,KAAK,UAAW,CAAC,GAChD7C,GAAAD,EAAA,KAAK,WAAU,qBAAf,MAAAC,EAAA,KAAAD,EAAoC,KAAK,YACzC,KAAK,QAAQ,CACf,CAEA,iBAAkB,CA/mBpB,IAAAA,EAAAC,EAgnBI,KAAK,YAAY,EACjB,KAAK,WAAa,CAAC,EACnB,KAAK,YAAY,CAAE,WAAY,CAAC,CAAE,CAAC,GACnCA,GAAAD,EAAA,KAAK,WAAU,qBAAf,MAAAC,EAAA,KAAAD,EAAoC,CAAC,GACrC,KAAK,QAAQ,CACf,CAEA,eAAe+C,EAAuB,CAvnBxC,IAAA/C,EAAAC,EAwnBI,KAAK,YAAY,EACb,KAAK,cAAgB8C,IACzB,KAAK,YAAcA,EACnB,KAAK,YAAY,CAAE,QAAAA,CAAQ,CAAC,GAC5B9C,GAAAD,EAAA,KAAK,WAAU,sBAAf,MAAAC,EAAA,KAAAD,EAAqC+C,GACrC,KAAK,QAAQ,EACf,CAEA,kBAAkBC,EAAyB,CAhoB7C,IAAAhD,EAAAC,EAkoBI,GADA,KAAK,YAAY,EACb,KAAK,mBAAqB+C,EAG9B,IAAIA,IAAa,KAAM,CACrB,IAAMN,EAAS,KAAK,WAAW,KAAMO,GAAMA,EAAE,iBAAmBD,CAAQ,EACpEN,GAAUA,EAAO,OAAS,KAAK,aACjC,KAAK,eAAeA,EAAO,IAAI,CAEnC,CAEA,KAAK,iBAAmBM,EACxB,KAAK,YAAY,CAAE,mBAAoBA,CAAS,CAAC,GACjD/C,GAAAD,EAAA,KAAK,WAAU,2BAAf,MAAAC,EAAA,KAAAD,EAA0CgD,GAC1C,KAAK,QAAQ,EACf,CAGA,UAA+B,CAC7B,MAAO,CAAE,GAAG,KAAK,KAAM,CACzB,CAGQ,YAAYnB,EAAgBqB,EAAkB,eAAgB,CACpE,IAAMC,EAAetB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACpEuB,EAAWvB,aAAiB,MAAQA,EAAQ,IAAI,MAAMsB,CAAY,EAExE,QAAQ,MAAM,IAAID,CAAO,IAAKC,CAAY,EAEtC,KAAK,UAAU,SACjB,KAAK,UAAU,QAAQC,EAAUF,CAAO,CAE5C,CAEA,YAAYG,EAAwB,CAClC,KAAK,MAAQ,CAAE,GAAG,KAAK,MAAO,GAAGA,CAAO,CAC1C,CAEA,SAASC,EAA6B,CAvqBxC,IAAAtD,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAwqBI,IAAMwC,EAAY,CAAE,GAAG,KAAK,KAAM,EAClC,KAAK,YAAYD,CAAQ,EAGrBA,EAAS,SAAW,QAAaA,EAAS,SAAWC,EAAU,UACjEtD,GAAAD,EAAA,KAAK,WAAU,iBAAf,MAAAC,EAAA,KAAAD,EAAgCsD,EAAS,OAAQ,KAAK,MAAM,OAE1DA,EAAS,OAAS,QAAaA,EAAS,OAASC,EAAU,QAC7DpD,GAAAD,EAAA,KAAK,WAAU,eAAf,MAAAC,EAAA,KAAAD,EAA8BoD,EAAS,OAErCA,EAAS,SAAW,QAAaA,EAAS,SAAWC,EAAU,UACjElD,GAAAD,EAAA,KAAK,WAAU,iBAAf,MAAAC,EAAA,KAAAD,EAAgCkD,EAAS,SAGzCA,EAAS,gBAAkB,QAC3BA,EAAS,gBAAkBC,EAAU,iBAErChD,GAAAD,EAAA,KAAK,WAAU,wBAAf,MAAAC,EAAA,KAAAD,EAAuCgD,EAAS,gBAGhDA,EAAS,UAAY,QACrBA,EAAS,UAAYC,EAAU,WAE/B9C,GAAAD,EAAA,KAAK,WAAU,kBAAf,MAAAC,EAAA,KAAAD,EAAiC8C,EAAS,UAG1CA,EAAS,iBAAmB,QAC5BA,EAAS,iBAAmBC,EAAU,kBAEtC5C,GAAAD,EAAA,KAAK,WAAU,yBAAf,MAAAC,EAAA,KAAAD,EAAwC4C,EAAS,iBAGjDA,EAAS,iBAAmB,QAC5BA,EAAS,iBAAmBC,EAAU,kBAEtC1C,GAAAD,EAAA,KAAK,WAAU,uBAAf,MAAAC,EAAA,KAAAD,EAAsC0C,EAAS,iBAG/CA,EAAS,cAAgB,QACzBA,EAAS,cAAgBC,EAAU,eAEnCxC,GAAAD,EAAA,KAAK,WAAU,yBAAf,MAAAC,EAAA,KAAAD,EAAwCwC,EAAS,aAErD,CAEA,WAAWE,EAAsB,CAC/B,KAAK,SAAS,CAAE,QAAAA,CAAQ,CAAC,CAC3B,CAEA,kBAAkBC,EAA0B,CAC1C,KAAK,SAAS,CAAE,eAAgBA,CAAS,CAAC,CAC5C,CAEA,UAAUd,EAA0B,CAClC,KAAK,SAAS,CAAE,OAAAA,CAAO,CAAC,CAC1B,CAEA,iBAAiBA,EAA0B,CACzC,KAAK,SAAS,CAAE,cAAeA,CAAO,CAAC,CACzC,CAEA,cAAcA,EAA0B,CACtC,KAAK,SAAS,CAAE,WAAYA,CAAO,CAAC,CACtC,CAEA,WAAWe,EAAkB,CAC3B,KAAK,SAAS,CAAE,eAAgBA,CAAQ,CAAC,CAC3C,CAEA,aAAaC,EAAoB,CAC/B,KAAK,SAAS,CAAE,YAAaA,CAAU,CAAC,CAC1C,CAEA,kBAAkBC,EAAoB,CACpC,KAAK,SAAS,CAAE,iBAAkBA,CAAU,CAAC,CAC/C,CAEA,iBAAiBjB,EAAmB,CAClC,GAAI,KAAK,MAAM,iBAAkB,CAC/B,KAAK,SAAS,CACZ,iBAAkB,GAClB,WAAYA,EACZ,cAAe,IACjB,CAAC,EACD,MACF,CAEA,IAAMkB,EAAa,KAAK,MAAM,WAC9B,GAAI,CAACA,EAAY,CACf,KAAK,SAAS,CACZ,WAAYlB,EACZ,cAAeA,CACjB,CAAC,EACD,MACF,CAEA,IAAMmB,EAAQ,IAEZ,KAAK,IAAInB,EAAO,GAAG,IAAMkB,EAAW,GAAG,GAAG,EAAIC,GAC9C,KAAK,IAAInB,EAAO,GAAG,IAAMkB,EAAW,GAAG,GAAG,EAAIC,GAC9C,KAAK,IAAInB,EAAO,GAAG,IAAMkB,EAAW,GAAG,GAAG,EAAIC,GAC9C,KAAK,IAAInB,EAAO,GAAG,IAAMkB,EAAW,GAAG,GAAG,EAAIC,EAG9C,KAAK,SAAS,CAAE,cAAenB,CAAO,CAAC,EAEvC,KAAK,SAAS,CAAE,cAAe,IAAK,CAAC,CAEzC,CAEA,SACEoB,EACAC,EACAC,EACAC,EAAqB,GACrB,CAOA,GANA,KAAK,YAAY,EACjB,KAAK,SAAS,CAAE,OAAQ,CAACF,EAAUD,CAAS,CAAE,CAAC,EAC3C,OAAOE,GAAS,UAClB,KAAK,SAAS,CAAE,KAAAA,CAAK,CAAC,EAGpB,CAAC,KAAK,QAAS,OACnB,IAAMlC,EAAc,KAAK,QAAQ,OAAO,EACxC,GAAKA,EAEL,IAAI,KAAK,kBAAoB,SAAU,CACrC,KAAK,kBAAkB,EAAK,EAC5BA,EAAY,UAAU,CAAE,IAAKiC,EAAU,IAAKD,CAAU,CAAC,EACnDE,IAAS,MAAQ,OAAOA,GAAS,UACnClC,EAAY,QAAQkC,GAAA,KAAAA,EAAQ,EAAE,EAEhC,MACF,CAGA,GAAIC,IAAc,GAAO,CACvB,KAAK,kBAAkB,EAAK,EACxBnC,EAAY,QACdA,EAAY,OAAO,CACjB,OAAQ,CAACgC,EAAWC,CAAQ,EAC5B,GAAIC,IAAS,MAAQ,CAAE,KAAMA,GAAA,KAAAA,EAAQ,EAAG,CAC1C,CAAC,EAEH,MACF,CAEA,KAAK,kBAAkB,EAAI,EACvBlC,EAAY,OACdA,EAAY,MAAM,CAChB,OAAQ,CAACgC,EAAWC,CAAQ,EAC5B,GAAIC,IAAS,MAAQ,CAAE,KAAMA,GAAA,KAAAA,EAAQ,EAAG,CAC1C,CAAC,EAEL,CAEA,UACEE,EACAC,EACAC,EAAmB,GACnB,CAx0BJ,IAAArE,EAAAC,EA00BI,GADA,KAAK,YAAY,EACb,CAAC,KAAK,QAAS,OACnB,IAAM8B,EAAc,KAAK,QAAQ,OAAO,EACxC,GAAI,CAACA,EAAa,OAElB,IAAIuC,EAASH,EAab,IAZI,CAACG,GAAUA,EAAO,SAAW,KAC/BA,EAAS,KAAK,WACX,OACEzB,GACCA,EAAE,WAAa,SACduB,IAAS,OAAYvB,EAAE,OAASuB,EAAO,GAC5C,EACC,IAAKG,IAAO,CACX,IAAKA,EAAE,SAAU,IACjB,IAAKA,EAAE,SAAU,GACnB,EAAE,GAEF,GAACD,GAAUA,EAAO,SAAW,IAIjC,GAAIA,EAAO,SAAW,EAAG,CACvB,IAAME,EAAMF,EAAO,CAAC,EAChB,KAAK,kBAAoB,UAC3BvC,EAAY,UAAU,CAAE,IAAKyC,EAAI,IAAK,IAAKA,EAAI,GAAI,CAAC,EACpDzC,EAAY,QAAQ,EAAE,GACbA,EAAY,OACrBA,EAAY,MAAM,CAChB,OAAQ,CAACyC,EAAI,IAAKA,EAAI,GAAG,EACzB,KAAM,EACR,CAAC,CAEL,SACM,KAAK,kBAAoB,SAAU,CAErC,IAAMC,GAAgBxE,GAAAD,EAAA,OAAe,SAAf,YAAAA,EAAuB,OAAvB,YAAAC,EAA6B,aACnD,GAAIwE,EAAc,CAChB,IAAM9B,EAAS,IAAI8B,EACnBH,EAAO,QAASE,GAAQ,CACtB7B,EAAO,OAAO,CAAE,IAAK6B,EAAI,IAAK,IAAKA,EAAI,GAAI,CAAC,CAC9C,CAAC,EACGH,GACF,KAAK,kBAAkB,EAAI,EAE7BtC,EAAY,UAAUY,EAAQ,KAAK,gBAAgB,CACrD,CACF,SAAWZ,EAAY,UAAW,CAEhC,IAAMY,EAA+C,CACnD,CAAC2B,EAAO,CAAC,EAAE,IAAKA,EAAO,CAAC,EAAE,GAAG,EAC7B,CAACA,EAAO,CAAC,EAAE,IAAKA,EAAO,CAAC,EAAE,GAAG,CAC/B,EAEAA,EAAO,QAASE,GAAQ,CACtB7B,EAAO,CAAC,EAAE,CAAC,EAAI,KAAK,IAAIA,EAAO,CAAC,EAAE,CAAC,EAAG6B,EAAI,GAAG,EAC7C7B,EAAO,CAAC,EAAE,CAAC,EAAI,KAAK,IAAIA,EAAO,CAAC,EAAE,CAAC,EAAG6B,EAAI,GAAG,EAC7C7B,EAAO,CAAC,EAAE,CAAC,EAAI,KAAK,IAAIA,EAAO,CAAC,EAAE,CAAC,EAAG6B,EAAI,GAAG,EAC7C7B,EAAO,CAAC,EAAE,CAAC,EAAI,KAAK,IAAIA,EAAO,CAAC,EAAE,CAAC,EAAG6B,EAAI,GAAG,CAC/C,CAAC,EAEGH,GACF,KAAK,kBAAkB,EAAI,EAE7BtC,EAAY,UAAUY,EAAQ,CAC5B,QAAS,KAAK,iBACd,QAAA0B,CACF,CAAC,CACH,EAEJ,CAEA,YAAa,CACX,IAAMb,EAAU,CAAE,GAAG,KAAK,MAAM,OAAQ,EAExC,OAAIA,EAAQ,mBAAmB,OAC7BA,EAAQ,QAAUkB,GAAMlB,EAAQ,OAAO,GAErCA,EAAQ,oBAAoB,OAC9BA,EAAQ,SAAWkB,GAAMlB,EAAQ,QAAQ,GAEpCA,CACT,CAEA,MAAM,eAAe,CACnB,YAAAmB,EACA,YAAAC,EAAc,GACd,QAAAC,EAAU,IACV,YAAAC,EACA,MAAAC,EACA,MAAAC,CACF,EAGG,CAv6BL,IAAAhF,EAAAC,EAAAC,EAAAC,EAAAC,EA06BI,GAFA,KAAK,YAAY,EAEb,CAAC,KAAK,OACR,eAAQ,KAAK,wDAAwD,EAC9D,CAAE,UAAW,EAAM,EAG5B,GAAI,CAACuE,EACH,MAAO,CAAE,UAAW,EAAM,EAG5B,IAAIM,EAAY,GACZC,EAEE1B,EAAU,KAAK,WAAW,EAC5BwB,IACFxB,EAAQ,MAAQwB,GAGlB,IAAMG,EAAY,CAChB,QAAA3B,EACA,YAAAmB,CACF,EAEA,QAASS,EAAU,EAAGA,EAAUR,EAAaQ,IAAW,CACtD,GAAIN,GAAA,MAAAA,IACF,MAAO,CAAE,UAAAG,EAAW,SAAAC,CAAS,EAG/B,GAAI,CACF,IAAMG,EAAW,MAAM,MACrB,GAAG,KAAK,MAAM,6BAA6BD,CAAO,GAClD,CACE,OAAQ,OACR,KAAM,KAAK,UAAUD,CAAI,EACzB,QAAS,CACP,eAAgB,mBAChB,GAAI,KAAK,QAAU,CACjB,YAAa,KAAK,MACpB,CACF,CACF,CACF,EAEA,GAAI,CAACE,EAAS,GACZ,MAAM,IAAIC,EAAqB,CAC7B,QAAS,gBAAgBD,EAAS,MAAM,GACxC,OAAQA,EAAS,MACnB,CAAC,EAKH,GAFAH,EAAW,MAAMG,EAAS,KAAK,EAE3BP,GAAA,MAAAA,IACF,MAAO,CAAE,UAAAG,EAAW,SAAAC,CAAS,EAG/B,IAAMK,GAAUtF,GAAAD,EAAAkF,GAAA,YAAAA,EAAU,UAAV,YAAAlF,EAAmB,UAAnB,KAAAC,EAA8B,CAAC,EAiC/C,GAhCIsF,EAAQ,OAAS,GACnB,KAAK,cAAeC,GAAS,CAC3B,IAAMC,EAAY,IAAI,IAAIF,EAAQ,IAAKhB,GAAMA,EAAE,cAAc,CAAC,EACxDmB,EAAoBF,EAAK,OAC5B1C,GACCA,EAAS,OAAS,iBAClB2C,EAAU,IAAI3C,EAAS,cAAc,CACzC,EAEA,OAAAyC,EAAQ,QAASzC,GAAa,CA3+B1C,IAAA9C,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EA4+Bc,GAAI,CAACyC,EAAS,SAAU,QAEtB7C,GAAAD,EAAA8C,EAAS,UAAT,YAAA9C,EAAkB,QAAlB,MAAAC,EAAyB,OACzB8E,MACC5E,GAAAD,EAAA4C,EAAS,UAAT,YAAA5C,EAAkB,QAAlB,YAAAC,EAAyB,QAAQ4E,GAAA,YAAAA,EAAO,QACvC1E,GAAAD,EAAA0C,EAAS,UAAT,YAAA1C,EAAkB,QAAlB,YAAAC,EAAyB,QAAQ0E,GAAA,YAAAA,EAAO,QAE1CjC,EAAS,QAAQ,aAAe,eAElC,IAAM6C,EAAgBD,EAAkB,UACrCnB,GAAMA,EAAE,iBAAmBzB,EAAS,cACvC,EACI6C,GAAiB,EACnBD,EAAkBC,CAAa,EAAI7C,EAEnC4C,EAAkB,KAAK5C,CAAQ,CAEnC,CAAC,EACM4C,CACT,CAAC,GAGCxF,EAAAgF,GAAA,YAAAA,EAAU,UAAV,MAAAhF,EAAmB,WAAY,CACjC+E,EAAY,GACZ,KACF,CACF,OAASpD,EAAO,CACd,KAAK,YAAYA,EAAO,gBAAgB,GACxCzB,GAAAD,EAAA,KAAK,WAAU,wBAAf,MAAAC,EAAA,KAAAD,EAAuC0B,GACvC,KACF,CAEIuD,EAAUR,EAAc,GAC1B,MAAM,IAAI,QAASgB,GAAY,WAAWA,EAASf,CAAO,CAAC,CAE/D,CAEA,MAAO,CAAE,UAAAI,EAAW,SAAAC,CAAS,CAC/B,CAEQ,cAAcW,EAAiD,CACrE,IAAMH,EAAoBG,EAAQ,KAAK,UAAU,EACjD,KAAK,eAAeH,CAAiB,CACvC,CAEQ,6BAA6B9C,EAAsC,CACzE,IAAMkD,EAAalD,EAAW,OAAO,CAACmD,EAAQjD,KAC5CiD,EAAOjD,EAAS,IAAI,GAAKiD,EAAOjD,EAAS,IAAI,GAAK,GAAK,EAChDiD,GACN,CAAC,CAAiC,EAErC,OAAO,OAAO,QAAQD,CAAU,EAAE,OAAO,CAACE,EAAGC,IAC3CH,EAAWE,EAAE,CAAC,CAAiB,EAAIF,EAAWG,EAAE,CAAC,CAAiB,EAC9DD,EACAC,CACN,EAAE,CAAC,CACL,CAEA,MAAM,oBAAoB,CACxB,KAAAd,EACA,sBAAAe,EACA,sBAAAC,EACA,QAAAC,CACF,EAQgC,CAnjClC,IAAApG,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAsjCI,GAFA,KAAK,YAAY,EAEb,CAAC,KAAK,OACR,eAAQ,KACN,6DACF,EACA8F,GAAA,MAAAA,EAAU,IAAI,MAAM,uBAAuB,GACpC,KAGT,KAAK,SAAS,CAAE,cAAe,EAAM,CAAC,EACtC,KAAK,aAAa,EAAI,EACtB,KAAK,gBAAgB,EAErB,GAAI,CACF,IAAMC,EAAO,MAAMC,GACjB,GAAG,KAAK,MAAM,cACdnB,EACA,KAAK,MACP,EAEA,KAAK,iCAAiCkB,CAAI,EAE1C,IAAItB,EAAsB,KACtBC,EAAgB,GAChBuB,EAAyCF,EAAK,QAAQ,aAE1D,GAAIH,EAAuB,CACzB,IAAMM,EAASN,EAAsBG,CAAI,EACzCtB,GAAQ/E,EAAAwG,EAAO,QAAP,KAAAxG,EAAgB,KACxBgF,GAAQ/E,EAAAuG,EAAO,QAAP,KAAAvG,EAAgB,EAC1B,CAGA,IAAMwG,EAAQJ,EAAK,WAAW,KAAMxD,GAAM,CAAC,CAACA,EAAE,QAAQ,EAGhD6D,EAAqB3B,EACvBsB,EAAK,WAAW,IAAKxD,GAAG,CA1lClC,IAAA7C,EA2lCY,OAAAA,EAAA6C,EAAE,UAAF,MAAA7C,EAAW,MACP,CACE,GAAG6C,EACH,QAAS,CACP,GAAGA,EAAE,QACL,aACEA,EAAE,QAAQ,MAAM,QACfA,EAAE,QAAQ,MAAM,MAAQkC,EAAM,KAC7BlC,EAAE,QAAQ,MAAM,MAAQkC,EAAM,KAC3B,cACDlC,EAAE,QAAQ,YAClB,CACF,EACAA,EACN,EACAwD,EAAK,WAuBT,GApBA,KAAK,eAAeK,CAAkB,EAGlCD,GACF,KAAK,UACHJ,EAAK,WACF,OACExD,GACC,CAAC,CAACA,EAAE,WACHwD,EAAK,QAAQ,aACVxD,EAAE,OAASwD,EAAK,QAAQ,aACxB,GACR,EACC,IAAKxD,IAAO,CAAE,IAAKA,EAAE,SAAU,IAAK,IAAKA,EAAE,SAAU,GAAI,EAAE,EAC9D,OACAsC,EAAK,UAAY,EACnB,EAKAkB,EAAK,QAAQ,cACbA,EAAK,WAAW,OACbvD,GAAU,CApoCrB,IAAA9C,EAqoCY,OAAA8C,EAAS,OAASuD,EAAK,QAAQ,eAC9BvD,EAAS,OAAS,kBACf9C,EAAA8C,EAAS,UAAT,YAAA9C,EAAkB,gBAAiB,cACnC,IACR,EAAE,OAAS,EAEXuG,EAAeF,EAAK,QAAQ,aAC5B,KAAK,eAAeA,EAAK,QAAQ,YAAY,UACpCA,EAAK,WAAW,OAAS,EAAG,CACrC,IAAMM,EAAiB,KAAK,6BAC1BN,EAAK,UACP,EACA,KAAK,eAAeM,CAAc,EAClCJ,EAAeI,CACjB,CAKA,GAHA,KAAK,SAAS,CAAE,cAAe,EAAK,CAAC,EAGjCN,EAAK,aAAe,IAASA,EAAK,YAAa,CACjD,GAAM,CAAE,UAAApB,EAAW,SAAAC,CAAS,EAAI,MAAM,KAAK,eAAe,CACxD,YAAamB,EAAK,YAClB,GAAItB,GAAS,CAAE,MAAAA,CAAM,EACrB,GAAIC,GAAS,CAAE,MAAAA,CAAM,CACvB,CAAC,EAED,GACEC,KACA/E,EAAAgF,GAAA,YAAAA,EAAU,UAAV,MAAAhF,EAAmB,UACnBgF,EAAS,QAAQ,QAAQ,OACtBpC,GAAU,CAnqCvB,IAAA9C,EAoqCc,OAAA8C,EAAS,OAASuD,EAAK,QAAQ,eAC9BvD,EAAS,OAAS,kBACf9C,EAAA8C,EAAS,UAAT,YAAA9C,EAAkB,gBAAiB,cACnC,IACR,EAAE,SAAW,GACbuG,GACAA,IAAiBF,EAAK,QAAQ,aAC9B,CACA,IAAMM,EAAiB,KAAK,6BAC1BN,EAAK,UACP,EACA,KAAK,eAAeM,CAAc,CACpC,CACF,CAGA,OAAKF,IACCJ,EAAK,WAAW,KAAMxD,GAAM,CAAC,CAACA,EAAE,QAAQ,EAC1C,KAAK,UACHwD,EAAK,WACF,OACExD,GACC,CAAC,CAACA,EAAE,WACHwD,EAAK,QAAQ,aACVxD,EAAE,OAASwD,EAAK,QAAQ,aACxB,GACR,EACC,IAAKxD,IAAO,CAAE,IAAKA,EAAE,SAAU,IAAK,IAAKA,EAAE,SAAU,GAAI,EAAE,EAC9D,OACAsC,EAAK,UAAY,EACnB,GAEAhF,EAAAkG,EAAK,QAAQ,WAAb,MAAAlG,EAAuB,YACvBC,EAAAiG,EAAK,QAAQ,WAAb,MAAAjG,EAAuB,YAEvB,KAAK,SACHiG,EAAK,QAAQ,SAAS,UACtBA,EAAK,QAAQ,SAAS,SACtB,GACAlB,EAAK,UAAY,EACnB,GAIGkB,CACT,OAASxE,EAAO,CACd,YAAK,YAAYA,EAAO,qBAAqB,EAC7CuE,GAAA,MAAAA,EAAUvE,IACVvB,GAAAD,EAAA,KAAK,WAAU,wBAAf,MAAAC,EAAA,KAAAD,EAAuCwB,GACvC,KAAK,gBAAgB,EACrB,KAAK,SAAS,CAAE,cAAe,EAAK,CAAC,EAC9B,IACT,QAAE,CACA,KAAK,aAAa,EAAK,EACvB,KAAK,SAAS,CAAE,cAAe,EAAK,CAAC,CACvC,CACF,CAEA,MAAM,qBAAmD,CA9tC3D,IAAA7B,EAiuCI,GAFA,KAAK,YAAY,EAEb,CAAC,KAAK,OACR,eAAQ,KACN,6DACF,EACO,KAGT,GAAI,CAAC,KAAK,MAAM,cACd,OAAO,KAGT,IAAMwD,EAAU,KAAK,WAAW,EAC1B2B,EAA2B,CAC/B,OAAQ,KAAK,MAAM,cACnB,QAAA3B,CACF,EAEMoD,GAAc5G,EAAAwD,GAAA,YAAAA,EAAS,QAAT,KAAAxD,EAAkB,OAEhCwG,EAAS,MAAM,KAAK,oBAAoB,CAC5C,KAAArB,EACA,sBAAuB,KACd,CAAE,MAAOyB,GAAA,KAAAA,EAAe,IAAK,EAExC,CAAC,EAED,OAAIJ,IACF,KAAK,UAAU,KAAK,MAAM,aAAa,EACvC,KAAK,cAAc,KAAK,MAAM,aAAa,EAC3C,KAAK,iBAAiB,IAAI,GAGrBA,CACT,CAEQ,iCAAiCH,EAAmB,CApwC9D,IAAArG,EAAAC,EAAAC,EAAAC,EAqwCI,IAAM0G,GAAgB7G,EAAAqG,EAAK,cAAL,KAAArG,EAAoB,KACpC8G,GAAU5G,GAAAD,EAAAoG,EAAK,QAAQ,WAAb,YAAApG,EAAuB,OAAvB,KAAAC,EAA+B,OACzC6G,IAAa5G,EAAAkG,EAAK,QAAQ,WAAb,YAAAlG,EAAuB,UAAW,GAC/C6G,EAAiBX,EAAK,QAAQ,SAChC,CAACA,EAAK,QAAQ,SAAS,SAAUA,EAAK,QAAQ,SAAS,SAAS,EAChE,OAEJ,GAAI,CAACW,EAAgB,OAErB,IAAMC,EAAkB,KAAK,MAAM,gBAIjCJ,KAAkBI,GAAA,YAAAA,EAAiB,cACnCH,KAAYG,GAAA,YAAAA,EAAiB,OAC7BF,KAAeE,GAAA,YAAAA,EAAiB,WAEhC,KAAK,kBAAkB,CACrB,KAAMH,EACN,QAASC,EACT,YAAaF,EACb,aACEC,GAAWC,EACP,GAAGD,CAAO,KAAKC,CAAU,GACzBA,GAAc,GACpB,YAAaC,CACf,CAAC,CAEL,CAEA,MAAM,qBAAqB,CACzB,MAAAzF,EACA,QAAAiC,EACA,iBAAA0D,EACA,QAAAd,CACF,EAagC,CAG9B,GAFA,KAAK,YAAY,EAEb,CAAC,KAAK,OACR,eAAQ,KACN,8DACF,EACAA,GAAA,MAAAA,EAAU,IAAI,MAAM,uBAAuB,GACpC,KAIT,IAAIe,EAAgB,KAAK,WAAW,EAC9BC,EAAQ,KAAK,SAAS,EAE5B,GAAI5D,GAAWA,EAAQ,OAAS,EAAG,CACjC,IAAM6D,EAAY,IAAI,IAChBC,EAAa,IAAI,IACnBvC,EACAwC,EACAC,EACAjB,EACAkB,EACAC,EAEJlE,EAAQ,QAASmE,GAAW,CA90ClC,IAAA3H,EAAAC,EAAAC,EA+0CQ,OAAQyH,EAAO,KAAM,CACnB,IAAK,UACHN,EAAU,IAAIM,EAAO,KAAK,EAC1B,MACF,IAAK,aACHL,EAAW,IAAIK,EAAO,KAAK,EAC3B,MACF,IAAK,aACCA,EAAO,aACT5C,EAAQ,CACN,IAAK4C,EAAO,WAAW,IACvB,KAAK3H,EAAA2H,EAAO,WAAW,MAAlB,KAAA3H,EAAyB,CAChC,GAEF,MACF,IAAK,YACHuH,GAAYtH,EAAA0H,EAAO,eAAP,KAAA1H,EAAuB,OAAO0H,EAAO,KAAK,EACtD,MACF,IAAK,aACHH,GAAatH,EAAAyH,EAAO,eAAP,KAAAzH,EAAuB,OAAOyH,EAAO,KAAK,EACvD,MACF,IAAK,eACHpB,EAAeoB,EAAO,aACtB,MACF,IAAK,oBACHF,EAAoBE,EAAO,MAC3B,MACF,IAAK,mCACHD,EAAmCC,EAAO,YAC1C,KACJ,CACF,CAAC,EAEDR,EAAgB,CACd,GAAGA,EACH,GAAIE,EAAU,KAAO,GAAK,CAAE,UAAW,MAAM,KAAKA,CAAS,CAAE,EAC7D,GAAIC,EAAW,KAAO,GAAK,CAAE,WAAY,MAAM,KAAKA,CAAU,CAAE,EAChE,GAAIvC,GAAS,CAAE,MAAAA,CAAM,EACrB,GAAIwC,IAAc,QAAa,CAAE,UAAAA,CAAU,EAC3C,GAAIC,IAAe,QAAa,CAAE,WAAAA,CAAW,EAC7C,GAAIjB,GAAgB,CAAE,aAAAA,CAAa,EACnC,GAAIkB,GAAqB,CAAE,kBAAAA,CAAkB,EAC7C,GAAIC,GAAoC,CACtC,iCAAAA,CACF,CACF,CACF,MAAYnG,IAEV4F,EAAc,UAAY,GAG5B,IAAMhC,EAA2B,CAC/B,QAASgC,EACT,GAAI5F,GAAS,CAAE,MAAAA,CAAM,EACrB,GAAI6F,EAAM,OACN,CAAE,OAAQA,EAAM,MAAO,EACvBA,EAAM,eAAe,YACrB,CAAE,YAAaA,EAAM,eAAe,WAAY,EAChDA,EAAM,eAAe,YACrB,CACE,SAAUA,EAAM,eAAe,YAAY,CAAC,EAC5C,UAAWA,EAAM,eAAe,YAAY,CAAC,CAC/C,EACA,CAAC,CACP,EAEA,OAAO,KAAK,oBAAoB,CAC9B,KAAAjC,EACA,sBAAuB+B,EAClBb,GAAS,CAp5CpB,IAAArG,EAAAC,EAq5CY,IAAMuG,EAASU,EAAiBb,EAAK,QAASA,EAAK,WAAW,EAC9D,MAAO,CACL,OAAOrG,EAAAwG,EAAO,QAAP,KAAAxG,EAAgB,KACvB,OAAOC,EAAAuG,EAAO,QAAP,KAAAvG,EAAgB,EACzB,CACF,EACA,OACJ,sBAAuB,CAAC,CAACsB,EACzB,QAAA6E,CACF,CAAC,CACH,CAEA,aAAoC,CAClC,YAAK,YAAY,EACV,CAAC,GAAG,KAAK,YAAY,CAC9B,CAEA,UAAUwB,EAAiBC,EAAoB,GAAM,CACnD,KAAK,YAAY,EAGjB,KAAK,OAASD,EAIZ,CAACA,GACD,KAAK,iBACL,KAAK,kBAAoB,YAEzB,QAAQ,KACN,uFACF,EAIGA,GACH,KAAK,gBAAgB,EAInBA,GAAUC,IACR,KAAK,QAAQ,oBACf,KAAK,2BAA2B,KAAK,QAAQ,mBAAmB,EACvD,KAAK,aAAe,KAAK,eAClC,KAAK,mBAAmB,EAG9B,CAEA,UAAUC,EAA4B,CACpC,KAAK,YAAY,EACjB,IAAMC,EAAS,KAAK,OACpB,KAAK,OAASD,EAGVC,IAAW,KAAK,QAAU,KAAK,gBACjC,KAAK,QAAQ,EAET,KAAK,SACH,KAAK,QAAQ,oBACf,KAAK,2BAA2B,KAAK,QAAQ,mBAAmB,EACvD,KAAK,aACd,KAAK,mBAAmB,GAIhC,CAEA,WAAgC,CAC9B,OAAO,KAAK,MACd,CAEA,SAAU,CA79CZ,IAAA/H,EAAAC,EAAAC,EA+9CI,GADA,KAAK,YAAY,EACb,CAAC,KAAK,QAAS,OAEnB,IAAM8H,EAAY,KAAK,qBAAqB,EACtCC,EAAc,KAAK,mBAAmB,EAE5C,KAAK,aAAeC,EAAe,CACjC,YAAAD,EACA,QAAS,KAAK,WACd,IAAK,KAAK,QACV,iBAAkB,KAAK,iBACvB,MAAMjI,EAAAgI,GAAA,YAAAA,EAAW,OAAX,KAAAhI,EAAmB,CAC3B,CAAC,EAEqB,KAAK,QAAQ,iBAAiB,EACtC,OAAO,KAAK,aAAciI,EAAa,KAAK,gBAAgB,GAE1E/H,GAAAD,EAAA,KAAK,SAAQ,kBAAb,MAAAC,EAAA,KAAAD,EAA+B,KAAK,aAAc+H,EACpD,CAEA,SAAU,CACJ,KAAK,YAGL,KAAK,UACe,KAAK,QAAQ,iBAAiB,EACtC,QAAQ,EACtB,KAAK,QAAQ,QAAQ,GAGvB,KAAK,aAAe,CAAC,EACrB,KAAK,WAAa,CAAC,EACnB,KAAK,UAAY,GACjB,KAAK,cAAgB,GACvB,CAEQ,oBAAmC,CAlgD7C,IAAAhI,EAAAC,EAAAC,EAmgDI,OACEA,GAAAD,EAAA,KAAK,cAAL,KAAAA,GACAD,EAAA,KAAK,WAAW,KAAM0C,GAAWA,EAAO,IAAI,IAA5C,YAAA1C,EAA+C,OAD/C,KAAAE,EAEAZ,EAEJ,CAEQ,sBAAiD,CACvD,GAAI,CAAC,KAAK,QAAS,OAAO,KAC1B,GAAI,CACF,OAAO6I,EAAiB,KAAK,OAAO,CACtC,MAAQ,CACN,OAAO,IACT,CACF,CAEQ,aAAc,CACpB,GAAI,KAAK,UACP,MAAM,IAAI,MAAM,0CAA0C,CAE9D,CACF,EAEA,SAAShG,GACPpC,EAC4B,CAC5B,OAAQA,EAA4B,WAAa,UACnD,CAEA,SAASmB,GACPnB,EAC8B,CAC9B,OAAQA,EAA8B,WAAa,QACrD,CAEA,SAASuC,GAAgBvC,EAAoD,CAC3E,OAAQA,EAA0B,WAAa,QACjD","names":["styleInject","css","insertAt","head","style","styleInject","createDotMarkerElement","item","primaryType","selectedMarkerId","onMarkerClick","_a","_b","_c","marker","isPrimaryType","isSelected","isPending","container","button","evt","AWARD_SVG","AWARD_BACK_SVG","EAT_DRINK_SVG","ATTRACTION_SVG","getDefaultImageForType","type","createPropertyCard","marker","_a","_b","_c","_d","_e","_f","_g","card","rating","reviews","displayPrice","url","renderStars","fullStars","hasHalfStar","stars","i","emptyStars","imageUrl","positionCard","markerElement","mapContainer","markerRect","containerRect","cardWidth","cardHeight","offset","spaceRight","spaceLeft","spaceBottom","spaceTop","left","top","createPrimaryMarkerElement","item","primaryType","selectedMarkerId","onMarkerClick","isPrimaryType","isSelected","isAccommodation","hasPrice","isPending","ratingLabel","numeric","root","pill","badge","awardContainer","backLayer","colorDot","frontLayer","content","evt","propertyCard","hoverTimeout","hideTimeout","positionUpdateFrame","cleanupCard","updateCardPosition","showCard","immediate","doShow","hideCard","observer","mutations","mutation","removedNode","checkParent","updatePrimaryMarkerElement","element","isPrimaryType","isSelected","isPending","root","pill","badge","updateDotMarkerElement","container","button","extractMarkerIdFromKey","key","match","BaseMarkerManager","mapInstance","onMarkerClick","items","primaryType","selectedMarkerId","_a","_b","_c","_d","newKeys","item","key","entry","coords","safeLatLon","existing","markerId","existingEntry","existingKey","extractMarkerIdFromKey","isPrimaryType","isSelected","isAccommodation","isPending","element","updatePrimaryMarkerElement","updateDotMarkerElement","createPrimaryMarkerElement","createDotMarkerElement","marker","error","location","MapLibreMarkerManager","BaseMarkerManager","options","_a","items","primaryType","selectedMarkerId","element","coords","item","marker","GoogleMapsMarkerManager","BaseMarkerManager","options","items","primaryType","selectedMarkerId","_a","_b","element","coords","item","isPrimaryType","isSelected","zIndex","marker","error","MapboxMarkerManager","BaseMarkerManager","options","_a","items","primaryType","selectedMarkerId","element","coords","item","marker","MapAdapter","map","onImpression","container","observer","entries","entry","cleanup","originalCleanup","MapLibreAdapter","MapAdapter","map","options","MapLibreMarkerManager","onMapMoveEnd","handleMoveEnd","bounds","handleLoad","onRefresh","eventName","_a","_b","cleanup","center","sw","ne","lngLat","event","handler","GoogleMapsAdapter","MapAdapter","map","options","GoogleMapsMarkerManager","onMapMoveEnd","google","handleIdle","bounds","listener","onRefresh","events","listeners","eventName","_a","_b","cleanup","googleMaps","OverlayView","center","sw","ne","lngLat","projection","latLng","point","event","handler","MapboxAdapter","MapAdapter","map","options","MapboxMarkerManager","onMapMoveEnd","handleMoveEnd","bounds","handleLoad","onRefresh","eventName","_a","_b","cleanup","center","sw","ne","lngLat","event","handler","extractViewState","mapInstance","center","COLLISION_THRESHOLD_PX_ZOOM_BREAKPOINTS","resolveCollisionThreshold","zoom","breakpoint","clusterMarkers","primaryType","markers","map","selectedMarkerId","collisionThresholdPx","dotCollisionThresholdPx","marker","projected","index","location","x","y","value","threshold","dotThreshold","resolveDotCollisionThreshold","parent","_","idx","find","i","union","a","b","rootA","rootB","j","dx","dy","groups","item","root","group","clustered","groupItems","_a","_b","isPrimary","isSelected","sorted","compareMarkers","primary","rest","isPrimaryPrimary","isSelectedPrimary","dotCandidates","remainder","distancePx","followUp","base","aIsPrimary","bIsPrimary","ratingDiff","resolveRating","priceDiff","resolvePrice","reviewsDiff","parsed","_c","numeric","processApiFilters","apiFilters","filters","amenity","style","convertToApiFilters","filter","apiFilter","min","max","API_URLS","PropertiesFetchError","message","status","code","fetchProperties","url","body","apiKey","signal","_a","_b","response","errorBody","toISO","date","DEFAULT_PRIMARY_TYPE","getDefaultDates","base","daysUntilSaturday","checkIn","startDay","daysUntilWeekend","checkOut","MapFirstCore","options","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","API_URLS","isGoogleMaps","isGoogleMapsOptions","defaultDates","locationData","city","country","query","requestBody","geoResponse","geoData","finalCity","finalCountry","error","defaultRequestBody","mapInstance","config","markerManager","adapterConfig","isMapLibreOptions","MapLibreAdapter","GoogleMapsAdapter","isMapboxOptions","MapboxAdapter","adapter","shouldAutoSelect","marker","bounds","properties","x","property","primary","markerId","p","context","errorMessage","errorObj","update","newState","prevState","filters","location","loading","searching","animating","tempBounds","delta","longitude","latitude","zoom","animation","pois","type","animate","points","h","poi","LatLngBounds","toISO","pollingLink","maxAttempts","delayMs","isCancelled","price","limit","completed","pollData","body","attempt","pollResp","PropertiesFetchError","results","prev","resultIds","updatedProperties","existingIndex","resolve","updater","typeCounts","counts","a","b","beforeApplyProperties","smartFiltersClearable","onError","data","fetchProperties","primary_type","result","flown","filteredProperties","mostCommonType","priceFilter","newLocationId","newCity","newCountry","newCoordinates","currentLocation","onProcessFilters","filterPayload","state","amenities","hotelStyle","minRating","starRating","transformed_query","selected_restaurant_price_levels","filter","useApi","autoLoad","apiKey","oldKey","viewState","primaryType","clusterMarkers","extractViewState"]}
1
+ {"version":3,"sources":["#style-inject:#style-inject","../src/markers.css","../src/dotmarker.ts","../src/marker.ts","../src/marker-updater.ts","../src/adapters/markermanager.ts","../src/adapters/maplibre/markermanager.ts","../src/adapters/google/markermanager.ts","../src/adapters/mapbox/markermanager.ts","../src/adapters/index.ts","../src/adapters/maplibre/index.ts","../src/adapters/google/index.ts","../src/adapters/mapbox/index.ts","../src/utils/clustering.ts","../src/utils/filters.ts","../src/index.ts"],"sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\".mapfirst-marker-root{display:flex;z-index:20;flex-direction:column;align-items:center;pointer-events:auto}.mapfirst-marker-pill{border:2px solid;border-radius:999px;padding:8px;font-size:16px;font-weight:600;font-family:system-ui,-apple-system,sans-serif;box-shadow:0 4px 6px #6b728080;display:flex;align-items:center;justify-content:center;position:relative;transition:transform .2s;transform-origin:center bottom}.mapfirst-marker-pill-pending{background:#ffffff80;backdrop-filter:blur(4px);border-color:transparent;cursor:default}.mapfirst-marker-pill-active{background:#012b11;border-color:#fff;color:#fff;cursor:pointer}.mapfirst-marker-pill-active.mapfirst-marker-non-primary{background:#ffffffb3;border-color:#03852e80;color:#03852e80;padding:4px}.mapfirst-marker-pill-active.mapfirst-marker-selected{background:#fff;border-color:#03852e;color:#03852e;transform:scale(1.2)}.mapfirst-marker-pill-active:hover{transform:scale(1.2)}.mapfirst-marker-badge{position:absolute;top:-12px;right:-20px}.mapfirst-marker-award-container{position:relative;width:32px;height:32px}.mapfirst-marker-award-back{position:absolute;stroke:#f5f5f5;stroke-width:2px}.mapfirst-marker-award-dot{position:absolute;top:6.2px;left:6.3px;width:18.5px;height:18.5px;border-radius:50%;z-index:1}.mapfirst-marker-award-dot-type-0{background:#ffef0e}.mapfirst-marker-award-dot-type-1{background:#01ea5b}.mapfirst-marker-award-front{position:relative;z-index:2;color:#012b11}.mapfirst-marker-rating-badge{display:flex;align-items:center;justify-content:center;border-radius:999px;background:#03852e;color:#fff;font-size:12px;line-height:1;box-shadow:0 2px 4px #0003;padding:2px 6px;border:2px solid #ffffff;font-weight:400}.mapfirst-marker-content{display:flex;align-items:center}.mapfirst-marker-loading-video{width:20px;height:20px;display:block}.mapfirst-dot-marker-container{display:flex;z-index:10;align-items:center;justify-content:center;pointer-events:auto}.mapfirst-dot-marker-button{width:20px;height:20px;border-radius:999px;border:2px solid #ffffff;box-shadow:0 2px 4px #6b728066;transition:transform .2s;outline:none;transform-origin:center center}.mapfirst-dot-marker-button-pending{background:#d1d5db;cursor:default}.mapfirst-dot-marker-button-active{background:#012b11;cursor:pointer}.mapfirst-dot-marker-button-active.mapfirst-dot-marker-non-primary{background:#ffffffb3;border-color:#03852e33}.mapfirst-dot-marker-button-active.mapfirst-dot-marker-selected{background:#fff;border-color:#03852e}.mapfirst-dot-marker-button-active:hover{transform:scale(1.2)}.mapfirst-dot-marker-button-active:focus{outline:2px solid #ffffff;outline-offset:2px}.mapfirst-property-hover-card{position:absolute;width:270px;background:#fff;border-radius:8px;box-shadow:0 4px 12px #00000026;overflow:hidden;display:flex;pointer-events:auto;z-index:9999;transition:opacity .2s;height:120px;text-decoration:none;color:inherit}.mapfirst-property-hover-card img{width:120px;height:120px;object-fit:cover;flex-shrink:0}.mapfirst-property-hover-image{width:120px;height:120px;flex-shrink:0}.mapfirst-property-hover-image-placeholder{background-color:#e5e7eb}.mapfirst-property-hover-details{display:flex;flex-direction:column;padding:8px 12px;flex:1;gap:4px}.mapfirst-property-hover-name{font-size:12px;font-weight:600;color:#1a1a1a;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.3}.mapfirst-property-hover-rating{display:flex;align-items:center;gap:4px;font-size:12px}.mapfirst-property-hover-rating .rating-value{font-weight:600;color:#1a1a1a}.mapfirst-property-hover-rating .stars{display:flex;gap:1px;font-size:10px;line-height:1;align-items:center}.mapfirst-property-hover-rating .reviews{color:#666;font-size:11px}.mapfirst-property-hover-price{font-size:12px;color:#666;margin-top:2px}.mapfirst-property-hover-price strong{color:#1a1a1a;font-weight:600}.mapfirst-property-hover-learn-more{font-size:12px;color:#03852e;text-decoration:none;font-weight:500;margin-top:auto;pointer-events:auto;display:inline-block}.mapfirst-property-hover-learn-more:hover{text-decoration:underline}\\n\")","import type { Property } from \".\";\r\nimport \"./markers.css\";\r\nimport { ClusterDisplayItem } from \"./utils/clustering\";\r\n\r\nexport function createDotMarkerElement(\r\n item: Extract<ClusterDisplayItem, { kind: \"dot\" }>,\r\n primaryType: string,\r\n selectedMarkerId: number | null,\r\n onMarkerClick?: (marker: Property) => void\r\n) {\r\n if (typeof document === \"undefined\") {\r\n return null;\r\n }\r\n\r\n const marker = item.marker;\r\n const isPrimaryType = marker.type === primaryType;\r\n const isSelected = selectedMarkerId === marker.tripadvisor_id;\r\n const isAccommodation = marker.type === \"Accommodation\";\r\n const isPending =\r\n isAccommodation && marker.pricing?.offer?.availability !== \"available\";\r\n\r\n // Create container div to match primary marker structure\r\n const container = document.createElement(\"div\");\r\n container.className = \"mapfirst-dot-marker-container\";\r\n container.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"3\" : \"1\";\r\n\r\n const button = document.createElement(\"div\");\r\n button.className = isPending\r\n ? \"mapfirst-dot-marker-button mapfirst-dot-marker-button-pending\"\r\n : `mapfirst-dot-marker-button mapfirst-dot-marker-button-active${\r\n isSelected\r\n ? \" mapfirst-dot-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-dot-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n button.title = marker.name ?? String(marker.tripadvisor_id);\r\n\r\n button.addEventListener(\"click\", (evt) => {\r\n evt.stopPropagation();\r\n if (!isPending) {\r\n onMarkerClick?.(marker);\r\n }\r\n });\r\n\r\n container.appendChild(button);\r\n return container;\r\n}\r\n","import type { Property } from \".\";\r\nimport { fetchImages } from \".\";\r\nimport \"./markers.css\";\r\nimport { ClusterDisplayItem } from \"./utils/clustering\";\r\n\r\nconst AWARD_SVG = `<svg viewBox=\"0 0 24 24\" width=\"32\" height=\"32\" fill=\"currentColor\"><path d=\"M12 3.953a7.442 7.442 0 1 0 .001 14.884A7.442 7.442 0 0 0 12 3.953m0 14.05a6.61 6.61 0 1 1 0-13.218 6.61 6.61 0 0 1 0 13.219M10.343 11.9a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.821 0m5.134 0a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.82 0m.82-1.897.84-.913h-1.863A5.8 5.8 0 0 0 12 8.08a5.77 5.77 0 0 0-3.27 1.008H6.862l.84.913a2.567 2.567 0 1 0 3.475 3.78l.823.896.823-.895a2.568 2.568 0 1 0 3.474-3.78m-6.865 3.634a1.738 1.738 0 1 1 0-3.476 1.738 1.738 0 0 1 0 3.476M12 11.85c0-1.143-.832-2.124-1.929-2.543A5 5 0 0 1 12 8.92a5 5 0 0 1 1.928.386c-1.096.42-1.927 1.4-1.927 2.543m2.566 1.787a1.738 1.738 0 1 1 .001-3.476 1.738 1.738 0 0 1 0 3.476m-8.456 3.719s-.377-.946-1.396-1.903c-1.02-.957-2.303-1.132-2.303-1.132s.457 1.02 1.54 2.04c1.086 1.017 2.159.995 2.159.995m2.568 1.41s-.524-.511-1.479-.883-1.861-.191-1.861-.191.598.54 1.615.935c1.016.397 1.725.139 1.725.139m2.493.505s-.545-.224-1.357-.196-1.415.47-1.415.47.608.222 1.473.193 1.3-.467 1.3-.467m-6.186-4.203s-.175-1.008-.974-2.154c-.8-1.147-2.015-1.578-2.015-1.578s.238 1.098 1.089 2.319c.85 1.22 1.9 1.413 1.9 1.413m-1.003-3.071s.195-1.021-.134-2.393c-.328-1.371-1.294-2.21-1.294-2.21s-.17 1.128.18 2.589c.35 1.46 1.248 2.014 1.248 2.014\"></path><path d=\"M17.887 17.355s.377-.946 1.396-1.903c1.02-.957 2.303-1.132 2.303-1.132s-.457 1.02-1.54 2.04c-1.086 1.017-2.159.995-2.159.995m-2.567 1.41s.524-.511 1.479-.883 1.861-.191 1.861-.191-.598.54-1.615.935c-1.016.397-1.725.139-1.725.139m-2.493.505s.545-.224 1.357-.196 1.415.47 1.415.47-.608.222-1.473.193-1.3-.467-1.3-.467m6.186-4.203s.175-1.008.974-2.154c.8-1.147 2.015-1.578 2.015-1.578s-.238 1.098-1.089 2.319c-.85 1.22-1.9 1.413-1.9 1.413m1.003-3.071s-.195-1.021.133-2.393c.33-1.371 1.293-2.21 1.293-2.21s.17 1.128-.18 2.589c-.349 1.46-1.246 2.014-1.246 2.014M12 20.047a.413.413 0 1 0 0-.827.413.413 0 0 0 0 .827\"></path></svg>`;\r\n\r\nconst AWARD_BACK_SVG = `<svg viewBox=\"0 0 24 24\" width=\"32\" height=\"32\"><path d=\"M12 3.953a7.442 7.442 0 1 0 .001 14.884A7.442 7.442 0 0 0 12 3.953m0 14.05a6.61 6.61 0 1 1 0-13.218 6.61 6.61 0 0 1 0 13.219M10.343 11.9a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.821 0m5.134 0a.91.91 0 1 1-1.821 0 .91.91 0 0 1 1.82 0m.82-1.897.84-.913h-1.863A5.8 5.8 0 0 0 12 8.08a5.77 5.77 0 0 0-3.27 1.008H6.862l.84.913a2.567 2.567 0 1 0 3.475 3.78l.823.896.823-.895a2.568 2.568 0 1 0 3.474-3.78m-6.865 3.634a1.738 1.738 0 1 1 0-3.476 1.738 1.738 0 0 1 0 3.476M12 11.85c0-1.143-.832-2.124-1.929-2.543A5 5 0 0 1 12 8.92a5 5 0 0 1 1.928.386c-1.096.42-1.927 1.4-1.927 2.543m2.566 1.787a1.738 1.738 0 1 1 .001-3.476 1.738 1.738 0 0 1 0 3.476m-8.456 3.719s-.377-.946-1.396-1.903c-1.02-.957-2.303-1.132-2.303-1.132s.457 1.02 1.54 2.04c1.086 1.017 2.159.995 2.159.995m2.568 1.41s-.524-.511-1.479-.883-1.861-.191-1.861-.191.598.54 1.615.935c1.016.397 1.725.139 1.725.139m2.493.505s-.545-.224-1.357-.196-1.415.47-1.415.47.608.222 1.473.193 1.3-.467 1.3-.467m-6.186-4.203s-.175-1.008-.974-2.154c-.8-1.147-2.015-1.578-2.015-1.578s.238 1.098 1.089 2.319c.85 1.22 1.9 1.413 1.9 1.413m-1.003-3.071s.195-1.021-.134-2.393c-.328-1.371-1.294-2.21-1.294-2.21s-.17 1.128.18 2.589c.35 1.46 1.248 2.014 1.248 2.014\"></path><path d=\"M17.887 17.355s.377-.946 1.396-1.903c1.02-.957 2.303-1.132 2.303-1.132s-.457 1.02-1.54 2.04c-1.086 1.017-2.159.995-2.159.995m-2.567 1.41s.524-.511 1.479-.883 1.861-.191 1.861-.191-.598.54-1.615.935c-1.016.397-1.725.139-1.725.139m-2.493.505s.545-.224 1.357-.196 1.415.47 1.415.47-.608.222-1.473.193-1.3-.467-1.3-.467m6.186-4.203s.175-1.008.974-2.154c.8-1.147 2.015-1.578 2.015-1.578s-.238 1.098-1.089 2.319c-.85 1.22-1.9 1.413-1.9 1.413m1.003-3.071s-.195-1.021.133-2.393c.33-1.371 1.293-2.21 1.293-2.21s.17 1.128-.18 2.589c-.349 1.46-1.246 2.014-1.246 2.014M12 20.047a.413.413 0 1 0 0-.827.413.413 0 0 0 0 .827\"></path></svg>`;\r\n\r\nconst EAT_DRINK_SVG = `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M14.051 6.549v.003l1.134 1.14 3.241-3.25.003-.002 1.134 1.136-3.243 3.252 1.134 1.14a1 1 0 0 0 .09-.008c.293-.05.573-.324.72-.474l.005-.006 2.596-2.603L22 8.016l-2.597 2.604a3.73 3.73 0 0 1-1.982 1.015 4.3 4.3 0 0 1-3.162-.657l-.023-.016-.026-.018-1.366 1.407 8.509 8.512L20.219 22l-.002-.002-6.654-6.663-2.597 2.76-7.3-7.315C1.967 8.948 1.531 6.274 2.524 4.198c.241-.504.566-.973.978-1.386l8.154 8.416 1.418-1.423-.039-.045c-.858-1.002-1.048-2.368-.62-3.595a4.15 4.15 0 0 1 .983-1.561L16 2l1.135 1.138-2.598 2.602-.047.045c-.16.151-.394.374-.433.678zM3.809 5.523c-.362 1.319-.037 2.905 1.06 4.103L10.93 15.7l1.408-1.496zM2.205 20.697 3.34 21.84l4.543-4.552-1.135-1.143z\"/></svg>`;\r\n\r\nconst ATTRACTION_SVG = `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M7.56 7.5H3.75a.25.25 0 0 0-.25.25v10c0 .138.112.25.25.25h16.5a.25.25 0 0 0 .25-.25v-10a.25.25 0 0 0-.25-.25h-3.81l-2-2H9.56zM8.94 4h6.12l2 2h3.19c.966 0 1.75.784 1.75 1.75v10a1.75 1.75 0 0 1-1.75 1.75H3.75A1.75 1.75 0 0 1 2 17.75v-10C2 6.784 2.784 6 3.75 6h3.19z\"/><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M12 9.25a2.75 2.75 0 1 0 0 5.5 2.75 2.75 0 0 0 0-5.5M7.75 12a4.25 4.25 0 1 1 8.5 0 4.25 4.25 0 0 1-8.5 0\"/></svg>`;\r\n\r\nconst LOADING_VIDEO_HTML = `<video class=\"mapfirst-marker-loading-video\" src=\"https://api.mapfirst.ai/static/images/loading.webm\" autoplay loop muted></video>`;\r\n\r\nexport function setupHoverCard(\r\n root: HTMLElement,\r\n pill: HTMLElement,\r\n marker: Property,\r\n isSelected: boolean\r\n) {\r\n // Check if hover card is already set up\r\n if (root.dataset.hasHoverCard === \"true\") return;\r\n root.dataset.hasHoverCard = \"true\";\r\n\r\n const propertyCard = createPropertyCard(marker);\r\n let hoverTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let hideTimeout: ReturnType<typeof setTimeout> | null = null;\r\n let positionUpdateFrame: number | null = null;\r\n\r\n const cleanupCard = () => {\r\n if (hoverTimeout) {\r\n clearTimeout(hoverTimeout);\r\n hoverTimeout = null;\r\n }\r\n if (hideTimeout) {\r\n clearTimeout(hideTimeout);\r\n hideTimeout = null;\r\n }\r\n if (positionUpdateFrame) {\r\n cancelAnimationFrame(positionUpdateFrame);\r\n positionUpdateFrame = null;\r\n }\r\n if (propertyCard.parentElement) {\r\n propertyCard.remove();\r\n }\r\n };\r\n\r\n const updateCardPosition = () => {\r\n if (propertyCard.parentElement) {\r\n let mapContainer = root.parentElement;\r\n while (\r\n mapContainer &&\r\n getComputedStyle(mapContainer).position === \"static\"\r\n ) {\r\n mapContainer = mapContainer.parentElement;\r\n }\r\n\r\n if (mapContainer) {\r\n positionCard(propertyCard, root, mapContainer);\r\n positionUpdateFrame = requestAnimationFrame(updateCardPosition);\r\n }\r\n }\r\n };\r\n\r\n const showCard = (immediate = false) => {\r\n if (hideTimeout) {\r\n clearTimeout(hideTimeout);\r\n hideTimeout = null;\r\n }\r\n\r\n const doShow = () => {\r\n // Find map container\r\n let mapContainer = root.parentElement;\r\n while (\r\n mapContainer &&\r\n getComputedStyle(mapContainer).position === \"static\"\r\n ) {\r\n mapContainer = mapContainer.parentElement;\r\n }\r\n\r\n if (mapContainer) {\r\n mapContainer.appendChild(propertyCard);\r\n positionCard(propertyCard, root, mapContainer);\r\n // Load image when card is shown\r\n loadCardImage(propertyCard, marker);\r\n // Start continuous position updates\r\n positionUpdateFrame = requestAnimationFrame(updateCardPosition);\r\n }\r\n };\r\n\r\n if (immediate) {\r\n doShow();\r\n } else {\r\n hoverTimeout = setTimeout(doShow, 300); // Delay to avoid showing on quick hovers\r\n }\r\n };\r\n\r\n const hideCard = () => {\r\n // Don't hide if marker is selected\r\n if (isSelected) return;\r\n\r\n if (hoverTimeout) {\r\n clearTimeout(hoverTimeout);\r\n hoverTimeout = null;\r\n }\r\n if (positionUpdateFrame) {\r\n cancelAnimationFrame(positionUpdateFrame);\r\n positionUpdateFrame = null;\r\n }\r\n hideTimeout = setTimeout(() => {\r\n if (propertyCard.parentElement) {\r\n propertyCard.remove();\r\n }\r\n }, 100); // Small delay to allow mouse to enter card\r\n };\r\n\r\n // Show card immediately if marker is selected\r\n if (isSelected) {\r\n showCard(true);\r\n }\r\n\r\n pill.addEventListener(\"mouseenter\", () => showCard(false));\r\n pill.addEventListener(\"mouseleave\", hideCard);\r\n\r\n // Keep card visible when hovering over it\r\n propertyCard.addEventListener(\"mouseenter\", () => {\r\n if (hideTimeout) {\r\n clearTimeout(hideTimeout);\r\n hideTimeout = null;\r\n }\r\n // Resume position updates if stopped\r\n if (!positionUpdateFrame && propertyCard.parentElement) {\r\n positionUpdateFrame = requestAnimationFrame(updateCardPosition);\r\n }\r\n });\r\n\r\n propertyCard.addEventListener(\"mouseleave\", hideCard);\r\n\r\n // Cleanup card when marker is removed from DOM\r\n const observer = new MutationObserver((mutations) => {\r\n for (const mutation of mutations) {\r\n for (const removedNode of mutation.removedNodes) {\r\n if (removedNode === root || removedNode.contains(root)) {\r\n cleanupCard();\r\n observer.disconnect();\r\n return;\r\n }\r\n }\r\n }\r\n });\r\n\r\n // Start observing when the root is added to the DOM\r\n if (root.parentElement) {\r\n observer.observe(root.parentElement, { childList: true, subtree: true });\r\n } else {\r\n // If not yet in DOM, wait for it\r\n const checkParent = setInterval(() => {\r\n if (root.parentElement) {\r\n observer.observe(root.parentElement, {\r\n childList: true,\r\n subtree: true,\r\n });\r\n clearInterval(checkParent);\r\n }\r\n }, 100);\r\n }\r\n}\r\n\r\nfunction getDefaultImageForType(type: string): string {\r\n const normalizedType = type\r\n .toLowerCase()\r\n .replace(/\\s+/g, \"\")\r\n .replace(/&/g, \"\");\r\n return `/img/${normalizedType}.webp`;\r\n}\r\n\r\nfunction createPropertyCard(marker: Property): HTMLElement {\r\n const url = marker.pricing?.offer?.clickUrl ?? marker.url;\r\n\r\n const card = document.createElement(url ? \"a\" : \"div\");\r\n card.className = \"mapfirst-property-hover-card\";\r\n card.setAttribute(\"data-marker-id\", marker.tripadvisor_id.toString());\r\n\r\n if (url) {\r\n (card as HTMLAnchorElement).href = url;\r\n (card as HTMLAnchorElement).target = \"_blank\";\r\n }\r\n\r\n const rating = marker.rating || 0;\r\n const reviews = marker.reviews || 0;\r\n const displayPrice =\r\n marker.pricing?.offer?.displayPrice ?? marker.price_level;\r\n\r\n // Generate star rating\r\n const renderStars = () => {\r\n const fullStars = Math.floor(rating);\r\n const hasHalfStar = rating % 1 !== 0;\r\n const stars = [];\r\n\r\n // Style for star circles\r\n const starStyle = `\r\n display: inline-block;\r\n width: 8px;\r\n height: 8px;\r\n border: 1px solid #03852e;\r\n border-radius: 9999px;\r\n `;\r\n\r\n for (let i = 0; i < fullStars; i++) {\r\n stars.push(\r\n `<span style=\"${starStyle} background-color: #03852e;\"></span>`\r\n );\r\n }\r\n if (hasHalfStar) {\r\n stars.push(\r\n `<span style=\"${starStyle} background: linear-gradient(90deg, #03852e 50%, transparent 50%);\"></span>`\r\n );\r\n }\r\n const remainingStars = 5 - Math.ceil(rating);\r\n for (let i = 0; i < remainingStars; i++) {\r\n stars.push(`<span style=\"${starStyle}\"></span>`);\r\n }\r\n return stars.join(\"\");\r\n };\r\n\r\n const defaultImageUrl = getDefaultImageForType(marker.type);\r\n\r\n card.innerHTML = `\r\n <div \r\n class=\"mapfirst-property-hover-image mapfirst-property-hover-image-placeholder\"\r\n data-tripadvisor-id=\"${marker.tripadvisor_id}\"\r\n data-default-image=\"${defaultImageUrl}\"\r\n ></div>\r\n <div class=\"mapfirst-property-hover-details\">\r\n <div class=\"mapfirst-property-hover-name\">${marker.name}</div>\r\n <div class=\"mapfirst-property-hover-rating\">\r\n <span class=\"rating-value\">${rating.toFixed(1)}</span>\r\n <span class=\"stars\">${renderStars()}</span>\r\n <span class=\"reviews\">(${reviews})</span>\r\n </div>\r\n ${\r\n marker.type === \"Accommodation\" && displayPrice\r\n ? `\r\n <div class=\"mapfirst-property-hover-price\">\r\n Starting at <strong>${displayPrice}</strong>\r\n </div>\r\n `\r\n : \"\"\r\n }\r\n ${\r\n url\r\n ? `\r\n <span class=\"mapfirst-property-hover-learn-more\">\r\n Learn More\r\n </span>\r\n `\r\n : \"\"\r\n }\r\n </div>\r\n `;\r\n\r\n return card;\r\n}\r\n\r\nfunction loadCardImage(card: HTMLElement, marker: Property) {\r\n const imgContainer = card.querySelector(\r\n \".mapfirst-property-hover-image\"\r\n ) as HTMLElement;\r\n\r\n // Check if image was already loaded\r\n if (\r\n imgContainer &&\r\n marker.tripadvisor_id &&\r\n !imgContainer.dataset.imageLoaded\r\n ) {\r\n imgContainer.dataset.imageLoaded = \"loading\";\r\n const defaultImageUrl = imgContainer.dataset.defaultImage;\r\n\r\n fetchImages(marker.tripadvisor_id, 1)\r\n .then((imageUrl) => {\r\n if (imageUrl && imgContainer) {\r\n // Create an img element and set the TripAdvisor image\r\n const img = document.createElement(\"img\");\r\n img.src = imageUrl;\r\n img.alt = marker.name;\r\n img.style.width = \"100%\";\r\n img.style.height = \"100%\";\r\n img.style.objectFit = \"cover\";\r\n\r\n // Replace placeholder with image\r\n imgContainer.innerHTML = \"\";\r\n imgContainer.appendChild(img);\r\n imgContainer.classList.remove(\r\n \"mapfirst-property-hover-image-placeholder\"\r\n );\r\n imgContainer.dataset.imageLoaded = \"true\";\r\n } else {\r\n throw new Error(\"No image URL\");\r\n }\r\n })\r\n .catch(() => {\r\n // Load default type-based image on error\r\n if (defaultImageUrl && imgContainer) {\r\n const img = document.createElement(\"img\");\r\n img.src = defaultImageUrl;\r\n img.alt = marker.name;\r\n img.style.width = \"100%\";\r\n img.style.height = \"100%\";\r\n img.style.objectFit = \"cover\";\r\n\r\n imgContainer.innerHTML = \"\";\r\n imgContainer.appendChild(img);\r\n imgContainer.classList.remove(\r\n \"mapfirst-property-hover-image-placeholder\"\r\n );\r\n imgContainer.dataset.imageLoaded = \"false\";\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction positionCard(\r\n card: HTMLElement,\r\n markerElement: HTMLElement,\r\n mapContainer: HTMLElement\r\n) {\r\n // Get marker position and dimensions\r\n const markerRect = markerElement.getBoundingClientRect();\r\n const containerRect = mapContainer.getBoundingClientRect();\r\n\r\n const cardWidth = 270; // Fixed card width\r\n const cardHeight = 120; // Approximate card height\r\n const offset = 12; // Gap between marker and card\r\n\r\n // Calculate available space on each side\r\n const spaceRight = containerRect.right - markerRect.right;\r\n const spaceLeft = markerRect.left - containerRect.left;\r\n const spaceBottom = containerRect.bottom - markerRect.bottom;\r\n const spaceTop = markerRect.top - containerRect.top;\r\n\r\n // Default position: bottom center\r\n let left =\r\n markerRect.left - containerRect.left + markerRect.width / 2 - cardWidth / 2;\r\n let top = markerRect.top - containerRect.top + markerRect.height + offset;\r\n\r\n // Horizontal adjustment if card would overflow\r\n if (left < 0) {\r\n left = 8; // Small margin from left edge\r\n } else if (left + cardWidth > containerRect.width) {\r\n left = containerRect.width - cardWidth - 8; // Small margin from right edge\r\n }\r\n\r\n // Vertical adjustment if not enough space below\r\n if (spaceBottom < cardHeight + offset && spaceTop > spaceBottom) {\r\n // Position above if more space above\r\n top = markerRect.top - containerRect.top - cardHeight - offset;\r\n }\r\n\r\n card.style.left = `${left}px`;\r\n card.style.top = `${top}px`;\r\n}\r\n\r\nexport function createPrimaryMarkerElement(\r\n item: Extract<ClusterDisplayItem, { kind: \"primary\" }>,\r\n primaryType: string,\r\n selectedMarkerId: number | null,\r\n onMarkerClick?: (marker: Property) => void\r\n) {\r\n if (typeof document === \"undefined\") {\r\n return null;\r\n }\r\n\r\n const marker = item.marker;\r\n const isPrimaryType = marker.type === primaryType;\r\n const isSelected = selectedMarkerId === marker.tripadvisor_id;\r\n const isAccommodation = marker.type === \"Accommodation\";\r\n const hasPrice = marker.pricing?.offer?.displayPrice;\r\n const isPending = isAccommodation && !hasPrice;\r\n\r\n // Rating\r\n const ratingLabel = (() => {\r\n if (marker.rating === undefined || marker.rating === null) return null;\r\n const numeric =\r\n typeof marker.rating === \"number\" ? marker.rating : Number(marker.rating);\r\n if (Number.isNaN(numeric) || numeric <= 0) return null;\r\n return numeric.toFixed(1);\r\n })();\r\n\r\n const root = document.createElement(\"div\");\r\n root.className = \"mapfirst-marker-root\";\r\n root.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"12\" : \"11\";\r\n\r\n // Get URL for the marker\r\n const markerUrl = marker.pricing?.offer?.clickUrl ?? marker.url;\r\n\r\n const pill = document.createElement(markerUrl ? \"a\" : \"div\");\r\n if (markerUrl) {\r\n (pill as HTMLAnchorElement).href = markerUrl;\r\n (pill as HTMLAnchorElement).target = \"_blank\";\r\n pill.style.textDecoration = \"none\";\r\n }\r\n pill.className = isPending\r\n ? \"mapfirst-marker-pill mapfirst-marker-pill-pending\"\r\n : `mapfirst-marker-pill mapfirst-marker-pill-active${\r\n isSelected\r\n ? \" mapfirst-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n // pill.title = marker.name ?? String(marker.tripadvisor_id);\r\n\r\n // Awards or Rating badge\r\n if (!isPending && (marker.awards?.length || ratingLabel)) {\r\n const badge = document.createElement(\"div\");\r\n badge.className = \"mapfirst-marker-badge\";\r\n if (!isPrimaryType) {\r\n badge.style.opacity = \"0.2\";\r\n }\r\n badge.className = \"mapfirst-marker-badge\";\r\n\r\n if (marker.awards?.length && marker.awards[0].type) {\r\n const awardContainer = document.createElement(\"div\");\r\n awardContainer.className = \"mapfirst-marker-award-container\";\r\n\r\n const backLayer = document.createElement(\"div\");\r\n backLayer.className = \"mapfirst-marker-award-back\";\r\n backLayer.innerHTML = AWARD_BACK_SVG;\r\n\r\n const colorDot = document.createElement(\"div\");\r\n colorDot.className = `mapfirst-marker-award-dot mapfirst-marker-award-dot-type-${marker.awards[0].type}`;\r\n\r\n const frontLayer = document.createElement(\"div\");\r\n frontLayer.className = \"mapfirst-marker-award-front\";\r\n frontLayer.innerHTML = AWARD_SVG;\r\n\r\n awardContainer.appendChild(backLayer);\r\n awardContainer.appendChild(colorDot);\r\n awardContainer.appendChild(frontLayer);\r\n badge.appendChild(awardContainer);\r\n } else if (ratingLabel) {\r\n badge.className = \"mapfirst-marker-badge mapfirst-marker-rating-badge\";\r\n badge.textContent = ratingLabel;\r\n }\r\n\r\n pill.appendChild(badge);\r\n }\r\n\r\n // Content\r\n const content = document.createElement(\"span\");\r\n content.className = \"mapfirst-marker-content\";\r\n if (isAccommodation) {\r\n if (marker.pricing?.offer?.displayPrice) {\r\n content.innerHTML = marker.pricing.offer.displayPrice;\r\n content.dataset.price = marker.pricing.offer.displayPrice;\r\n } else {\r\n content.innerHTML = LOADING_VIDEO_HTML;\r\n content.dataset.price = \"\";\r\n }\r\n } else if (marker.type === \"Eat & Drink\") {\r\n content.innerHTML = EAT_DRINK_SVG;\r\n } else if (marker.type === \"Attraction\") {\r\n content.innerHTML = ATTRACTION_SVG;\r\n }\r\n pill.appendChild(content);\r\n\r\n pill.addEventListener(\"click\", (evt) => {\r\n evt.stopPropagation();\r\n if (!isPending) {\r\n onMarkerClick?.(marker);\r\n }\r\n });\r\n\r\n // Add hover card\r\n if (!isPending) {\r\n setupHoverCard(root, pill, marker, isSelected);\r\n }\r\n\r\n root.appendChild(pill);\r\n return root;\r\n}\r\n","import type { Property } from \"./types\";\r\nimport { setupHoverCard } from \"./marker\";\r\n\r\nconst LOADING_VIDEO_HTML = `<video class=\"mapfirst-marker-loading-video\" src=\"https://api.mapfirst.ai/static/images/loading.webm\" autoplay loop muted></video>`;\r\n\r\n/**\r\n * Utility functions to update marker DOM elements without recreating them\r\n */\r\n\r\n/**\r\n * Updates the z-index and CSS classes of a primary marker element\r\n */\r\nexport function updatePrimaryMarkerElement(\r\n element: HTMLElement,\r\n isPrimaryType: boolean,\r\n isSelected: boolean,\r\n isPending: boolean,\r\n marker?: Property\r\n) {\r\n const wasPending =\r\n element\r\n .querySelector(\".mapfirst-marker-pill\")\r\n ?.classList.contains(\"mapfirst-marker-pill-pending\") ?? false;\r\n // Update root z-index\r\n const root = element;\r\n root.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"12\" : \"11\";\r\n\r\n // Update pill classes\r\n const pill = root.querySelector(\".mapfirst-marker-pill\");\r\n if (pill) {\r\n if (isPending) {\r\n pill.className = \"mapfirst-marker-pill mapfirst-marker-pill-pending\";\r\n } else {\r\n pill.className = `mapfirst-marker-pill mapfirst-marker-pill-active${\r\n isSelected\r\n ? \" mapfirst-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n }\r\n }\r\n\r\n // Update badge opacity for non-primary markers\r\n const badge = root.querySelector(\".mapfirst-marker-badge\");\r\n if (badge instanceof HTMLElement) {\r\n badge.style.opacity = !isPrimaryType && !isSelected ? \"0.2\" : \"\";\r\n }\r\n\r\n // If transitioning from pending to non-pending, setup hover card\r\n if (wasPending && !isPending && marker) {\r\n const pill = root.querySelector(\".mapfirst-marker-pill\");\r\n if (pill instanceof HTMLElement) {\r\n setupHoverCard(root, pill, marker, isSelected);\r\n }\r\n }\r\n\r\n // Update content (price) if marker data is provided\r\n if (marker && marker.type === \"Accommodation\") {\r\n const content = root.querySelector(\".mapfirst-marker-content\");\r\n if (content instanceof HTMLElement) {\r\n const displayPrice = marker.pricing?.offer?.displayPrice;\r\n const currentPrice = content.dataset.price;\r\n\r\n // Only update if price has changed\r\n if (currentPrice !== displayPrice) {\r\n if (displayPrice) {\r\n content.innerHTML = displayPrice;\r\n content.dataset.price = displayPrice;\r\n } else {\r\n content.innerHTML = LOADING_VIDEO_HTML;\r\n content.dataset.price = \"\";\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Update hover card content if it exists\r\n if (marker) {\r\n const hoverCard = document.querySelector(\r\n `.mapfirst-property-hover-card[data-marker-id=\"${marker.tripadvisor_id}\"]`\r\n );\r\n if (hoverCard) {\r\n const rating = marker.rating || 0;\r\n const reviews = marker.reviews || 0;\r\n const displayPrice =\r\n marker.pricing?.offer?.displayPrice ?? marker.price_level;\r\n\r\n const ratingValueEl = hoverCard.querySelector(\".rating-value\");\r\n if (ratingValueEl) {\r\n const newRating = rating.toFixed(1);\r\n if (ratingValueEl.textContent !== newRating) {\r\n ratingValueEl.textContent = newRating;\r\n }\r\n }\r\n\r\n const reviewsEl = hoverCard.querySelector(\".reviews\");\r\n if (reviewsEl) {\r\n const newReviews = `(${reviews})`;\r\n if (reviewsEl.textContent !== newReviews) {\r\n reviewsEl.textContent = newReviews;\r\n }\r\n }\r\n\r\n if (marker.type === \"Accommodation\" && displayPrice) {\r\n let priceEl = hoverCard.querySelector(\".mapfirst-property-hover-price\");\r\n if (!priceEl) {\r\n // Create price element if it doesn't exist\r\n priceEl = document.createElement(\"div\");\r\n priceEl.className = \"mapfirst-property-hover-price\";\r\n const detailsEl = hoverCard.querySelector(\r\n \".mapfirst-property-hover-details\"\r\n );\r\n const learnMoreEl = hoverCard.querySelector(\r\n \".mapfirst-property-hover-learn-more\"\r\n );\r\n if (detailsEl) {\r\n if (learnMoreEl) {\r\n detailsEl.insertBefore(priceEl, learnMoreEl);\r\n } else {\r\n detailsEl.appendChild(priceEl);\r\n }\r\n }\r\n }\r\n if (priceEl) {\r\n const newPriceHtml = `Starting at <strong>${displayPrice}</strong>`;\r\n if (priceEl.innerHTML !== newPriceHtml) {\r\n priceEl.innerHTML = newPriceHtml;\r\n }\r\n }\r\n }\r\n\r\n // Update click URL if provided\r\n const url = marker.pricing?.offer?.clickUrl ?? marker.url;\r\n if (\r\n url &&\r\n hoverCard instanceof HTMLAnchorElement &&\r\n hoverCard.href !== url\r\n ) {\r\n hoverCard.href = url;\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Updates the z-index and CSS classes of a dot marker element\r\n */\r\nexport function updateDotMarkerElement(\r\n element: HTMLElement,\r\n isPrimaryType: boolean,\r\n isSelected: boolean,\r\n isPending: boolean\r\n) {\r\n // Update container z-index\r\n const container = element;\r\n container.style.zIndex = isSelected ? \"20\" : isPrimaryType ? \"3\" : \"1\";\r\n\r\n // Update button classes\r\n const button = container.querySelector(\".mapfirst-dot-marker-button\");\r\n if (button) {\r\n if (isPending) {\r\n button.className =\r\n \"mapfirst-dot-marker-button mapfirst-dot-marker-button-pending\";\r\n } else {\r\n button.className = `mapfirst-dot-marker-button mapfirst-dot-marker-button-active${\r\n isSelected\r\n ? \" mapfirst-dot-marker-selected\"\r\n : !isPrimaryType\r\n ? \" mapfirst-dot-marker-non-primary\"\r\n : \"\"\r\n }`;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Extracts the tripadvisor_id from a marker key\r\n */\r\nexport function extractMarkerIdFromKey(key: string): number | null {\r\n const match = key.match(/^(?:primary|dot)-(\\d+)-/);\r\n return match ? parseInt(match[1], 10) : null;\r\n}\r\n\r\n/**\r\n * Extracts the state flags from a marker key\r\n */\r\nexport function extractStateFromKey(key: string): {\r\n isPrimary: boolean;\r\n isSelected: boolean;\r\n} {\r\n const match = key.match(/-p([01])-s([01])$/);\r\n if (!match) {\r\n return { isPrimary: true, isSelected: false };\r\n }\r\n return {\r\n isPrimary: match[1] === \"1\",\r\n isSelected: match[2] === \"1\",\r\n };\r\n}\r\n","import type { Property } from \"../types\";\r\nimport { createDotMarkerElement } from \"../dotmarker\";\r\nimport { createPrimaryMarkerElement } from \"../marker\";\r\nimport {\r\n updatePrimaryMarkerElement,\r\n updateDotMarkerElement,\r\n extractMarkerIdFromKey,\r\n} from \"../marker-updater\";\r\nimport { ClusterDisplayItem } from \"../utils/clustering\";\r\n\r\nexport type MarkerEntry<T = any> = {\r\n key: string;\r\n marker: T;\r\n kind: \"primary\" | \"dot\";\r\n parentId?: number;\r\n};\r\n\r\nexport abstract class BaseMarkerManager<TMarker = any> {\r\n protected readonly mapInstance: any;\r\n protected readonly onMarkerClick?: (marker: Property) => void;\r\n protected markerCache = new Map<string, MarkerEntry<TMarker>>();\r\n protected primaryType: string = \"Accommodation\";\r\n protected selectedMarkerId: number | null = null;\r\n\r\n constructor(mapInstance: any, onMarkerClick?: (marker: Property) => void) {\r\n this.mapInstance = mapInstance;\r\n this.onMarkerClick = onMarkerClick;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (primaryType && primaryType !== this.primaryType) {\r\n this.primaryType = primaryType;\r\n }\r\n if (selectedMarkerId !== undefined) {\r\n this.selectedMarkerId = selectedMarkerId;\r\n }\r\n\r\n // Create a set of keys for the new items\r\n const newKeys = new Set(items.map((item) => item.key));\r\n\r\n // Remove markers that are no longer needed\r\n for (const [key, entry] of this.markerCache.entries()) {\r\n if (!newKeys.has(key)) {\r\n this.removeMarkerFromMap(entry.marker);\r\n this.markerCache.delete(key);\r\n }\r\n }\r\n\r\n // Add or update markers\r\n for (const item of items) {\r\n const coords = safeLatLon(item.marker.location);\r\n if (!coords) continue;\r\n\r\n const existing = this.markerCache.get(item.key);\r\n\r\n if (existing) {\r\n // Update existing marker position and content\r\n const isPrimaryType = item.marker.type === this.primaryType;\r\n const isSelected = this.selectedMarkerId === item.marker.tripadvisor_id;\r\n const isAccommodation = item.marker.type === \"Accommodation\";\r\n const isPending =\r\n item.kind === \"primary\"\r\n ? isAccommodation && !item.marker.pricing?.offer?.displayPrice\r\n : isAccommodation &&\r\n item.marker.pricing?.offer?.availability !== \"available\";\r\n\r\n const element = this.getMarkerElement(existing.marker);\r\n if (element) {\r\n if (item.kind === \"primary\") {\r\n updatePrimaryMarkerElement(\r\n element,\r\n isPrimaryType,\r\n isSelected,\r\n isPending,\r\n item.marker\r\n );\r\n } else {\r\n updateDotMarkerElement(\r\n element,\r\n isPrimaryType,\r\n isSelected,\r\n isPending\r\n );\r\n }\r\n }\r\n\r\n try {\r\n this.updateMarkerPosition(existing.marker, coords);\r\n } catch {\r\n // If update fails, remove and recreate\r\n this.removeMarkerFromMap(existing.marker);\r\n this.markerCache.delete(item.key);\r\n this.createAndAddMarker(item, coords);\r\n }\r\n } else {\r\n // Check if there's a marker for the same property with a different key (styling change)\r\n const markerId = item.marker.tripadvisor_id;\r\n let existingEntry: MarkerEntry<TMarker> | undefined;\r\n let existingKey: string | undefined;\r\n\r\n for (const [key, entry] of this.markerCache.entries()) {\r\n if (\r\n extractMarkerIdFromKey(key) === markerId &&\r\n entry.kind === item.kind\r\n ) {\r\n existingEntry = entry;\r\n existingKey = key;\r\n break;\r\n }\r\n }\r\n\r\n if (existingEntry && existingKey) {\r\n // Same marker, different state - update styles instead of recreating\r\n const isPrimaryType = item.marker.type === this.primaryType;\r\n const isSelected =\r\n this.selectedMarkerId === item.marker.tripadvisor_id;\r\n const isAccommodation = item.marker.type === \"Accommodation\";\r\n const isPending =\r\n item.kind === \"primary\"\r\n ? isAccommodation && !item.marker.pricing?.offer?.displayPrice\r\n : isAccommodation &&\r\n item.marker.pricing?.offer?.availability !== \"available\";\r\n\r\n const element = this.getMarkerElement(existingEntry.marker);\r\n if (element) {\r\n if (item.kind === \"primary\") {\r\n updatePrimaryMarkerElement(\r\n element,\r\n isPrimaryType,\r\n isSelected,\r\n isPending,\r\n item.marker\r\n );\r\n } else {\r\n updateDotMarkerElement(\r\n element,\r\n isPrimaryType,\r\n isSelected,\r\n isPending\r\n );\r\n }\r\n }\r\n\r\n // Update zIndex if supported\r\n this.updateMarkerZIndex(\r\n existingEntry.marker,\r\n item,\r\n isPrimaryType,\r\n isSelected\r\n );\r\n\r\n // Update cache with new key\r\n this.markerCache.delete(existingKey);\r\n this.markerCache.set(item.key, existingEntry);\r\n\r\n // Update position\r\n try {\r\n this.updateMarkerPosition(existingEntry.marker, coords);\r\n } catch {\r\n // If update fails, ignore\r\n }\r\n } else {\r\n // Create new marker\r\n this.createAndAddMarker(item, coords);\r\n }\r\n }\r\n }\r\n }\r\n\r\n destroy() {\r\n for (const entry of this.markerCache.values()) {\r\n this.removeMarkerFromMap(entry.marker);\r\n }\r\n this.markerCache.clear();\r\n }\r\n\r\n protected createAndAddMarker(\r\n item: ClusterDisplayItem,\r\n coords: { lon: number; lat: number }\r\n ) {\r\n const element =\r\n item.kind === \"primary\"\r\n ? createPrimaryMarkerElement(\r\n item,\r\n this.primaryType,\r\n this.selectedMarkerId,\r\n this.onMarkerClick\r\n )\r\n : createDotMarkerElement(\r\n item,\r\n this.primaryType,\r\n this.selectedMarkerId,\r\n this.onMarkerClick\r\n );\r\n\r\n if (!element) return;\r\n\r\n const isPrimaryType = item.marker.type === this.primaryType;\r\n const isSelected = this.selectedMarkerId === item.marker.tripadvisor_id;\r\n\r\n try {\r\n const marker = this.createMarker(\r\n element,\r\n coords,\r\n item,\r\n isPrimaryType,\r\n isSelected\r\n );\r\n if (marker) {\r\n this.markerCache.set(item.key, {\r\n key: item.key,\r\n marker,\r\n kind: item.kind,\r\n parentId: item.kind === \"dot\" ? item.parentId : undefined,\r\n });\r\n }\r\n } catch (error) {\r\n console.error(\"Error creating marker\", error);\r\n }\r\n }\r\n\r\n // Abstract methods to be implemented by subclasses\r\n protected abstract createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): TMarker | null;\r\n\r\n protected abstract removeMarkerFromMap(marker: TMarker): void;\r\n\r\n protected abstract updateMarkerPosition(\r\n marker: TMarker,\r\n coords: { lon: number; lat: number }\r\n ): void;\r\n\r\n protected abstract getMarkerElement(marker: TMarker): HTMLElement | null;\r\n\r\n protected updateMarkerZIndex(\r\n marker: TMarker,\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): void {\r\n // Default implementation does nothing (override in subclasses that support zIndex)\r\n }\r\n}\r\n\r\nfunction safeLatLon(location?: { lon?: number; lat?: number }) {\r\n if (typeof location?.lon !== \"number\" || typeof location?.lat !== \"number\") {\r\n return null;\r\n }\r\n if (Number.isNaN(location.lon) || Number.isNaN(location.lat)) {\r\n return null;\r\n }\r\n return { lon: location.lon, lat: location.lat };\r\n}\r\n","import type { Property } from \"../../types\";\r\nimport { BaseMarkerManager } from \"../markermanager\";\r\nimport { ClusterDisplayItem } from \"../../utils/clustering\";\r\n\r\nexport type MapLibreMarkerHandle = {\r\n setLngLat(lngLat: [number, number]): MapLibreMarkerHandle;\r\n addTo(map: any): MapLibreMarkerHandle;\r\n remove(): void;\r\n getElement(): HTMLElement;\r\n};\r\n\r\nexport type MapLibreNamespace = {\r\n Marker: new (options?: {\r\n element?: HTMLElement;\r\n anchor?: string;\r\n }) => MapLibreMarkerHandle;\r\n};\r\n\r\ntype MapLibreMarkerManagerOptions = {\r\n mapInstance: any;\r\n maplibregl: MapLibreNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n};\r\n\r\nexport class MapLibreMarkerManager extends BaseMarkerManager<MapLibreMarkerHandle> {\r\n private readonly MarkerCtor?: MapLibreNamespace[\"Marker\"];\r\n\r\n constructor(options: MapLibreMarkerManagerOptions) {\r\n super(options.mapInstance, options.onMarkerClick);\r\n this.MarkerCtor = options.maplibregl?.Marker;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (!this.MarkerCtor) {\r\n return;\r\n }\r\n super.render(items, primaryType, selectedMarkerId);\r\n }\r\n\r\n protected createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem\r\n ): MapLibreMarkerHandle | null {\r\n if (!this.MarkerCtor) return null;\r\n\r\n return new this.MarkerCtor({\r\n element,\r\n anchor: item.kind === \"primary\" ? \"bottom\" : \"center\",\r\n })\r\n .setLngLat([coords.lon, coords.lat])\r\n .addTo(this.mapInstance);\r\n }\r\n\r\n protected removeMarkerFromMap(marker: MapLibreMarkerHandle): void {\r\n try {\r\n marker.remove();\r\n } catch {\r\n // swallow removal errors\r\n }\r\n }\r\n\r\n protected updateMarkerPosition(\r\n marker: MapLibreMarkerHandle,\r\n coords: { lon: number; lat: number }\r\n ): void {\r\n marker.setLngLat([coords.lon, coords.lat]);\r\n }\r\n\r\n protected getMarkerElement(marker: MapLibreMarkerHandle): HTMLElement | null {\r\n return marker.getElement();\r\n }\r\n}\r\n","import type { Property } from \"../../types\";\r\nimport { BaseMarkerManager } from \"../markermanager\";\r\nimport { ClusterDisplayItem } from \"../../utils/clustering\";\r\n\r\nexport type GoogleMapsMarkerHandle = any; // google.maps.marker.AdvancedMarkerElement\r\n\r\nexport type GoogleMapsNamespace = any; // typeof google.maps\r\n\r\ntype GoogleMapsMarkerManagerOptions = {\r\n mapInstance: any; // google.maps.Map\r\n google: GoogleMapsNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n};\r\n\r\nexport class GoogleMapsMarkerManager extends BaseMarkerManager<GoogleMapsMarkerHandle> {\r\n private readonly google: GoogleMapsNamespace;\r\n\r\n constructor(options: GoogleMapsMarkerManagerOptions) {\r\n super(options.mapInstance, options.onMarkerClick);\r\n this.google = options.google;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (!this.google?.marker?.AdvancedMarkerElement) {\r\n console.warn(\"AdvancedMarkerElement not available\");\r\n return;\r\n }\r\n super.render(items, primaryType, selectedMarkerId);\r\n }\r\n\r\n protected createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): GoogleMapsMarkerHandle | null {\r\n if (!this.google?.marker?.AdvancedMarkerElement) return null;\r\n\r\n const zIndex =\r\n item.kind === \"primary\"\r\n ? isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 12\r\n : 11\r\n : isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 3\r\n : 1;\r\n\r\n return new this.google.marker.AdvancedMarkerElement({\r\n map: this.mapInstance,\r\n position: { lat: coords.lat, lng: coords.lon },\r\n content: element,\r\n zIndex,\r\n });\r\n }\r\n\r\n protected removeMarkerFromMap(marker: GoogleMapsMarkerHandle): void {\r\n try {\r\n marker.map = null;\r\n } catch (error) {\r\n console.error(\"Error removing marker\", error);\r\n }\r\n }\r\n\r\n protected updateMarkerPosition(\r\n marker: GoogleMapsMarkerHandle,\r\n coords: { lon: number; lat: number }\r\n ): void {\r\n marker.position = { lat: coords.lat, lng: coords.lon };\r\n }\r\n\r\n protected getMarkerElement(\r\n marker: GoogleMapsMarkerHandle\r\n ): HTMLElement | null {\r\n const element = marker.content;\r\n return element instanceof HTMLElement ? element : null;\r\n }\r\n\r\n protected updateMarkerZIndex(\r\n marker: GoogleMapsMarkerHandle,\r\n item: ClusterDisplayItem,\r\n isPrimaryType: boolean,\r\n isSelected: boolean\r\n ): void {\r\n const zIndex =\r\n item.kind === \"primary\"\r\n ? isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 12\r\n : 11\r\n : isSelected\r\n ? 20\r\n : isPrimaryType\r\n ? 3\r\n : 1;\r\n marker.zIndex = zIndex;\r\n }\r\n}\r\n","import type { Property } from \"../../types\";\r\nimport { BaseMarkerManager } from \"../markermanager\";\r\nimport { ClusterDisplayItem } from \"../../utils/clustering\";\r\n\r\nexport type MapboxMarkerHandle = {\r\n setLngLat(lngLat: [number, number]): MapboxMarkerHandle;\r\n addTo(map: any): MapboxMarkerHandle;\r\n remove(): void;\r\n getElement(): HTMLElement;\r\n};\r\n\r\nexport type MapboxNamespace = {\r\n Marker: new (options?: {\r\n element?: HTMLElement;\r\n anchor?: string;\r\n }) => MapboxMarkerHandle;\r\n};\r\n\r\ntype MapboxMarkerManagerOptions = {\r\n mapInstance: any;\r\n mapboxgl: MapboxNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n};\r\n\r\nexport class MapboxMarkerManager extends BaseMarkerManager<MapboxMarkerHandle> {\r\n private readonly MarkerCtor?: MapboxNamespace[\"Marker\"];\r\n\r\n constructor(options: MapboxMarkerManagerOptions) {\r\n super(options.mapInstance, options.onMarkerClick);\r\n this.MarkerCtor = options.mapboxgl?.Marker;\r\n }\r\n\r\n render(\r\n items: ClusterDisplayItem[],\r\n primaryType?: string,\r\n selectedMarkerId?: number | null\r\n ) {\r\n if (!this.MarkerCtor) {\r\n return;\r\n }\r\n super.render(items, primaryType, selectedMarkerId);\r\n }\r\n\r\n protected createMarker(\r\n element: HTMLElement,\r\n coords: { lon: number; lat: number },\r\n item: ClusterDisplayItem\r\n ): MapboxMarkerHandle | null {\r\n if (!this.MarkerCtor) return null;\r\n\r\n return new this.MarkerCtor({\r\n element,\r\n anchor: item.kind === \"primary\" ? \"bottom\" : \"center\",\r\n })\r\n .setLngLat([coords.lon, coords.lat])\r\n .addTo(this.mapInstance);\r\n }\r\n\r\n protected removeMarkerFromMap(marker: MapboxMarkerHandle): void {\r\n try {\r\n marker.remove();\r\n } catch {\r\n // swallow removal errors\r\n }\r\n }\r\n\r\n protected updateMarkerPosition(\r\n marker: MapboxMarkerHandle,\r\n coords: { lon: number; lat: number }\r\n ): void {\r\n marker.setLngLat([coords.lon, coords.lat]);\r\n }\r\n\r\n protected getMarkerElement(marker: MapboxMarkerHandle): HTMLElement | null {\r\n return marker.getElement();\r\n }\r\n}\r\n","export {\r\n MapLibreMarkerManager,\r\n type MapLibreMarkerHandle,\r\n type MapLibreNamespace,\r\n} from \"./maplibre/markermanager\";\r\n\r\nexport {\r\n GoogleMapsMarkerManager,\r\n type GoogleMapsMarkerHandle,\r\n type GoogleMapsNamespace,\r\n} from \"./google/markermanager\";\r\n\r\nexport {\r\n MapboxMarkerManager,\r\n type MapboxMarkerHandle,\r\n type MapboxNamespace,\r\n} from \"./mapbox/markermanager\";\r\n\r\n/**\r\n * Abstract base class for map adapters supporting different map libraries\r\n */\r\nexport abstract class MapAdapter {\r\n protected map: any;\r\n\r\n constructor(map: any) {\r\n this.map = map;\r\n }\r\n\r\n /**\r\n * Get the underlying map instance\r\n * @returns {any} The native map instance\r\n */\r\n getMap(): any {\r\n return this.map;\r\n }\r\n\r\n /**\r\n * Initialize the adapter with platform-specific configuration\r\n * @param {any} options Platform-specific initialization options\r\n * @returns {any} The marker manager instance\r\n */\r\n abstract initialize(options: any): any;\r\n\r\n /**\r\n * Get the marker manager instance\r\n * @returns {any} The marker manager\r\n */\r\n abstract getMarkerManager(): any;\r\n\r\n /**\r\n * Clean up event listeners and resources\r\n */\r\n abstract cleanup(): void;\r\n\r\n /**\r\n * Get the map container element\r\n * @returns {HTMLElement | null} The map container DOM element\r\n */\r\n abstract getContainer(): HTMLElement | null;\r\n\r\n /**\r\n * Set up impression tracking when map becomes visible\r\n * @param {() => void} onImpression Callback to invoke when map is visible\r\n */\r\n setupImpressionTracking(onImpression: () => void): void {\r\n if (typeof window === \"undefined\" || !window.IntersectionObserver) {\r\n return;\r\n }\r\n\r\n const container = this.getContainer();\r\n if (!container) {\r\n return;\r\n }\r\n\r\n const observer = new IntersectionObserver(\r\n (entries) => {\r\n entries.forEach((entry) => {\r\n if (entry.isIntersecting) {\r\n onImpression();\r\n observer.disconnect();\r\n }\r\n });\r\n },\r\n { threshold: 0.1 }\r\n );\r\n\r\n observer.observe(container);\r\n\r\n // Store cleanup function\r\n const cleanup = () => observer.disconnect();\r\n const originalCleanup = this.cleanup.bind(this);\r\n this.cleanup = () => {\r\n cleanup();\r\n originalCleanup();\r\n };\r\n }\r\n\r\n /**\r\n * Get the current center coordinates of the map\r\n * @returns {{ lng: number; lat: number }} [longitude, latitude]\r\n */\r\n abstract getCenter(): { lng: number; lat: number };\r\n\r\n /**\r\n * Get the current zoom level of the map\r\n * @returns {number} Current zoom level\r\n */\r\n abstract getZoom(): number;\r\n\r\n /**\r\n * Get the current bearing (rotation) of the map\r\n * @returns {number} Bearing in degrees\r\n */\r\n abstract getBearing(): number;\r\n\r\n /**\r\n * Get the current pitch (tilt) of the map\r\n * @returns {number} Pitch in degrees\r\n */\r\n abstract getPitch(): number;\r\n\r\n /**\r\n * Get the current bounds of the map viewport\r\n * @returns {MapBounds} Map bounds with southwest and northeast corners\r\n */\r\n abstract getMapBounds(): MapBounds;\r\n\r\n /**\r\n * Project a geographical coordinate to screen space\r\n * @param {[number, number]} lngLat [longitude, latitude]\r\n * @returns {{ x: number; y: number }} Screen coordinates\r\n */\r\n abstract project(lngLat: [number, number]): { x: number; y: number };\r\n}\r\n\r\nexport type LngLat = { lng: number; lat: number };\r\n\r\nexport type MapBounds = {\r\n sw: { lat: number; lng: number };\r\n ne: { lat: number; lng: number };\r\n};\r\n","import { MapAdapter, type LngLat, type MapBounds } from \"../index\";\nimport { MapLibreMarkerManager, type MapLibreNamespace } from \"./markermanager\";\nimport type { Property } from \"../../types\";\n\nexport class MapLibreAdapter extends MapAdapter {\n private markerManager?: MapLibreMarkerManager;\n private cleanupFns: Array<() => void> = [];\n\n constructor(map: any) {\n super(map);\n }\n\n initialize(options: {\n maplibregl: MapLibreNamespace;\n onMarkerClick?: (marker: Property) => void;\n onRefresh?: () => void;\n onMapMoveEnd?: (bounds: MapBounds) => void;\n }) {\n this.markerManager = new MapLibreMarkerManager({\n mapInstance: this.map,\n maplibregl: options.maplibregl,\n onMarkerClick: options.onMarkerClick,\n });\n\n if (options.onRefresh) {\n this.attachEventListeners(options.onRefresh);\n }\n\n if (options.onMapMoveEnd) {\n this.attachBoundsTracking(options.onMapMoveEnd);\n }\n\n return this.markerManager;\n }\n\n private attachBoundsTracking(onMapMoveEnd: (bounds: MapBounds) => void) {\n if (!this.map || typeof this.map.on !== \"function\") {\n return;\n }\n\n const handleMoveEnd = () => {\n const bounds = this.getMapBounds();\n onMapMoveEnd(bounds);\n };\n\n // Set initial bounds on load\n const handleLoad = () => {\n const bounds = this.getMapBounds();\n onMapMoveEnd(bounds);\n };\n\n if (this.map.loaded && this.map.loaded()) {\n handleLoad();\n } else {\n this.map.once(\"load\", handleLoad);\n this.cleanupFns.push(() => {\n if (typeof this.map.off === \"function\") {\n this.map.off(\"load\", handleLoad);\n }\n });\n }\n\n this.map.on(\"moveend\", handleMoveEnd);\n this.cleanupFns.push(() => {\n if (typeof this.map.off === \"function\") {\n this.map.off(\"moveend\", handleMoveEnd);\n }\n });\n }\n\n private attachEventListeners(onRefresh: () => void) {\n if (!this.map || typeof this.map.on !== \"function\") {\n return;\n }\n const events = [\"move\", \"zoom\", \"dragend\", \"pitch\", \"rotate\"];\n events.forEach((eventName) => {\n this.map.on(eventName, onRefresh);\n this.cleanupFns.push(() => {\n if (typeof this.map.off === \"function\") {\n this.map.off(eventName, onRefresh);\n }\n });\n });\n }\n\n getMarkerManager() {\n return this.markerManager;\n }\n\n getContainer(): HTMLElement | null {\n return this.map?.getContainer?.() || null;\n }\n\n cleanup() {\n for (const cleanup of this.cleanupFns) {\n try {\n cleanup();\n } catch {\n // ignore\n }\n }\n this.cleanupFns.length = 0;\n }\n\n getMap(): any {\n return this.map;\n }\n\n getCenter(): LngLat {\n const center = this.map.getCenter();\n return { lng: center.lng, lat: center.lat };\n }\n\n getZoom(): number {\n return this.map.getZoom();\n }\n\n getBearing(): number {\n return this.map.getBearing();\n }\n\n getPitch(): number {\n return this.map.getPitch();\n }\n\n getMapBounds(): MapBounds {\n const bounds = this.map.getBounds();\n const sw = bounds.getSouthWest();\n const ne = bounds.getNorthEast();\n return {\n sw: { lat: sw.lat, lng: sw.lng },\n ne: { lat: ne.lat, lng: ne.lng },\n };\n }\n\n project(lngLat: [number, number]) {\n return this.map.project({ lng: lngLat[0], lat: lngLat[1] });\n }\n\n on(event: string, handler: (...args: any[]) => void): void {\n this.map.on(event, handler);\n }\n\n off(event: string, handler: (...args: any[]) => void): void {\n this.map.off(event, handler);\n }\n\n resize(): void {\n this.map.resize();\n }\n\n remove(): void {\n this.cleanup();\n this.map.remove();\n }\n}\n","import { MapAdapter, type LngLat, type MapBounds } from \"../index\";\r\nimport {\r\n GoogleMapsMarkerManager,\r\n type GoogleMapsNamespace,\r\n} from \"./markermanager\";\r\nimport type { Property } from \"../../types\";\r\n\r\nexport class GoogleMapsAdapter extends MapAdapter {\r\n private overlayView: any;\r\n private markerManager?: GoogleMapsMarkerManager;\r\n private cleanupFns: Array<() => void> = [];\r\n\r\n constructor(map: any) {\r\n super(map);\r\n this.initializeOverlayView();\r\n }\r\n\r\n initialize(options: {\r\n google: GoogleMapsNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n onRefresh?: () => void;\r\n onMapMoveEnd?: (bounds: MapBounds) => void;\r\n }) {\r\n this.markerManager = new GoogleMapsMarkerManager({\r\n mapInstance: this.map,\r\n google: options.google,\r\n onMarkerClick: options.onMarkerClick,\r\n });\r\n\r\n if (options.onRefresh) {\r\n this.attachEventListeners(options.onRefresh);\r\n }\r\n\r\n if (options.onMapMoveEnd) {\r\n this.attachBoundsTracking(options.onMapMoveEnd, options.google);\r\n }\r\n\r\n return this.markerManager;\r\n }\r\n\r\n private attachBoundsTracking(\r\n onMapMoveEnd: (bounds: MapBounds) => void,\r\n google: GoogleMapsNamespace\r\n ) {\r\n if (!this.map) {\r\n return;\r\n }\r\n\r\n const handleIdle = () => {\r\n const bounds = this.getMapBounds();\r\n onMapMoveEnd(bounds);\r\n };\r\n\r\n // Set initial bounds\r\n handleIdle();\r\n\r\n const listener = google.event.addListener(this.map, \"idle\", handleIdle);\r\n this.cleanupFns.push(() => {\r\n google.event.removeListener(listener);\r\n });\r\n }\r\n\r\n private attachEventListeners(onRefresh: () => void) {\r\n const events = [\r\n \"center_changed\",\r\n \"zoom_changed\",\r\n \"drag\",\r\n \"heading_changed\",\r\n \"tilt_changed\",\r\n ];\r\n const listeners: any[] = [];\r\n\r\n events.forEach((eventName) => {\r\n const listener = this.map.addListener(eventName, onRefresh);\r\n listeners.push(listener);\r\n });\r\n\r\n this.cleanupFns.push(() => {\r\n listeners.forEach((listener) => {\r\n try {\r\n listener.remove();\r\n } catch {\r\n // ignore\r\n }\r\n });\r\n });\r\n }\r\n\r\n getMarkerManager() {\r\n return this.markerManager;\r\n }\r\n\r\n getContainer(): HTMLElement | null {\r\n return this.map?.getDiv?.() || null;\r\n }\r\n\r\n cleanup() {\r\n for (const cleanup of this.cleanupFns) {\r\n try {\r\n cleanup();\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n this.cleanupFns.length = 0;\r\n }\r\n\r\n private initializeOverlayView() {\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (!googleMaps) return;\r\n\r\n // Create a custom overlay to access the projection\r\n const OverlayView = googleMaps.OverlayView;\r\n if (!OverlayView) return;\r\n\r\n this.overlayView = new OverlayView();\r\n this.overlayView.draw = function () {}; // Required method\r\n this.overlayView.setMap(this.map);\r\n }\r\n\r\n getMap(): any {\r\n return this.map;\r\n }\r\n\r\n getCenter(): LngLat {\r\n const center = this.map.getCenter();\r\n if (!center) {\r\n return { lng: 0, lat: 0 };\r\n }\r\n return { lng: center.lng(), lat: center.lat() };\r\n }\r\n\r\n getZoom(): number {\r\n return this.map.getZoom() ?? 0;\r\n }\r\n\r\n getBearing(): number {\r\n return this.map.getHeading() ?? 0;\r\n }\r\n\r\n getPitch(): number {\r\n return this.map.getTilt() ?? 0;\r\n }\r\n\r\n getMapBounds(): MapBounds {\r\n const bounds = this.map.getBounds();\r\n if (!bounds) {\r\n return {\r\n sw: { lat: 0, lng: 0 },\r\n ne: { lat: 0, lng: 0 },\r\n };\r\n }\r\n const sw = bounds.getSouthWest();\r\n const ne = bounds.getNorthEast();\r\n return {\r\n sw: { lat: sw.lat(), lng: sw.lng() },\r\n ne: { lat: ne.lat(), lng: ne.lng() },\r\n };\r\n }\r\n\r\n project(lngLat: [number, number]): { x: number; y: number } {\r\n if (!this.overlayView) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n const projection = this.overlayView.getProjection();\r\n if (!projection) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (!googleMaps) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n const latLng = new googleMaps.LatLng(lngLat[1], lngLat[0]);\r\n const point = projection.fromLatLngToContainerPixel(latLng);\r\n\r\n if (!point) {\r\n return { x: 0, y: 0 };\r\n }\r\n\r\n return {\r\n x: point.x,\r\n y: point.y,\r\n };\r\n }\r\n\r\n on(event: string, handler: (...args: any[]) => void): void {\r\n this.map.addListener(event, handler);\r\n }\r\n\r\n off(event: string, handler: (...args: any[]) => void): void {\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (googleMaps?.event) {\r\n googleMaps.event.clearListeners(this.map, event);\r\n }\r\n }\r\n\r\n resize(): void {\r\n const googleMaps = (globalThis as any).google?.maps;\r\n if (googleMaps?.event) {\r\n googleMaps.event.trigger(this.map, \"resize\");\r\n }\r\n }\r\n\r\n remove(): void {\r\n this.cleanup();\r\n // Clean up overlay view\r\n if (this.overlayView) {\r\n this.overlayView.setMap(null);\r\n this.overlayView = null;\r\n }\r\n // Google Maps doesn't have a remove method\r\n // Users should handle cleanup themselves\r\n }\r\n}\r\n","import { MapAdapter, type LngLat, type MapBounds } from \"../index\";\r\nimport { MapboxMarkerManager, type MapboxNamespace } from \"./markermanager\";\r\nimport type { Property } from \"../../types\";\r\n\r\nexport class MapboxAdapter extends MapAdapter {\r\n private markerManager?: MapboxMarkerManager;\r\n private cleanupFns: Array<() => void> = [];\r\n\r\n constructor(map: any) {\r\n super(map);\r\n }\r\n\r\n initialize(options: {\r\n mapboxgl: MapboxNamespace;\r\n onMarkerClick?: (marker: Property) => void;\r\n onRefresh?: () => void;\r\n onMapMoveEnd?: (bounds: MapBounds) => void;\r\n }) {\r\n this.markerManager = new MapboxMarkerManager({\r\n mapInstance: this.map,\r\n mapboxgl: options.mapboxgl,\r\n onMarkerClick: options.onMarkerClick,\r\n });\r\n\r\n if (options.onRefresh) {\r\n this.attachEventListeners(options.onRefresh);\r\n }\r\n\r\n if (options.onMapMoveEnd) {\r\n this.attachBoundsTracking(options.onMapMoveEnd);\r\n }\r\n\r\n return this.markerManager;\r\n }\r\n\r\n private attachBoundsTracking(onMapMoveEnd: (bounds: MapBounds) => void) {\r\n if (!this.map || typeof this.map.on !== \"function\") {\r\n return;\r\n }\r\n\r\n const handleMoveEnd = () => {\r\n const bounds = this.getMapBounds();\r\n onMapMoveEnd(bounds);\r\n };\r\n\r\n // Set initial bounds on load\r\n const handleLoad = () => {\r\n const bounds = this.getMapBounds();\r\n // Initialize tempBounds without triggering pendingBounds\r\n onMapMoveEnd(bounds);\r\n };\r\n\r\n if (this.map.loaded && this.map.loaded()) {\r\n handleLoad();\r\n } else {\r\n this.map.once(\"load\", handleLoad);\r\n this.cleanupFns.push(() => {\r\n if (typeof this.map.off === \"function\") {\r\n this.map.off(\"load\", handleLoad);\r\n }\r\n });\r\n }\r\n\r\n this.map.on(\"moveend\", handleMoveEnd);\r\n this.cleanupFns.push(() => {\r\n if (typeof this.map.off === \"function\") {\r\n this.map.off(\"moveend\", handleMoveEnd);\r\n }\r\n });\r\n }\r\n\r\n private attachEventListeners(onRefresh: () => void) {\r\n if (!this.map || typeof this.map.on !== \"function\") {\r\n return;\r\n }\r\n const events = [\"move\", \"zoom\", \"dragend\", \"pitch\", \"rotate\"];\r\n events.forEach((eventName) => {\r\n this.map.on(eventName, onRefresh);\r\n this.cleanupFns.push(() => {\r\n if (typeof this.map.off === \"function\") {\r\n this.map.off(eventName, onRefresh);\r\n }\r\n });\r\n });\r\n }\r\n\r\n getMarkerManager() {\r\n return this.markerManager;\r\n }\r\n\r\n getContainer(): HTMLElement | null {\r\n return this.map?.getContainer?.() || null;\r\n }\r\n\r\n cleanup() {\r\n for (const cleanup of this.cleanupFns) {\r\n try {\r\n cleanup();\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n this.cleanupFns.length = 0;\r\n }\r\n\r\n getMap(): any {\r\n return this.map;\r\n }\r\n\r\n getCenter(): LngLat {\r\n const center = this.map.getCenter();\r\n return { lng: center.lng, lat: center.lat };\r\n }\r\n\r\n getZoom(): number {\r\n return this.map.getZoom();\r\n }\r\n\r\n getBearing(): number {\r\n return this.map.getBearing();\r\n }\r\n\r\n getPitch(): number {\r\n return this.map.getPitch();\r\n }\r\n\r\n getMapBounds(): MapBounds {\r\n const bounds = this.map.getBounds();\r\n const sw = bounds.getSouthWest();\r\n const ne = bounds.getNorthEast();\r\n return {\r\n sw: { lat: sw.lat, lng: sw.lng },\r\n ne: { lat: ne.lat, lng: ne.lng },\r\n };\r\n }\r\n\r\n project(lngLat: [number, number]) {\r\n return this.map.project({ lng: lngLat[0], lat: lngLat[1] });\r\n }\r\n\r\n on(event: string, handler: (...args: any[]) => void): void {\r\n this.map.on(event, handler);\r\n }\r\n\r\n off(event: string, handler: (...args: any[]) => void): void {\r\n this.map.off(event, handler);\r\n }\r\n\r\n resize(): void {\r\n this.map.resize();\r\n }\r\n\r\n remove(): void {\r\n this.cleanup();\r\n this.map.remove();\r\n }\r\n}\r\n","import { MapAdapter } from \"../adapters\";\r\nimport { Property, PropertyType } from \"../types\";\r\n\r\nexport type ClusterDisplayItem =\r\n | {\r\n kind: \"primary\";\r\n marker: Property;\r\n key: string;\r\n }\r\n | {\r\n kind: \"dot\";\r\n marker: Property;\r\n key: string;\r\n parentId: number;\r\n };\r\n\r\nexport type ViewStateSnapshot = {\r\n longitude: number;\r\n latitude: number;\r\n zoom: number;\r\n bearing: number;\r\n pitch: number;\r\n};\r\n\r\nexport type ClusterParams = {\r\n primaryType: PropertyType;\r\n markers: Property[];\r\n map: MapAdapter | null;\r\n selectedMarkerId: number | null;\r\n zoom: number;\r\n collisionThresholdPx?: number;\r\n dotCollisionThresholdPx?: number;\r\n};\r\n\r\nexport type ProjectedMarker = {\r\n marker: Property;\r\n index: number;\r\n x: number;\r\n y: number;\r\n};\r\n\r\nexport function extractViewState(mapInstance: MapAdapter): ViewStateSnapshot {\r\n const center = mapInstance.getCenter();\r\n return {\r\n longitude: center.lng,\r\n latitude: center.lat,\r\n zoom: mapInstance.getZoom(),\r\n bearing: mapInstance.getBearing(),\r\n pitch: mapInstance.getPitch(),\r\n };\r\n}\r\n\r\nconst COLLISION_THRESHOLD_PX_ZOOM_BREAKPOINTS: Array<{\r\n zoom: number;\r\n threshold: number;\r\n}> = [\r\n { zoom: 6, threshold: 120 },\r\n { zoom: 8, threshold: 108 },\r\n { zoom: 10, threshold: 92 },\r\n { zoom: 12, threshold: 80 },\r\n { zoom: 14, threshold: 68 },\r\n { zoom: 16, threshold: 56 },\r\n];\r\n\r\nfunction resolveCollisionThreshold(zoom: number) {\r\n for (const breakpoint of COLLISION_THRESHOLD_PX_ZOOM_BREAKPOINTS) {\r\n if (zoom <= breakpoint.zoom) {\r\n return breakpoint.threshold;\r\n }\r\n }\r\n return 48;\r\n}\r\n\r\nexport function clusterMarkers({\r\n primaryType,\r\n markers,\r\n map,\r\n selectedMarkerId,\r\n zoom,\r\n collisionThresholdPx,\r\n dotCollisionThresholdPx,\r\n}: ClusterParams): ClusterDisplayItem[] {\r\n if (!markers.length) return [];\r\n if (!map) {\r\n return markers.map((marker) => ({\r\n kind: \"primary\" as const,\r\n marker,\r\n key: `primary-${marker.tripadvisor_id}`,\r\n }));\r\n }\r\n\r\n const projected: ProjectedMarker[] = markers\r\n .map((marker, index) => {\r\n const location = marker.location as { lon?: number; lat?: number };\r\n if (\r\n typeof location?.lon !== \"number\" ||\r\n typeof location?.lat !== \"number\"\r\n ) {\r\n return null;\r\n }\r\n const { x, y } = map.project([location.lon, location.lat]);\r\n return { marker, index, x, y };\r\n })\r\n .filter((value): value is ProjectedMarker => Boolean(value));\r\n\r\n if (!projected.length) {\r\n return [];\r\n }\r\n\r\n const threshold = resolveCollisionThreshold(zoom);\r\n const dotThreshold = resolveDotCollisionThreshold(zoom);\r\n const parent = projected.map((_, idx) => idx);\r\n\r\n const find = (i: number): number => {\r\n if (parent[i] === i) return i;\r\n parent[i] = find(parent[i]);\r\n return parent[i];\r\n };\r\n\r\n const union = (a: number, b: number) => {\r\n const rootA = find(a);\r\n const rootB = find(b);\r\n if (rootA === rootB) return;\r\n parent[rootB] = rootA;\r\n };\r\n\r\n for (let i = 0; i < projected.length; i += 1) {\r\n for (let j = i + 1; j < projected.length; j += 1) {\r\n const dx = projected[i].x - projected[j].x;\r\n const dy = projected[i].y - projected[j].y;\r\n if (Math.hypot(dx, dy) <= threshold) {\r\n union(i, j);\r\n }\r\n }\r\n }\r\n\r\n const groups = new Map<number, ProjectedMarker[]>();\r\n for (const item of projected) {\r\n const root = find(item.index);\r\n const group = groups.get(root);\r\n if (group) {\r\n group.push(item);\r\n } else {\r\n groups.set(root, [item]);\r\n }\r\n }\r\n\r\n const clustered: ClusterDisplayItem[] = [];\r\n\r\n groups.forEach((groupItems) => {\r\n if (groupItems.length === 1) {\r\n const [{ marker }] = groupItems;\r\n const isPrimary = marker.type === primaryType;\r\n const isSelected = selectedMarkerId === marker.tripadvisor_id;\r\n clustered.push({\r\n kind: \"primary\",\r\n marker,\r\n key: `primary-${marker.tripadvisor_id}-p${isPrimary ? 1 : 0}-s${\r\n isSelected ? 1 : 0\r\n }-${marker.pricing?.availability}`,\r\n });\r\n return;\r\n }\r\n\r\n const sorted = [...groupItems].sort((a, b) =>\r\n compareMarkers(b.marker, a.marker, primaryType)\r\n );\r\n const [primary, ...rest] = sorted;\r\n const isPrimaryPrimary = primary.marker.type === primaryType;\r\n const isSelectedPrimary =\r\n selectedMarkerId === primary.marker.tripadvisor_id;\r\n clustered.push({\r\n kind: \"primary\",\r\n marker: primary.marker,\r\n key: `primary-${primary.marker.tripadvisor_id}-p${\r\n isPrimaryPrimary ? 1 : 0\r\n }-s${isSelectedPrimary ? 1 : 0}-${primary.marker.pricing?.availability}`,\r\n });\r\n\r\n if (!rest.length) return;\r\n\r\n const dotCandidates: ProjectedMarker[] = [];\r\n const remainder: ProjectedMarker[] = [];\r\n\r\n rest.forEach((item) => {\r\n if (selectedMarkerId && item.marker.tripadvisor_id === selectedMarkerId) {\r\n const isPrimary = item.marker.type === primaryType;\r\n clustered.push({\r\n kind: \"primary\",\r\n marker: item.marker,\r\n key: `primary-${item.marker.tripadvisor_id}-p${\r\n isPrimary ? 1 : 0\r\n }-s1-${item.marker.pricing?.availability}`,\r\n });\r\n return;\r\n }\r\n\r\n if (distancePx(primary, item) <= dotThreshold) {\r\n dotCandidates.push(item);\r\n } else {\r\n remainder.push(item);\r\n }\r\n });\r\n\r\n dotCandidates.forEach((item) => {\r\n const isPrimary = item.marker.type === primaryType;\r\n clustered.push({\r\n kind: \"dot\",\r\n marker: item.marker,\r\n key: `dot-${item.marker.tripadvisor_id}-p${isPrimary ? 1 : 0}-s0-${\r\n item.marker.pricing?.availability\r\n }`,\r\n parentId: primary.marker.tripadvisor_id,\r\n });\r\n });\r\n\r\n if (remainder.length) {\r\n const followUp = clusterMarkers({\r\n markers: remainder.map((item) => item.marker),\r\n map,\r\n selectedMarkerId,\r\n zoom,\r\n primaryType,\r\n collisionThresholdPx,\r\n dotCollisionThresholdPx,\r\n });\r\n clustered.push(...followUp);\r\n }\r\n });\r\n\r\n return clustered;\r\n}\r\n\r\nfunction distancePx(a: ProjectedMarker, b: ProjectedMarker) {\r\n return Math.hypot(a.x - b.x, a.y - b.y);\r\n}\r\n\r\nfunction resolveDotCollisionThreshold(zoom: number) {\r\n const base = resolveCollisionThreshold(zoom);\r\n return Math.max(48, base);\r\n}\r\n\r\nfunction compareMarkers(a: Property, b: Property, primaryType: PropertyType) {\r\n const aIsPrimary = a.type === primaryType;\r\n const bIsPrimary = b.type === primaryType;\r\n if (aIsPrimary && !bIsPrimary) return 1;\r\n if (!aIsPrimary && bIsPrimary) return -1;\r\n\r\n const ratingDiff = resolveRating(a) - resolveRating(b);\r\n if (ratingDiff !== 0) return ratingDiff;\r\n\r\n const priceDiff = resolvePrice(a) - resolvePrice(b);\r\n if (priceDiff !== 0) return priceDiff;\r\n\r\n const reviewsDiff = (a.reviews ?? 0) - (b.reviews ?? 0);\r\n if (reviewsDiff !== 0) return reviewsDiff;\r\n\r\n return a.tripadvisor_id - b.tripadvisor_id;\r\n}\r\n\r\nfunction resolveRating(marker: Property) {\r\n if (typeof marker.rating === \"number\") return marker.rating;\r\n if (marker.rating === undefined || marker.rating === null) return -Infinity;\r\n const parsed = Number(marker.rating);\r\n return Number.isNaN(parsed) ? -Infinity : parsed;\r\n}\r\n\r\nfunction resolvePrice(marker: Property) {\r\n if (!marker.pricing?.offer?.price) return -Infinity;\r\n const numeric = Number(\r\n (marker.pricing.offer.displayPrice ?? \"0\")\r\n .replace(/[^0-9.,-]+/g, \"\")\r\n .replace(/,/g, \"\")\r\n );\r\n return Number.isNaN(numeric) ? -Infinity : numeric;\r\n}\r\n\r\nexport function metersToPixels(meters: number, latitude: number, zoom: number) {\r\n const metersPerPixel =\r\n (Math.cos((latitude * Math.PI) / 180) * 2 * Math.PI * 6378137) /\r\n (256 * 2 ** zoom);\r\n if (!Number.isFinite(metersPerPixel) || metersPerPixel <= 0) {\r\n return meters;\r\n }\r\n return meters / metersPerPixel;\r\n}\r\n","import type { FilterSchema, SmartFilter } from \"../types\";\r\n\r\n/**\r\n * Response type from the API containing filter information\r\n */\r\nexport type ApiFiltersResponse = Pick<\r\n FilterSchema,\r\n | \"amenities\"\r\n | \"hotelStyle\"\r\n | \"price\"\r\n | \"minRating\"\r\n | \"starRating\"\r\n | \"transformed_query\"\r\n | \"selected_restaurant_price_levels\"\r\n>;\r\n\r\n/**\r\n * Converts API filter response into SmartFilter objects that can be used with the SmartFilter component.\r\n * This utility processes the various filter types returned from the API and transforms them into\r\n * a standardized SmartFilter format.\r\n *\r\n * @param apiFilters - The filter response from the API\r\n * @returns An array of SmartFilter objects\r\n *\r\n * @example\r\n * ```typescript\r\n * const apiResponse = await search({ query: \"hotels with pool\" });\r\n * const filters = processApiFilters(apiResponse.filters);\r\n * // filters will contain SmartFilter objects for amenities, price range, ratings, etc.\r\n * ```\r\n */\r\nexport function processApiFilters(\r\n apiFilters: ApiFiltersResponse\r\n): SmartFilter[] {\r\n const filters: SmartFilter[] = [];\r\n\r\n // Process amenities\r\n if (apiFilters.amenities && Array.isArray(apiFilters.amenities)) {\r\n apiFilters.amenities.forEach((amenity: string) => {\r\n filters.push({\r\n id: `amenity-${amenity}`,\r\n label: amenity,\r\n type: \"amenity\",\r\n value: amenity,\r\n });\r\n });\r\n }\r\n\r\n // Process hotel styles\r\n if (apiFilters.hotelStyle && Array.isArray(apiFilters.hotelStyle)) {\r\n apiFilters.hotelStyle.forEach((style: string) => {\r\n filters.push({\r\n id: `hotelStyle-${style}`,\r\n label: style,\r\n type: \"hotelStyle\",\r\n value: style,\r\n });\r\n });\r\n }\r\n\r\n // Process price range\r\n if (apiFilters.price) {\r\n filters.push({\r\n id: \"priceRange\",\r\n label: \"Price Range\",\r\n type: \"priceRange\",\r\n value: `${apiFilters.price.min}-${apiFilters.price.max}`,\r\n priceRange: apiFilters.price,\r\n });\r\n }\r\n\r\n // Process minimum rating\r\n if (\r\n typeof apiFilters.minRating === \"number\" &&\r\n Number.isFinite(apiFilters.minRating)\r\n ) {\r\n filters.push({\r\n id: \"minRating\",\r\n label: `${apiFilters.minRating}+`,\r\n type: \"minRating\",\r\n value: String(apiFilters.minRating),\r\n numericValue: apiFilters.minRating,\r\n });\r\n }\r\n\r\n // Process star rating\r\n if (\r\n typeof apiFilters.starRating === \"number\" &&\r\n Number.isFinite(apiFilters.starRating)\r\n ) {\r\n filters.push({\r\n id: \"starRating\",\r\n label: `${apiFilters.starRating} Stars`,\r\n type: \"starRating\",\r\n value: String(apiFilters.starRating),\r\n numericValue: apiFilters.starRating,\r\n });\r\n }\r\n\r\n // Process transformed query\r\n if (apiFilters.transformed_query) {\r\n filters.push({\r\n id: \"transformed_query\",\r\n label: apiFilters.transformed_query,\r\n type: \"transformed_query\",\r\n value: apiFilters.transformed_query,\r\n });\r\n }\r\n\r\n // Process restaurant price levels\r\n if (apiFilters.selected_restaurant_price_levels) {\r\n filters.push({\r\n id: \"selected_restaurant_price_levels\",\r\n label: apiFilters.selected_restaurant_price_levels.join(\", \"),\r\n type: \"selected_restaurant_price_levels\",\r\n value: apiFilters.selected_restaurant_price_levels.join(\", \"),\r\n priceLevels: apiFilters.selected_restaurant_price_levels,\r\n });\r\n }\r\n\r\n return filters;\r\n}\r\n\r\n/**\r\n * Converts filter objects (SmartFilter or React Filter) back to API-compatible filter format.\r\n * This is the inverse operation of processApiFilters.\r\n * Accepts filters with label as string or ReactNode and normalizes them.\r\n *\r\n * @param filters - Array of filter objects (SmartFilter or React Filter with ReactNode labels)\r\n * @returns API-compatible SmartFilter array\r\n *\r\n * @example\r\n * ```typescript\r\n * const filters = [\r\n * { id: \"amenity-pool\", label: \"Pool\", type: \"amenity\", value: \"Pool\" }\r\n * ];\r\n * const apiFilters = convertToApiFilters(filters);\r\n * // apiFilters will contain normalized SmartFilter objects\r\n * ```\r\n */\r\nexport function convertToApiFilters(filters: any[]): SmartFilter[] {\r\n return filters.map((filter) => {\r\n const apiFilter: SmartFilter = {\r\n id: filter.id,\r\n label:\r\n typeof filter.label === \"string\"\r\n ? filter.label\r\n : String(filter.label || \"\"),\r\n type: filter.type,\r\n value: filter.value,\r\n };\r\n\r\n if (filter.numericValue !== undefined) {\r\n apiFilter.numericValue = filter.numericValue;\r\n }\r\n\r\n if (filter.priceRange) {\r\n // Handle both optional and required min/max\r\n const min = filter.priceRange.min;\r\n const max = filter.priceRange.max;\r\n if (min !== undefined) {\r\n apiFilter.priceRange = {\r\n min,\r\n ...(max !== undefined && { max }),\r\n };\r\n }\r\n }\r\n\r\n if (filter.priceLevels) {\r\n apiFilter.priceLevels = filter.priceLevels;\r\n }\r\n\r\n return apiFilter;\r\n });\r\n}\r\n","import type { MapAdapter } from \"./adapters\";\nimport { MapLibreAdapter } from \"./adapters/maplibre\";\nimport { GoogleMapsAdapter } from \"./adapters/google\";\nimport { MapboxAdapter } from \"./adapters/mapbox\";\nimport type {\n APIResponse,\n FilterSchema,\n HotelPricingAPIResponse,\n InitialLocationData,\n InitialRequestBody,\n PollOptions,\n Price,\n PriceLevel,\n Property,\n PropertyType,\n SmartFilter,\n} from \"./types\";\nimport type { MapLibreNamespace } from \"./adapters/maplibre/markermanager\";\nimport type { GoogleMapsNamespace } from \"./adapters/google/markermanager\";\nimport type { MapboxNamespace } from \"./adapters/mapbox/markermanager\";\nimport {\n ClusterDisplayItem,\n clusterMarkers,\n extractViewState,\n ViewStateSnapshot,\n} from \"./utils/clustering\";\nimport type {\n MapBounds,\n ViewState,\n ActiveLocation,\n FilterState,\n MapState,\n MapStateCallbacks,\n MapStateUpdate,\n} from \"./state-types\";\n\nexport type {\n Property,\n PropertyType,\n PriceLevel,\n Price,\n FilterSchema,\n Locale,\n SmartFilter,\n} from \"./types\";\n\nexport type { ApiFiltersResponse } from \"./utils/filters\";\nexport { processApiFilters, convertToApiFilters } from \"./utils/filters\";\n\nexport type {\n MapBounds,\n ViewState,\n ActiveLocation,\n FilterState,\n MapState,\n MapStateCallbacks,\n MapStateUpdate,\n} from \"./state-types\";\n\nexport type { MapLibreNamespace } from \"./adapters/maplibre/markermanager\";\n\nexport type { GoogleMapsNamespace } from \"./adapters/google/markermanager\";\n\nexport type { MapboxNamespace } from \"./adapters/mapbox/markermanager\";\n\n// Environment configuration\nexport type Environment = \"prod\" | \"test\";\n\nconst API_URLS: Record<Environment, string> = {\n prod: \"https://api.mapfirst.ai\",\n test: \"https://api.mapfirst.ai/test\",\n};\n\n// Properties fetch error class\nexport class PropertiesFetchError extends Error {\n status: number;\n code?: string;\n\n constructor({\n message,\n status,\n code,\n }: {\n message: string;\n status: number;\n code?: string;\n }) {\n super(message);\n this.name = \"PropertiesFetchError\";\n this.status = status;\n this.code = code;\n }\n}\n\ntype PropertiesErrorResponse = {\n error?: string;\n detail?: string;\n code?: string;\n};\n\ntype FetchPropertiesOptions = {\n signal?: AbortSignal;\n};\n\n// Image fetch types\nexport type TripAdvisorImage = {\n [key: string]: { url: string };\n};\n\nexport type TripAdvisorImageResponse = {\n photos: TripAdvisorImage[];\n};\n\n// Fetch images for a property from TripAdvisor\nexport async function fetchImages(\n tripadvisorId: number,\n limit: number = 1\n): Promise<string | null> {\n try {\n const response = await fetch(\n `https://l4detuz832.execute-api.us-east-1.amazonaws.com/dev/photo?id=${tripadvisorId}&limit=${limit}`\n );\n\n if (!response.ok) {\n return null;\n }\n\n const data = (await response.json()) as TripAdvisorImageResponse;\n\n if (data.photos && data.photos.length > 0) {\n const imageUrl = data.photos[0][\"FullSizeURL\"].url;\n\n // Verify the image URL is accessible\n const imageResponse = await fetch(imageUrl);\n if (imageResponse.ok) {\n return imageUrl;\n }\n }\n\n return null;\n } catch (error) {\n console.debug(\"Failed to fetch images:\", error);\n return null;\n }\n}\n\n// Fetch properties from API\nexport async function fetchProperties<TBody = any, TResponse = any>(\n url: string,\n body: TBody,\n apiKey?: string,\n { signal }: FetchPropertiesOptions = {}\n): Promise<TResponse> {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(apiKey && {\n \"X-API-Key\": apiKey,\n }),\n },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!response.ok) {\n let message = `Unexpected response: ${response.status}`;\n let code: string | undefined;\n try {\n const errorBody = (await response.json()) as PropertiesErrorResponse;\n message = errorBody.detail ?? errorBody.error ?? message;\n code = errorBody.code;\n } catch {\n // ignore JSON parsing errors and fall back to status-based message\n }\n throw new PropertiesFetchError({ message, status: response.status, code });\n }\n\n return (await response.json()) as TResponse;\n}\n\nfunction toISO(date: Date | string): string {\n if (typeof date === \"string\") return date;\n return date.toISOString().slice(0, 10);\n}\n\nasync function trackMapImpression(\n apiUrl: string,\n apiKey?: string,\n metadata?: Record<string, any>\n): Promise<void> {\n try {\n await fetch(`${apiUrl}/${apiKey}/impressions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(apiKey && { \"X-API-Key\": apiKey }),\n },\n body: JSON.stringify({\n timestamp: new Date().toISOString(),\n type: \"map_view\",\n ...metadata,\n }),\n });\n } catch (error) {\n // Silently fail - don't block user experience for analytics\n console.debug(\"Failed to track map impression:\", error);\n }\n}\n\nexport type BaseMapFirstOptions = {\n properties?: Property[];\n primaryType?: PropertyType;\n selectedMarkerId?: number | null;\n clusterRadiusMeters?: number;\n autoSelectOnClick?: boolean;\n onClusterUpdate?: (\n clusters: ClusterDisplayItem[],\n viewState: ViewStateSnapshot | null\n ) => void;\n // State management options\n state?: Partial<MapState>;\n callbacks?: MapStateCallbacks;\n // API configuration\n useApi?: boolean; // default: true, can only be set at initialization\n environment?: Environment;\n apiKey?: string;\n requestBody?: any;\n // Initial location data (alternative to requestBody)\n initialLocationData?: InitialLocationData;\n // Map behavior options\n fitBoundsPadding?: {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n };\n apiUrl?: string;\n};\n\ntype AdapterDrivenOptions = BaseMapFirstOptions & {\n adapter: MapAdapter;\n platform?: undefined;\n};\n\ntype MapLibreOptions = BaseMapFirstOptions & {\n platform: \"maplibre\";\n mapInstance?: any;\n maplibregl: MapLibreNamespace;\n onMarkerClick?: (marker: Property) => void;\n};\n\ntype GoogleMapsOptions = BaseMapFirstOptions & {\n platform: \"google\";\n mapInstance?: any; // google.maps.Map\n google: GoogleMapsNamespace;\n onMarkerClick?: (marker: Property) => void;\n};\n\ntype MapboxOptions = BaseMapFirstOptions & {\n platform: \"mapbox\";\n mapInstance?: any;\n mapboxgl: MapboxNamespace;\n onMarkerClick?: (marker: Property) => void;\n};\n\nexport type MapFirstOptions =\n | AdapterDrivenOptions\n | MapLibreOptions\n | GoogleMapsOptions\n | MapboxOptions;\n\nconst DEFAULT_PRIMARY_TYPE: PropertyType = \"Accommodation\";\n\n// Helper function to calculate default check-in/check-out dates\nfunction getDefaultDates(): { checkIn: Date; checkOut: Date } {\n const dayMs = 24 * 60 * 60 * 1000;\n const base = new Date(Date.now() + 10 * dayMs);\n const daysUntilSaturday = (6 - base.getDay() + 7) % 7;\n const checkIn = new Date(base.getTime() + daysUntilSaturday * dayMs);\n const startDay = checkIn.getDay();\n const daysUntilWeekend = startDay === 0 ? 6 : 6 - startDay;\n const checkOut = new Date(checkIn.getTime() + (daysUntilWeekend + 1) * dayMs);\n return { checkIn, checkOut };\n}\n\nexport class MapFirstCore {\n private adapter: MapAdapter | null = null;\n private properties: Property[] = [];\n private primaryType?: PropertyType;\n private selectedMarkerId: number | null = null;\n private destroyed = false;\n private clusterItems: ClusterDisplayItem[] = [];\n private isMapAttached = false;\n\n // State management\n private state: MapState;\n private callbacks: MapStateCallbacks;\n\n // API configuration\n private useApi: boolean;\n private readonly environment: Environment;\n private readonly apiUrl: string;\n private apiKey?: string;\n private currentPlatform: \"google\" | \"maplibre\" | \"mapbox\" | undefined;\n private requestBody?: any;\n private readonly fitBoundsPadding: {\n top: number;\n bottom: number;\n left: number;\n right: number;\n };\n\n constructor(private readonly options: MapFirstOptions) {\n this.properties = [...(options.properties ?? [])];\n this.primaryType = options.primaryType;\n this.selectedMarkerId = options.selectedMarkerId ?? null;\n\n // Initialize API configuration\n this.useApi = options.useApi ?? true;\n this.environment = options.environment ?? \"prod\";\n this.apiUrl = options.apiUrl ?? API_URLS[this.environment];\n this.apiKey = options.apiKey;\n this.requestBody = options.requestBody;\n this.currentPlatform = options.platform;\n\n // Validate platform restrictions when useApi is false\n if (!this.useApi && options.platform && options.platform !== \"maplibre\") {\n throw new Error(\n \"When useApi is false, only maplibre platform is supported. Google Maps and Mapbox require API usage.\"\n );\n }\n\n // Determine if using Google Maps\n const isGoogleMaps = isGoogleMapsOptions(options);\n\n // Set default padding based on platform (Google Maps uses 0, others use padding)\n this.fitBoundsPadding = {\n top: options.fitBoundsPadding?.top ?? (isGoogleMaps ? 0 : 50),\n bottom: options.fitBoundsPadding?.bottom ?? (isGoogleMaps ? 0 : 160),\n left: options.fitBoundsPadding?.left ?? (isGoogleMaps ? 0 : 50),\n right: options.fitBoundsPadding?.right ?? (isGoogleMaps ? 0 : 50),\n };\n\n // Initialize default dates\n const defaultDates = getDefaultDates();\n\n // Initialize state\n this.state = {\n center: [0, 0],\n zoom: 0,\n bounds: null,\n pendingBounds: null,\n tempBounds: null,\n properties: this.properties,\n primary: this.primaryType ?? DEFAULT_PRIMARY_TYPE,\n selectedPropertyId: this.selectedMarkerId,\n initialLoading: true,\n isSearching: false,\n firstCallDone: false,\n filters: {\n checkIn: defaultDates.checkIn,\n checkOut: defaultDates.checkOut,\n numAdults: 2,\n numRooms: 1,\n ...(options.initialLocationData?.currency && {\n currency: options.initialLocationData.currency,\n }),\n },\n activeLocation: {\n country: \"\",\n location_id: null,\n locationName: \"\",\n coordinates: [0, 0],\n },\n isFlyToAnimating: false,\n ...options.state,\n };\n\n this.callbacks = options.callbacks ?? {};\n\n // Initialize map adapter if mapInstance is provided\n if (this.hasMapInstance(options)) {\n this.adapter = this.createAdapter(options);\n this.isMapAttached = true;\n this.refresh();\n }\n\n // Handle initial location data or auto-load properties\n if (options.initialLocationData) {\n this.initializeFromLocationData(options.initialLocationData);\n } else if (this.requestBody && this.isMapAttached) {\n this.autoLoadProperties();\n }\n }\n\n private hasMapInstance(options: MapFirstOptions): boolean {\n if (\"adapter\" in options && options.adapter) return true;\n if (\"mapInstance\" in options && options.mapInstance) return true;\n return false;\n }\n\n private async initializeFromLocationData(\n locationData: InitialLocationData\n ): Promise<void> {\n if (!this.useApi) {\n console.warn(\n \"initializeFromLocationData requires API usage. Set useApi to true.\"\n );\n return;\n }\n try {\n const { city, country, query } = locationData;\n\n let requestBody: any = {\n filters: this.getFilters(),\n initial: true,\n };\n\n // Geo-lookup if city/country provided\n if ((city && country) || country) {\n const geoResponse = await fetch(\n `${this.apiUrl}/geo-lookup?country=${encodeURIComponent(country!)}${\n city ? `&city=${encodeURIComponent(city)}` : \"\"\n }`,\n {\n headers: {\n ...(this.apiKey && {\n \"X-API-Key\": this.apiKey,\n }),\n },\n }\n );\n\n if (geoResponse.ok) {\n const geoData = await geoResponse.json();\n\n let finalCity = city;\n if (\n geoData.location_name &&\n geoData.path3_name &&\n geoData.location_name === geoData.path3_name\n ) {\n finalCity = undefined;\n }\n if (geoData.location_name) finalCity = geoData.location_name;\n\n const finalCountry = geoData.path3_name || country;\n\n requestBody = {\n ...requestBody,\n city: finalCity,\n country: finalCountry,\n location_id: geoData.location_id,\n longitude: geoData.longitude,\n latitude: geoData.latitude,\n };\n\n // Update active location\n this.setActiveLocation({\n city: finalCity,\n country: finalCountry,\n location_id: geoData.location_id,\n locationName:\n finalCity && finalCountry\n ? `${finalCity}, ${finalCountry}`\n : finalCountry || \"\",\n coordinates: [geoData.latitude, geoData.longitude],\n });\n\n // Update state center\n this.setState({\n center: [geoData.latitude, geoData.longitude],\n zoom: 12,\n });\n } else {\n this.handleError(\n new Error(`Geo mapping fetch failed: ${geoResponse.statusText}`),\n \"initializeFromLocationData\"\n );\n }\n } else if (query) {\n requestBody.query = query;\n }\n\n this.requestBody = requestBody;\n\n // Auto-load properties if map is already attached\n if (this.isMapAttached) {\n await this.autoLoadProperties();\n }\n } catch (error) {\n this.handleError(error, \"initializeFromLocationData\");\n }\n }\n\n private async autoLoadProperties(): Promise<void> {\n if (!this.useApi) {\n console.warn(\n \"autoLoadProperties requires API usage. Set useApi to true.\"\n );\n return;\n }\n if (!this.requestBody) return;\n\n // Default request body structure based on InitialDataLoader.tsx\n const defaultRequestBody: InitialRequestBody = {\n filters: this.getFilters(),\n initial: true,\n ...this.requestBody,\n };\n\n await this.runPropertiesSearch({\n body: defaultRequestBody,\n onError: (error) => {\n this.handleError(error, \"autoLoadProperties\");\n this.callbacks.onPropertiesLoadError?.(error);\n },\n });\n }\n\n attachMap(\n mapInstance: any,\n config: {\n platform: \"maplibre\" | \"google\" | \"mapbox\";\n maplibregl?: MapLibreNamespace;\n google?: GoogleMapsNamespace;\n mapboxgl?: MapboxNamespace;\n onMarkerClick?: (marker: Property) => void;\n }\n ): void {\n // Validate platform restrictions when useApi is false\n if (!this.useApi && config.platform !== \"maplibre\") {\n throw new Error(\n \"When useApi is false, only maplibre platform is supported. Google Maps and Mapbox require API usage.\"\n );\n }\n\n if (this.isMapAttached) {\n console.warn(\"Map is already attached. Destroying previous adapter.\");\n if (this.adapter) {\n const markerManager = this.adapter.getMarkerManager();\n markerManager?.destroy();\n this.adapter.cleanup();\n }\n }\n\n const adapterConfig: any = {\n ...this.options,\n platform: config.platform,\n mapInstance,\n maplibregl: config.maplibregl,\n google: config.google,\n mapboxgl: config.mapboxgl,\n onMarkerClick: config.onMarkerClick,\n };\n\n this.currentPlatform = config.platform;\n this.adapter = this.createAdapter(adapterConfig);\n this.isMapAttached = true;\n this.refresh();\n\n // Auto-load properties if we have requestBody and haven't loaded yet\n if (this.requestBody && !this.state.firstCallDone) {\n this.autoLoadProperties();\n }\n }\n\n private createAdapter(options: MapFirstOptions): MapAdapter | null {\n if (isMapLibreOptions(options) && options.mapInstance) {\n return this.initializeAdapter(new MapLibreAdapter(options.mapInstance), {\n maplibregl: options.maplibregl,\n onMarkerClick: options.onMarkerClick,\n });\n }\n if (isGoogleMapsOptions(options) && options.mapInstance) {\n return this.initializeAdapter(\n new GoogleMapsAdapter(options.mapInstance),\n { google: options.google, onMarkerClick: options.onMarkerClick }\n );\n }\n if (isMapboxOptions(options) && options.mapInstance) {\n return this.initializeAdapter(new MapboxAdapter(options.mapInstance), {\n mapboxgl: options.mapboxgl,\n onMarkerClick: options.onMarkerClick,\n });\n }\n if (\"adapter\" in options && options.adapter) {\n return options.adapter;\n }\n return null;\n }\n\n private initializeAdapter(adapter: MapAdapter, config: any): MapAdapter {\n const shouldAutoSelect = this.options.autoSelectOnClick ?? true;\n adapter.initialize({\n ...config,\n onMarkerClick: (marker: Property) => {\n if (marker.location) {\n this.flyMapTo(marker.location.lon, marker.location.lat, 14);\n }\n\n // Change primary type if clicking a secondary marker\n if (marker.type !== this.primaryType) {\n this.setPrimaryType(marker.type);\n }\n if (shouldAutoSelect) {\n this.setSelectedMarker(\n marker.tripadvisor_id === this.selectedMarkerId\n ? null\n : marker.tripadvisor_id\n );\n }\n config.onMarkerClick?.(marker);\n },\n onRefresh: () => this.refresh(),\n onMapMoveEnd: (bounds: MapBounds) => {\n // Only call handleMapMoveEnd if it's a real movement, not initial setup\n if (this.state.tempBounds === null) {\n this.setTempBounds(bounds);\n this.setPendingBounds(null);\n } else {\n this.handleMapMoveEnd(bounds);\n }\n },\n });\n\n // Set up impression tracking when map becomes visible in viewport\n if (this.useApi) {\n adapter.setupImpressionTracking(() => {\n // trackMapImpression(this.apiUrl, this.apiKey, {\n // platform: this.currentPlatform,\n // environment: this.environment,\n // });\n console.log(\"ToDo: Track Map Impression\");\n });\n }\n\n return adapter;\n }\n\n _setProperties(properties: Property[]) {\n this.ensureAlive();\n this.properties = [\n ...properties.filter((x) =>\n x.type === \"Accommodation\"\n ? x.pricing?.availability !== \"unavailable\"\n : true\n ),\n ];\n this.updateState({\n properties: this.properties,\n });\n this.callbacks.onPropertiesChange?.(properties);\n this.refresh();\n }\n\n addProperty(property: Property) {\n this.ensureAlive();\n this.properties = [...this.properties, property];\n this.updateState({ properties: this.properties });\n this.callbacks.onPropertiesChange?.(this.properties);\n this.refresh();\n }\n\n clearProperties() {\n this.ensureAlive();\n this.properties = [];\n this.updateState({ properties: [] });\n this.callbacks.onPropertiesChange?.([]);\n this.refresh();\n }\n\n setPrimaryType(primary: PropertyType) {\n this.ensureAlive();\n if (this.primaryType === primary) return;\n this.primaryType = primary;\n this.updateState({ primary });\n this.callbacks.onPrimaryTypeChange?.(primary);\n this.refresh();\n }\n\n setSelectedMarker(markerId: number | null) {\n this.ensureAlive();\n if (this.selectedMarkerId === markerId) return;\n\n // If selecting a marker, check if we need to change the primary type\n if (markerId !== null) {\n const marker = this.properties.find((p) => p.tripadvisor_id === markerId);\n if (marker && marker.type !== this.primaryType) {\n this.setPrimaryType(marker.type);\n }\n }\n\n this.selectedMarkerId = markerId;\n this.updateState({ selectedPropertyId: markerId });\n this.callbacks.onSelectedPropertyChange?.(markerId);\n this.refresh();\n }\n\n // State management methods\n getState(): Readonly<MapState> {\n return { ...this.state };\n }\n\n // Centralized error handler\n private handleError(error: unknown, context: string = \"MapFirstCore\") {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const errorObj = error instanceof Error ? error : new Error(errorMessage);\n\n console.error(`[${context}]`, errorMessage);\n\n if (this.callbacks.onError) {\n this.callbacks.onError(errorObj, context);\n }\n }\n\n updateState(update: MapStateUpdate) {\n this.state = { ...this.state, ...update };\n }\n\n setState(newState: Partial<MapState>) {\n const prevState = { ...this.state };\n this.updateState(newState);\n\n // Trigger callbacks for changed values\n if (newState.center !== undefined && newState.center !== prevState.center) {\n this.callbacks.onCenterChange?.(newState.center, this.state.zoom);\n }\n if (newState.zoom !== undefined && newState.zoom !== prevState.zoom) {\n this.callbacks.onZoomChange?.(newState.zoom);\n }\n if (newState.bounds !== undefined && newState.bounds !== prevState.bounds) {\n this.callbacks.onBoundsChange?.(newState.bounds);\n }\n if (\n newState.pendingBounds !== undefined &&\n newState.pendingBounds !== prevState.pendingBounds\n ) {\n this.callbacks.onPendingBoundsChange?.(newState.pendingBounds);\n }\n if (\n newState.filters !== undefined &&\n newState.filters !== prevState.filters\n ) {\n this.callbacks.onFiltersChange?.(newState.filters);\n }\n if (\n newState.activeLocation !== undefined &&\n newState.activeLocation !== prevState.activeLocation\n ) {\n this.callbacks.onActiveLocationChange?.(newState.activeLocation);\n }\n if (\n newState.initialLoading !== undefined &&\n newState.initialLoading !== prevState.initialLoading\n ) {\n this.callbacks.onLoadingStateChange?.(newState.initialLoading);\n }\n if (\n newState.isSearching !== undefined &&\n newState.isSearching !== prevState.isSearching\n ) {\n this.callbacks.onSearchingStateChange?.(newState.isSearching);\n }\n }\n\n setFilters(filters: FilterState) {\n this.setState({ filters });\n }\n\n setActiveLocation(location: ActiveLocation) {\n this.setState({ activeLocation: location });\n }\n\n setBounds(bounds: MapBounds | null) {\n this.setState({ bounds });\n }\n\n setPendingBounds(bounds: MapBounds | null) {\n this.setState({ pendingBounds: bounds });\n }\n\n setTempBounds(bounds: MapBounds | null) {\n this.setState({ tempBounds: bounds });\n }\n\n setLoading(loading: boolean) {\n this.setState({ initialLoading: loading });\n }\n\n setSearching(searching: boolean) {\n this.setState({ isSearching: searching });\n }\n\n setFlyToAnimating(animating: boolean) {\n this.setState({ isFlyToAnimating: animating });\n }\n\n handleMapMoveEnd(bounds: MapBounds) {\n if (this.state.isFlyToAnimating) {\n this.setState({\n isFlyToAnimating: false,\n tempBounds: bounds,\n pendingBounds: null,\n });\n return;\n }\n\n const tempBounds = this.state.tempBounds;\n if (!tempBounds) {\n this.setState({\n tempBounds: bounds,\n pendingBounds: bounds,\n });\n return;\n }\n\n const delta = 0.01;\n const hasChanged =\n Math.abs(bounds.sw.lat - tempBounds.sw.lat) > delta ||\n Math.abs(bounds.sw.lng - tempBounds.sw.lng) > delta ||\n Math.abs(bounds.ne.lat - tempBounds.ne.lat) > delta ||\n Math.abs(bounds.ne.lng - tempBounds.ne.lng) > delta;\n\n if (hasChanged) {\n this.setState({ pendingBounds: bounds });\n } else {\n this.setState({ pendingBounds: null });\n }\n }\n\n flyMapTo(\n longitude: number,\n latitude: number,\n zoom?: number | null,\n animation: boolean = true\n ) {\n this.ensureAlive();\n this.setState({ center: [latitude, longitude] });\n if (typeof zoom === \"number\") {\n this.setState({ zoom });\n }\n\n if (!this.adapter) return;\n const mapInstance = this.adapter.getMap();\n if (!mapInstance) return;\n\n if (this.currentPlatform === \"google\") {\n this.setFlyToAnimating(false);\n mapInstance.setCenter({ lat: latitude, lng: longitude });\n if (zoom !== null && typeof zoom === \"number\") {\n mapInstance.setZoom(zoom ?? 13);\n }\n return;\n }\n\n // MapLibre/Mapbox\n if (animation === false) {\n this.setFlyToAnimating(false);\n if (mapInstance.jumpTo) {\n mapInstance.jumpTo({\n center: [longitude, latitude],\n ...(zoom !== null && { zoom: zoom ?? 13 }),\n });\n }\n return;\n }\n\n this.setFlyToAnimating(true);\n if (mapInstance.flyTo) {\n mapInstance.flyTo({\n center: [longitude, latitude],\n ...(zoom !== null && { zoom: zoom ?? 13 }),\n });\n }\n }\n\n flyToPOIs(\n pois?: { lat: number; lng: number }[],\n type?: PropertyType,\n animate: boolean = true\n ) {\n this.ensureAlive();\n if (!this.adapter) return;\n const mapInstance = this.adapter.getMap();\n if (!mapInstance) return;\n\n let points = pois;\n if (!points || points.length === 0) {\n points = this.properties\n .filter(\n (x) =>\n x.location !== undefined &&\n (type !== undefined ? x.type === type : true)\n )\n .map((h) => ({\n lat: h.location!.lat,\n lng: h.location!.lon,\n }));\n }\n if (!points || points.length === 0) return;\n\n // Check if this is Google Maps\n\n if (points.length === 1) {\n const poi = points[0];\n if (this.currentPlatform === \"google\") {\n mapInstance.setCenter({ lat: poi.lat, lng: poi.lng });\n mapInstance.setZoom(13);\n } else if (mapInstance.flyTo) {\n mapInstance.flyTo({\n center: [poi.lng, poi.lat],\n zoom: 13,\n });\n }\n } else {\n if (this.currentPlatform === \"google\") {\n // Google Maps\n const LatLngBounds = (window as any).google?.maps?.LatLngBounds;\n if (LatLngBounds) {\n const bounds = new LatLngBounds();\n points.forEach((poi) => {\n bounds.extend({ lat: poi.lat, lng: poi.lng });\n });\n if (animate) {\n this.setFlyToAnimating(true);\n }\n mapInstance.fitBounds(bounds, this.fitBoundsPadding);\n }\n } else if (mapInstance.fitBounds) {\n // MapLibre/Mapbox\n const bounds: [[number, number], [number, number]] = [\n [points[0].lng, points[0].lat],\n [points[0].lng, points[0].lat],\n ];\n\n points.forEach((poi) => {\n bounds[0][0] = Math.min(bounds[0][0], poi.lng);\n bounds[0][1] = Math.min(bounds[0][1], poi.lat);\n bounds[1][0] = Math.max(bounds[1][0], poi.lng);\n bounds[1][1] = Math.max(bounds[1][1], poi.lat);\n });\n\n if (animate) {\n this.setFlyToAnimating(true);\n }\n mapInstance.fitBounds(bounds, {\n padding: this.fitBoundsPadding,\n animate,\n });\n }\n }\n }\n\n getFilters() {\n const filters = { ...this.state.filters };\n // Convert Date objects to ISO strings for API compatibility\n if (filters.checkIn instanceof Date) {\n filters.checkIn = toISO(filters.checkIn);\n }\n if (filters.checkOut instanceof Date) {\n filters.checkOut = toISO(filters.checkOut);\n }\n return filters as FilterSchema;\n }\n\n async pollForPricing({\n pollingLink,\n maxAttempts = 15,\n delayMs = 2000,\n isCancelled,\n price,\n limit,\n }: PollOptions): Promise<{\n completed: boolean;\n pollData?: HotelPricingAPIResponse;\n }> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\"pollForPricing requires API usage. Set useApi to true.\");\n return { completed: false };\n }\n\n if (!pollingLink) {\n return { completed: false };\n }\n\n let completed = false;\n let pollData: HotelPricingAPIResponse | undefined = undefined;\n\n const filters = this.getFilters();\n if (limit) {\n filters.limit = limit;\n }\n\n const body: any = {\n filters,\n pollingLink,\n };\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n if (isCancelled?.()) {\n return { completed, pollData };\n }\n\n try {\n const pollResp = await fetch(\n `${this.apiUrl}/ta-polling?pollingNumber=${attempt}`,\n {\n method: \"POST\",\n body: JSON.stringify(body),\n headers: {\n \"Content-Type\": \"application/json\",\n ...(this.apiKey && {\n \"X-API-Key\": this.apiKey,\n }),\n },\n }\n );\n\n if (!pollResp.ok) {\n throw new PropertiesFetchError({\n message: `Poll failed: ${pollResp.status}`,\n status: pollResp.status,\n });\n }\n\n pollData = await pollResp.json();\n\n if (isCancelled?.()) {\n return { completed, pollData };\n }\n\n const results = pollData?.success?.results ?? [];\n if (results.length > 0) {\n this.setProperties((prev) => {\n const resultIds = new Set(results.map((h) => h.tripadvisor_id));\n const updatedProperties = prev.filter(\n (property) =>\n property.type !== \"Accommodation\" ||\n resultIds.has(property.tripadvisor_id)\n );\n\n results.forEach((property) => {\n if (!property.location) return;\n if (\n property.pricing?.offer?.price &&\n price &&\n (property.pricing?.offer?.price < price?.min ||\n property.pricing?.offer?.price > price?.max)\n ) {\n property.pricing.availability = \"unavailable\";\n }\n const existingIndex = updatedProperties.findIndex(\n (h) => h.tripadvisor_id === property.tripadvisor_id\n );\n if (existingIndex >= 0) {\n updatedProperties[existingIndex] = property;\n } else {\n updatedProperties.push(property);\n }\n });\n return updatedProperties;\n });\n }\n\n if (pollData?.success?.isComplete) {\n completed = true;\n break;\n }\n } catch (error) {\n this.handleError(error, \"pollForPricing\");\n this.callbacks.onPropertiesLoadError?.(error);\n break;\n }\n\n if (attempt < maxAttempts - 1) {\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n return { completed, pollData };\n }\n\n private setProperties(updater: (prev: Property[]) => Property[]): void {\n const updatedProperties = updater(this.properties);\n this._setProperties(updatedProperties);\n }\n\n private mostCommonTypeFromProperties(properties: Property[]): PropertyType {\n const typeCounts = properties.reduce((counts, property) => {\n counts[property.type] = (counts[property.type] || 0) + 1;\n return counts;\n }, {} as Record<PropertyType, number>);\n\n return Object.entries(typeCounts).reduce((a, b) =>\n typeCounts[a[0] as PropertyType] > typeCounts[b[0] as PropertyType]\n ? a\n : b\n )[0] as PropertyType;\n }\n\n async runPropertiesSearch({\n body,\n beforeApplyProperties,\n smartFiltersClearable,\n onError,\n }: {\n body: InitialRequestBody;\n beforeApplyProperties?: (data: APIResponse) => {\n price?: Price | null;\n limit?: number;\n };\n smartFiltersClearable?: boolean;\n onError?: (error: unknown) => void;\n }): Promise<APIResponse | null> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\n \"runPropertiesSearch requires API usage. Set useApi to true.\"\n );\n onError?.(new Error(\"API usage is disabled\"));\n return null;\n }\n\n this.setState({ firstCallDone: false });\n this.setSearching(true);\n this.clearProperties();\n\n try {\n const data = await fetchProperties<InitialRequestBody, APIResponse>(\n `${this.apiUrl}/properties`,\n body,\n this.apiKey\n );\n\n this.updateActiveLocationFromResponse(data);\n\n let price: Price | null = null;\n let limit: number = 30;\n let primary_type: PropertyType | undefined = data.filters.primary_type;\n\n if (beforeApplyProperties) {\n const result = beforeApplyProperties(data);\n price = result.price ?? null;\n limit = result.limit ?? 30;\n }\n\n // Track if we've already flown to POIs\n const flown = data.properties.some((x) => !!x.location);\n\n // Apply price filtering if price range is specified\n const filteredProperties = price\n ? data.properties.map((x) =>\n x.pricing?.offer\n ? {\n ...x,\n pricing: {\n ...x.pricing,\n availability:\n x.pricing.offer.price &&\n (x.pricing.offer.price < price.min ||\n x.pricing.offer.price > price.max)\n ? (\"unavailable\" as const)\n : x.pricing.availability,\n },\n }\n : x\n )\n : data.properties;\n\n // Apply properties\n this._setProperties(filteredProperties);\n\n // Fly to POIs if properties have locations\n if (flown) {\n this.flyToPOIs(\n data.properties\n .filter(\n (x) =>\n !!x.location &&\n (data.filters.primary_type\n ? x.type === data.filters.primary_type\n : true)\n )\n .map((x) => ({ lat: x.location!.lat, lng: x.location!.lon })),\n undefined,\n body.initial !== true\n );\n }\n\n // Determine and set primary type\n if (\n data.filters.primary_type &&\n data.properties.filter(\n (property) =>\n property.type === data.filters.primary_type &&\n (property.type === \"Accommodation\"\n ? property.pricing?.availability !== \"unavailable\"\n : true)\n ).length > 0\n ) {\n primary_type = data.filters.primary_type;\n this.setPrimaryType(data.filters.primary_type);\n } else if (data.properties.length > 0) {\n const mostCommonType = this.mostCommonTypeFromProperties(\n data.properties\n );\n this.setPrimaryType(mostCommonType);\n primary_type = mostCommonType;\n }\n\n this.setState({ firstCallDone: true });\n\n // Check if we need to poll for pricing\n if (data.isComplete === false && data.pollingLink) {\n const { completed, pollData } = await this.pollForPricing({\n pollingLink: data.pollingLink,\n ...(price && { price }),\n ...(limit && { limit }),\n });\n\n if (\n completed &&\n pollData?.success?.results &&\n pollData.success.results.filter(\n (property) =>\n property.type === data.filters.primary_type &&\n (property.type === \"Accommodation\"\n ? property.pricing?.availability !== \"unavailable\"\n : true)\n ).length === 0 &&\n primary_type &&\n primary_type !== data.filters.primary_type\n ) {\n const mostCommonType = this.mostCommonTypeFromProperties(\n data.properties\n );\n this.setPrimaryType(mostCommonType);\n }\n\n // Ensure markers are refreshed after polling completes\n if (completed) {\n this.refresh();\n }\n }\n\n // Fly to POIs if not already done\n if (!flown) {\n if (data.properties.some((x) => !!x.location)) {\n this.flyToPOIs(\n data.properties\n .filter(\n (x) =>\n !!x.location &&\n (data.filters.primary_type\n ? x.type === data.filters.primary_type\n : true)\n )\n .map((x) => ({ lat: x.location!.lat, lng: x.location!.lon })),\n undefined,\n body.initial !== true\n );\n } else if (\n data.filters.location?.latitude &&\n data.filters.location?.longitude\n ) {\n this.flyMapTo(\n data.filters.location.longitude,\n data.filters.location.latitude,\n 12,\n body.initial !== true\n );\n }\n }\n\n return data;\n } catch (error) {\n this.handleError(error, \"runPropertiesSearch\");\n onError?.(error);\n this.callbacks.onPropertiesLoadError?.(error);\n this.clearProperties();\n this.setState({ firstCallDone: true });\n return null;\n } finally {\n this.setSearching(false);\n this.setState({ firstCallDone: true });\n }\n }\n\n async performBoundsSearch(): Promise<APIResponse | null> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\n \"performBoundsSearch requires API usage. Set useApi to true.\"\n );\n return null;\n }\n\n if (!this.state.pendingBounds) {\n return null;\n }\n\n const filters = this.getFilters();\n const body: InitialRequestBody = {\n bounds: this.state.pendingBounds,\n filters,\n };\n\n const priceFilter = filters?.price ?? undefined;\n\n const result = await this.runPropertiesSearch({\n body,\n beforeApplyProperties: () => {\n return { price: priceFilter ?? null };\n },\n });\n\n if (result) {\n this.setBounds(this.state.pendingBounds);\n this.setTempBounds(this.state.pendingBounds);\n this.setPendingBounds(null);\n }\n\n return result;\n }\n\n private updateActiveLocationFromResponse(data: APIResponse) {\n const newLocationId = data.location_id ?? null;\n const newCity = data.filters.location?.city ?? undefined;\n const newCountry = data.filters.location?.country || \"\";\n const newCoordinates = data.filters.location\n ? [data.filters.location.latitude, data.filters.location.longitude]\n : undefined;\n\n if (!newCoordinates) return;\n\n const currentLocation = this.state.activeLocation;\n\n // Check if location has changed\n if (\n newLocationId !== currentLocation?.location_id ||\n newCity !== currentLocation?.city ||\n newCountry !== currentLocation?.country\n ) {\n this.setActiveLocation({\n city: newCity,\n country: newCountry,\n location_id: newLocationId,\n locationName:\n newCity && newCountry\n ? `${newCity}, ${newCountry}`\n : newCountry || \"\",\n coordinates: newCoordinates as [number, number],\n });\n }\n }\n\n async runSmartFilterSearch({\n query,\n filters,\n onProcessFilters,\n onError,\n }: {\n query?: string;\n filters?: SmartFilter[];\n onProcessFilters?: (\n filters: any,\n location_id?: number\n ) => {\n smartFilters?: SmartFilter[];\n price?: Price | null;\n limit?: number;\n language?: string;\n };\n onError?: (error: unknown) => void;\n }): Promise<APIResponse | null> {\n this.ensureAlive();\n\n if (!this.useApi) {\n console.warn(\n \"runSmartFilterSearch requires API usage. Set useApi to true.\"\n );\n onError?.(new Error(\"API usage is disabled\"));\n return null;\n }\n\n // Build filter payload from smart filters if provided\n let filterPayload = this.getFilters();\n const state = this.getState();\n\n if (filters && filters.length > 0) {\n const amenities = new Set<string>();\n const hotelStyle = new Set<string>();\n let price: { min: number; max: number } | undefined;\n let minRating: number | undefined;\n let starRating: number | undefined;\n let primary_type: PropertyType | undefined;\n let transformed_query: string | undefined;\n let selected_restaurant_price_levels: PriceLevel[] | undefined;\n\n filters.forEach((filter) => {\n switch (filter.type) {\n case \"amenity\":\n amenities.add(filter.value);\n break;\n case \"hotelStyle\":\n hotelStyle.add(filter.value);\n break;\n case \"priceRange\":\n if (filter.priceRange) {\n price = {\n min: filter.priceRange.min,\n max: filter.priceRange.max ?? 0,\n };\n }\n break;\n case \"minRating\":\n minRating = filter.numericValue ?? Number(filter.value);\n break;\n case \"starRating\":\n starRating = filter.numericValue ?? Number(filter.value);\n break;\n case \"primary_type\":\n primary_type = filter.propertyType;\n break;\n case \"transformed_query\":\n transformed_query = filter.value;\n break;\n case \"selected_restaurant_price_levels\":\n selected_restaurant_price_levels = filter.priceLevels;\n break;\n }\n });\n\n filterPayload = {\n ...filterPayload,\n ...(amenities.size > 0 && { amenities: Array.from(amenities) }),\n ...(hotelStyle.size > 0 && { hotelStyle: Array.from(hotelStyle) }),\n ...(price && { price }),\n ...(minRating !== undefined && { minRating }),\n ...(starRating !== undefined && { starRating }),\n ...(primary_type && { primary_type }),\n ...(transformed_query && { transformed_query }),\n ...(selected_restaurant_price_levels && {\n selected_restaurant_price_levels,\n }),\n };\n } else if (!query) {\n // Add default minRating if no filters and no query\n filterPayload.minRating = 4;\n }\n\n const body: InitialRequestBody = {\n filters: filterPayload,\n ...(query && { query }),\n ...(state.bounds\n ? { bounds: state.bounds }\n : state.activeLocation.location_id\n ? { location_id: state.activeLocation.location_id }\n : state.activeLocation.coordinates\n ? {\n latitude: state.activeLocation.coordinates[0],\n longitude: state.activeLocation.coordinates[1],\n }\n : {}),\n };\n\n return this.runPropertiesSearch({\n body,\n beforeApplyProperties: onProcessFilters\n ? (data) => {\n const result = onProcessFilters(data.filters, data.location_id);\n return {\n price: result.price ?? null,\n limit: result.limit ?? 30,\n };\n }\n : undefined,\n smartFiltersClearable: !!query,\n onError,\n });\n }\n\n getClusters(): ClusterDisplayItem[] {\n this.ensureAlive();\n return [...this.clusterItems];\n }\n\n setUseApi(useApi: boolean, autoLoad: boolean = true) {\n this.ensureAlive();\n\n // Update useApi value\n this.useApi = useApi;\n\n // Validate platform restrictions when switching to useApi = false\n if (\n !useApi &&\n this.currentPlatform &&\n this.currentPlatform !== \"maplibre\"\n ) {\n console.warn(\n \"When useApi is false, only maplibre platform is supported. Please switch to maplibre.\"\n );\n }\n\n // Clear properties when disabling API\n if (!useApi) {\n this.clearProperties();\n }\n\n // Auto-load properties if enabled and useApi is turned on\n if (useApi && autoLoad) {\n if (this.options.initialLocationData) {\n this.initializeFromLocationData(this.options.initialLocationData);\n } else if (this.requestBody && this.isMapAttached) {\n this.autoLoadProperties();\n }\n }\n }\n\n setApiKey(apiKey: string | undefined) {\n this.ensureAlive();\n const oldKey = this.apiKey;\n this.apiKey = apiKey;\n\n // If API key changed and map is attached, refresh\n if (oldKey !== this.apiKey && this.isMapAttached) {\n this.refresh();\n\n if (this.useApi) {\n if (this.options.initialLocationData) {\n this.initializeFromLocationData(this.options.initialLocationData);\n } else if (this.requestBody) {\n this.autoLoadProperties();\n }\n }\n }\n }\n\n getApiKey(): string | undefined {\n return this.apiKey;\n }\n\n refresh() {\n this.ensureAlive();\n if (!this.adapter) return;\n\n const viewState = this.safeExtractViewState();\n const primaryType = this.resolvePrimaryType();\n\n this.clusterItems = clusterMarkers({\n primaryType,\n markers: this.properties,\n map: this.adapter,\n selectedMarkerId: this.selectedMarkerId,\n zoom: viewState?.zoom ?? 0,\n });\n\n const markerManager = this.adapter.getMarkerManager();\n markerManager.render(this.clusterItems, primaryType, this.selectedMarkerId);\n\n this.options.onClusterUpdate?.(this.clusterItems, viewState);\n }\n\n destroy() {\n if (this.destroyed) {\n return;\n }\n if (this.adapter) {\n const markerManager = this.adapter.getMarkerManager();\n markerManager.destroy();\n this.adapter.cleanup();\n }\n\n this.clusterItems = [];\n this.properties = [];\n this.destroyed = true;\n this.isMapAttached = false;\n }\n\n private resolvePrimaryType(): PropertyType {\n return (\n this.primaryType ??\n this.properties.find((marker) => marker.type)?.type ??\n DEFAULT_PRIMARY_TYPE\n );\n }\n\n private safeExtractViewState(): ViewStateSnapshot | null {\n if (!this.adapter) return null;\n try {\n return extractViewState(this.adapter);\n } catch {\n return null;\n }\n }\n\n private ensureAlive() {\n if (this.destroyed) {\n throw new Error(\"MapFirstCore instance has been destroyed\");\n }\n }\n}\n\nfunction isMapLibreOptions(\n options: MapFirstOptions\n): options is MapLibreOptions {\n return (options as MapLibreOptions).platform === \"maplibre\";\n}\n\nfunction isGoogleMapsOptions(\n options: MapFirstOptions\n): options is GoogleMapsOptions {\n return (options as GoogleMapsOptions).platform === \"google\";\n}\n\nfunction isMapboxOptions(options: MapFirstOptions): options is MapboxOptions {\n return (options as MapboxOptions).platform === \"mapbox\";\n}\n"],"mappings":"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","names":["styleInject","css","insertAt","head","style","styleInject","createDotMarkerElement","item","primaryType","selectedMarkerId","onMarkerClick","_a","_b","_c","marker","isPrimaryType","isSelected","isPending","container","button","evt","AWARD_SVG","AWARD_BACK_SVG","EAT_DRINK_SVG","ATTRACTION_SVG","LOADING_VIDEO_HTML","setupHoverCard","root","pill","marker","isSelected","propertyCard","createPropertyCard","hoverTimeout","hideTimeout","positionUpdateFrame","cleanupCard","updateCardPosition","mapContainer","positionCard","showCard","immediate","doShow","loadCardImage","hideCard","observer","mutations","mutation","removedNode","checkParent","getDefaultImageForType","type","_a","_b","_c","_d","_e","_f","url","card","rating","reviews","displayPrice","renderStars","fullStars","hasHalfStar","stars","starStyle","i","remainingStars","defaultImageUrl","imgContainer","fetchImages","imageUrl","img","markerElement","markerRect","containerRect","cardWidth","cardHeight","offset","spaceRight","spaceLeft","spaceBottom","spaceTop","left","top","createPrimaryMarkerElement","item","primaryType","selectedMarkerId","onMarkerClick","_g","_h","_i","isPrimaryType","isAccommodation","hasPrice","isPending","ratingLabel","numeric","markerUrl","badge","awardContainer","backLayer","colorDot","frontLayer","content","evt","LOADING_VIDEO_HTML","updatePrimaryMarkerElement","element","isPrimaryType","isSelected","isPending","marker","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","wasPending","root","pill","badge","setupHoverCard","content","displayPrice","hoverCard","rating","reviews","ratingValueEl","newRating","reviewsEl","newReviews","priceEl","detailsEl","learnMoreEl","newPriceHtml","url","updateDotMarkerElement","container","button","extractMarkerIdFromKey","key","match","BaseMarkerManager","mapInstance","onMarkerClick","items","primaryType","selectedMarkerId","_a","_b","_c","_d","_e","_f","_g","_h","newKeys","item","key","entry","coords","safeLatLon","existing","isPrimaryType","isSelected","isAccommodation","isPending","element","updatePrimaryMarkerElement","updateDotMarkerElement","markerId","existingEntry","existingKey","extractMarkerIdFromKey","createPrimaryMarkerElement","createDotMarkerElement","marker","error","location","MapLibreMarkerManager","BaseMarkerManager","options","_a","items","primaryType","selectedMarkerId","element","coords","item","marker","GoogleMapsMarkerManager","BaseMarkerManager","options","items","primaryType","selectedMarkerId","_a","_b","element","coords","item","isPrimaryType","isSelected","zIndex","marker","error","MapboxMarkerManager","BaseMarkerManager","options","_a","items","primaryType","selectedMarkerId","element","coords","item","marker","MapAdapter","map","onImpression","container","observer","entries","entry","cleanup","originalCleanup","MapLibreAdapter","MapAdapter","map","options","MapLibreMarkerManager","onMapMoveEnd","handleMoveEnd","bounds","handleLoad","onRefresh","eventName","_a","_b","cleanup","center","sw","ne","lngLat","event","handler","GoogleMapsAdapter","MapAdapter","map","options","GoogleMapsMarkerManager","onMapMoveEnd","google","handleIdle","bounds","listener","onRefresh","events","listeners","eventName","_a","_b","cleanup","googleMaps","OverlayView","center","sw","ne","lngLat","projection","latLng","point","event","handler","MapboxAdapter","MapAdapter","map","options","MapboxMarkerManager","onMapMoveEnd","handleMoveEnd","bounds","handleLoad","onRefresh","eventName","_a","_b","cleanup","center","sw","ne","lngLat","event","handler","extractViewState","mapInstance","center","COLLISION_THRESHOLD_PX_ZOOM_BREAKPOINTS","resolveCollisionThreshold","zoom","breakpoint","clusterMarkers","primaryType","markers","map","selectedMarkerId","collisionThresholdPx","dotCollisionThresholdPx","marker","projected","index","location","x","y","value","threshold","dotThreshold","resolveDotCollisionThreshold","parent","_","idx","find","i","union","a","b","rootA","rootB","j","dx","dy","groups","item","root","group","clustered","groupItems","_a","_b","isPrimary","isSelected","sorted","compareMarkers","primary","rest","isPrimaryPrimary","isSelectedPrimary","dotCandidates","remainder","distancePx","followUp","base","aIsPrimary","bIsPrimary","ratingDiff","resolveRating","priceDiff","resolvePrice","reviewsDiff","parsed","_c","numeric","processApiFilters","apiFilters","filters","amenity","style","convertToApiFilters","filter","apiFilter","min","max","API_URLS","PropertiesFetchError","message","status","code","fetchImages","tripadvisorId","limit","response","data","imageUrl","error","fetchProperties","url","body","apiKey","signal","_a","_b","errorBody","toISO","date","DEFAULT_PRIMARY_TYPE","getDefaultDates","base","daysUntilSaturday","checkIn","startDay","daysUntilWeekend","checkOut","MapFirstCore","options","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","API_URLS","isGoogleMaps","isGoogleMapsOptions","defaultDates","locationData","city","country","query","requestBody","geoResponse","geoData","finalCity","finalCountry","error","defaultRequestBody","mapInstance","config","markerManager","adapterConfig","isMapLibreOptions","MapLibreAdapter","GoogleMapsAdapter","isMapboxOptions","MapboxAdapter","adapter","shouldAutoSelect","marker","bounds","properties","x","property","primary","markerId","p","context","errorMessage","errorObj","update","newState","prevState","filters","location","loading","searching","animating","tempBounds","delta","longitude","latitude","zoom","animation","pois","type","animate","points","h","poi","LatLngBounds","toISO","pollingLink","maxAttempts","delayMs","isCancelled","price","limit","completed","pollData","body","attempt","pollResp","PropertiesFetchError","results","prev","resultIds","updatedProperties","existingIndex","resolve","updater","typeCounts","counts","b","beforeApplyProperties","smartFiltersClearable","onError","data","fetchProperties","primary_type","result","flown","filteredProperties","mostCommonType","priceFilter","newLocationId","newCity","newCountry","newCoordinates","currentLocation","onProcessFilters","filterPayload","state","amenities","hotelStyle","minRating","starRating","transformed_query","selected_restaurant_price_levels","filter","useApi","autoLoad","apiKey","oldKey","viewState","primaryType","clusterMarkers","extractViewState"]}