Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
410 changes: 235 additions & 175 deletions packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue

Large diffs are not rendered by default.

Large diffs are not rendered by default.

6 changes: 0 additions & 6 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,6 @@ const content = registryScripts
logo: registryScripts.find(s => s.label === 'Google Maps')?.logo,
registryScript: null,
},
{
name: 'Google Maps (Styled)',
path: '/third-parties/google-maps/styled',
logo: registryScripts.find(s => s.label === 'Google Maps')?.logo,
registryScript: null,
},
{
name: 'Google Maps (SFCs)',
path: '/third-parties/google-maps/sfcs',
Expand Down
3 changes: 1 addition & 2 deletions playground/pages/third-parties/google-maps/center.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ref } from 'vue'
const mapOptions = ref({
center: { lat: -34.397, lng: 150.644 },
})

function changeQuery() {
mapOptions.value = {
center: {
Expand All @@ -19,8 +20,6 @@ function changeQuery() {
<div>
<div>
<ScriptGoogleMaps
ref="googleMapsRef"
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
:width="1200"
:height="600"
:map-options="mapOptions"
Expand Down
6 changes: 2 additions & 4 deletions playground/pages/third-parties/google-maps/emit-test.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script setup lang="ts">
import { whenever } from '@vueuse/core'
import { ref, useTemplateRef } from 'vue'
import { ref } from 'vue'

const eventLog = ref<string[]>([])

Expand Down Expand Up @@ -59,12 +58,11 @@ const circleOptions = {
</p>

<ScriptGoogleMaps
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
:width="800"
:height="500"
:zoom="12"
:map-options="{
center: { lat: -33.87, lng: 151.21 },
zoom: 12,
mapId: 'DEMO_MAP_ID',
}"
>
Expand Down
4 changes: 1 addition & 3 deletions playground/pages/third-parties/google-maps/geojson-test.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,9 @@ const secondGeoJson = {
</p>

<ScriptGoogleMaps
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
:width="800"
:height="450"
:zoom="13"
:map-options="{ center: { lat: -33.875, lng: 151.22 } }"
:map-options="{ center: { lat: -33.875, lng: 151.22 }, zoom: 13 }"
>
<!-- Primary GeoJSON layer -->
<ScriptGoogleMapsGeoJson
Expand Down
4 changes: 0 additions & 4 deletions playground/pages/third-parties/google-maps/markers.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ const markers = ref([
{ lat: -34.397, lng: 150.642 },
])

const googleMapsRef = ref()

let increment = 1
function addMarker() {
const lat = (1000 * center.value.lat + increment) / 1000
Expand All @@ -27,8 +25,6 @@ function removeMarkers() {
<div>
<div>
<ScriptGoogleMaps
ref="googleMapsRef"
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
:width="1200"
:height="600"
:map-options="{ center }"
Expand Down
6 changes: 3 additions & 3 deletions playground/pages/third-parties/google-maps/null.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ function changeQuery() {
<div>
<div>
<ScriptGoogleMaps
ref="googleMapsRef"
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
:width="1200"
:height="600"
:center="center"
:map-options="{
center
}"
/>
</div>
<div class="button-container">
Expand Down
8 changes: 5 additions & 3 deletions playground/pages/third-parties/google-maps/nuxt-scripts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ const mapOptions = ref({
center: { lat: -34.397, lng: 150.644 },
})

const googleMapsRef = ref()
const googleMapsRef = useTemplateRef('googleMapsRef')

function changeQuery() {
query.value = 'Brooklyn+Bride,New+York+NY'
async function changeQuery() {
const res = await googleMapsRef.value.resolveQueryToLatLng('Brooklyn+Bridge,New+York+NY')

mapOptions.value.center = res
}
Comment on lines +11 to 15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add null check before accessing googleMapsRef.value.

If changeQuery is invoked before the component mounts, googleMapsRef.value will be null, causing a runtime error when calling resolveQueryToLatLng.

Also note the query string contains "Bride" (should likely be "Bridge").

Proposed fix
 async function changeQuery() {
+    if (!googleMapsRef.value) {
+        return
+    }
-    const res = await googleMapsRef.value.resolveQueryToLatLng('Brooklyn+Bride,New+York+NY')
+    const res = await googleMapsRef.value.resolveQueryToLatLng('Brooklyn+Bridge,New+York+NY')

-  mapOptions.value.center = res
+    if (res) {
+        mapOptions.value.center = res
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playground/pages/third-parties/google-maps/nuxt-scripts.vue` around lines 11
- 15, changeQuery currently assumes googleMapsRef.value is non-null and calls
googleMapsRef.value.resolveQueryToLatLng which can throw if invoked before
mount; add a null/undefined check for googleMapsRef.value (and/or
googleMapsRef.value.resolveQueryToLatLng) at the start of changeQuery and return
early or await component readiness before calling it, then assign the returned
coords to mapOptions.value.center; also correct the query string from
"Brooklyn+Bride,New+York+NY" to "Brooklyn+Bridge,New+York+NY" to fix the typo.

</script>

Expand Down
74 changes: 22 additions & 52 deletions playground/pages/third-parties/google-maps/overlay-animated.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@ function close(id: number) {
Click a marker to open/close. Uses data-state attribute for CSS enter/leave animations.
</p>
<ScriptGoogleMaps
:center="{ lat: -33.8688, lng: 151.2093 }"
:zoom="12"
:width="800"
:height="500"
:map-options="{ mapId: 'DEMO_MAP_ID' }"
:map-options="{ mapId: 'DEMO_MAP_ID', center: { lat: -33.8688, lng: 151.2093 }, zoom: 12 }"
>
<ScriptGoogleMapsMarker
v-for="place in places"
Expand All @@ -47,54 +45,37 @@ function close(id: number) {
<ScriptGoogleMapsOverlayView
:open="isOpen(place.id)"
anchor="bottom-center"
class="bg-white rounded-lg p-4 w-64 shadow-lg data-[state=open]:animate-[overlayIn_200ms_ease-out]"
:offset="{ x: 0, y: -50 }"
@update:open="(v: boolean) => { if (!v) close(place.id) }"
>
<div class="overlay-popup">
<div class="flex items-start justify-between gap-2">
<h3 class="text-sm font-semibold text-gray-900">
{{ place.name }}
</h3>
<button
class="shrink-0 rounded-full p-0.5 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
@click.stop="close(place.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
<div class="mt-1 flex items-center gap-1 text-xs text-gray-500">
<span class="font-medium text-yellow-500">★ {{ place.rating }}</span>
<span>({{ place.reviews }} reviews)</span>
</div>
<p class="mt-2 text-xs leading-relaxed text-gray-600">
{{ place.desc }}
</p>
<div class="flex items-start justify-between gap-2">
<h3 class="text-sm font-semibold text-gray-900">
{{ place.name }}
</h3>
<button
class="shrink-0 rounded-full p-0.5 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
@click.stop="close(place.id)"
>
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
<div class="mt-1 flex items-center gap-1 text-xs text-gray-500">
<span class="font-medium text-yellow-500">★ {{ place.rating }}</span>
<span>({{ place.reviews }} reviews)</span>
</div>
<p class="mt-2 text-xs leading-relaxed text-gray-600">
{{ place.desc }}
</p>
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMapsMarker>
</ScriptGoogleMaps>
</div>
</template>

<style scoped>
.overlay-popup {
width: 16rem;
border-radius: 0.75rem;
background: white;
padding: 1rem;
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
}

.overlay-popup[data-state="open"] {
animation: overlayIn 200ms ease-out forwards;
}

.overlay-popup[data-state="closed"] {
animation: overlayOut 150ms ease-in forwards;
}

<style>
@keyframes overlayIn {
from {
opacity: 0;
Expand All @@ -105,15 +86,4 @@ function close(id: number) {
transform: scale(1) translateY(0);
}
}

@keyframes overlayOut {
from {
opacity: 1;
transform: scale(1) translateY(0);
}
to {
opacity: 0;
transform: scale(0.95) translateY(4px);
}
}
</style>
21 changes: 16 additions & 5 deletions playground/pages/third-parties/google-maps/overlay-popup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ const places = [
Click a marker to show a fully custom popup. Click again or press × to close. Uses v-if for multiple markers.
</p>
<ScriptGoogleMaps
:center="{ lat: -33.8688, lng: 151.2093 }"
:zoom="12"
:width="800"
:height="500"
:map-options="{ mapId: 'DEMO_MAP_ID' }"
:map-options="{ mapId: 'DEMO_MAP_ID', center: { lat: -33.8688, lng: 151.2093 }, zoom: 12 }"
>
<ScriptGoogleMapsMarker
v-for="place in places"
Expand All @@ -34,9 +32,9 @@ const places = [
<ScriptGoogleMapsOverlayView
v-if="selected === place.id"
anchor="bottom-center"
class="w-64 rounded-xl bg-white p-4 shadow-lg ring-1 ring-black/5 data-[state=open]:animate-[overlayIn_200ms_ease-out]"
:offset="{ x: 0, y: -50 }"
>
<div class="w-64 rounded-xl bg-white p-4 shadow-lg ring-1 ring-black/5">
<div class="flex items-start justify-between gap-2">
<h3 class="text-sm font-semibold text-gray-900">
{{ place.name }}
Expand All @@ -60,9 +58,22 @@ const places = [
<button class="mt-3 w-full rounded-lg bg-blue-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-blue-700">
View details
</button>
</div>
</ScriptGoogleMapsOverlayView>
</ScriptGoogleMapsMarker>
</ScriptGoogleMaps>
</div>
</template>

<style>
@keyframes overlayIn {
from {
opacity: 0;
transform: scale(0.95) translateY(4px);
}

to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
</style>
36 changes: 26 additions & 10 deletions playground/pages/third-parties/google-maps/query.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
<script setup lang="ts">
import type { ScriptGoogleMapsProps } from '#nuxt-scripts/components/GoogleMaps/ScriptGoogleMaps.vue'
import { ref } from 'vue'

const center = ref<string>('Brooklyn+Bride,New+York+NY')
const googleMapsRef = useTemplateRef('googleMapsRef')

function changeQuery() {
if (center.value.startsWith('Statue')) {
center.value = 'Brooklyn+Bride,New+York+NY'
}
else {
center.value = 'Statue+of+Liberty+National+Monument+New+York+NY'
}
const query = ref('Brooklyn+Bridge,New+York+NY')

const center = ref<google.maps.LatLng | google.maps.LatLngLiteral>({ lat: -34.397, lng: 150.644 })

async function changeQuery() {
if (!googleMapsRef.value) {
return
}

query.value = query.value.startsWith('Statue')
? 'Brooklyn+Bridge,New+York+NY'
: 'Statue+of+Liberty+National+Monument+New+York+NY'

const queryLatLng = await googleMapsRef.value.resolveQueryToLatLng(
query.value
)
Comment on lines +20 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle geocode failures to avoid unhandled rejections.

changeQuery awaits a network-dependent call without error handling. A failed geocode request will reject and bubble from the click handler.

Proposed fix
 async function changeQuery() {
     if (!googleMapsRef.value) {
         return
     }

     query.value = query.value.startsWith('Statue')
         ? 'Brooklyn+Bridge,New+York+NY'
         : 'Statue+of+Liberty+National+Monument+New+York+NY'

-    const queryLatLng = await googleMapsRef.value.resolveQueryToLatLng(
-        query.value
-    )
-
-    if (queryLatLng) {
-        center.value = queryLatLng
+    try {
+        const queryLatLng = await googleMapsRef.value.resolveQueryToLatLng(query.value)
+        if (queryLatLng) {
+            center.value = queryLatLng
+        }
+    }
+    catch (error) {
+        console.error('Failed to resolve map query:', error)
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playground/pages/third-parties/google-maps/query.vue` around lines 20 - 22,
The call to googleMapsRef.value.resolveQueryToLatLng(query.value) inside
changeQuery is unhandled and can cause unhandled promise rejections on
geocode/network failures; wrap the await in a try/catch in changeQuery, handle
errors by logging or showing a user-facing message and gracefully returning (or
setting an error state) so the click handler doesn't propagate the rejection,
referencing changeQuery, googleMapsRef, resolveQueryToLatLng, and query.value.


if (queryLatLng) {
center.value = queryLatLng
}
}
</script>

<template>
<div>
<div>
<ScriptGoogleMaps
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
ref="googleMapsRef"
:width="1200"
:height="600"
:center="center"
:map-options="{
center
}"
/>
</div>
<div class="button-container">
Expand Down
33 changes: 16 additions & 17 deletions playground/pages/third-parties/google-maps/sfcs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,22 @@ const zoom = ref(8)

const googleMapsRef = useTemplateRef('googleMapsRef')

whenever(() => googleMapsRef.value?.googleMaps, (googleMaps) => {
whenever(() => googleMapsRef.value?.mapsApi, (mapsApi) => {
heatmapLayerData.value.push(...[
new googleMaps.LatLng(-33.8688, 151.2093),
new googleMaps.LatLng(-33.8690, 151.2100),
new googleMaps.LatLng(-33.8700, 151.2150),
new googleMaps.LatLng(-33.8710, 151.2200),
new googleMaps.LatLng(-33.8720, 151.2250),
new googleMaps.LatLng(-33.8730, 151.2300),
new googleMaps.LatLng(-33.8740, 151.2350),
new googleMaps.LatLng(-33.8750, 151.2400),
new googleMaps.LatLng(-33.8760, 151.2450),
new googleMaps.LatLng(-33.8770, 151.2500),
new googleMaps.LatLng(-33.8780, 151.2550),
new googleMaps.LatLng(-33.8790, 151.2600),
new googleMaps.LatLng(-33.8800, 151.2650),
new googleMaps.LatLng(-33.8810, 151.2700),
new mapsApi.LatLng(-33.8688, 151.2093),
new mapsApi.LatLng(-33.8690, 151.2100),
new mapsApi.LatLng(-33.8700, 151.2150),
new mapsApi.LatLng(-33.8710, 151.2200),
new mapsApi.LatLng(-33.8720, 151.2250),
new mapsApi.LatLng(-33.8730, 151.2300),
new mapsApi.LatLng(-33.8740, 151.2350),
new mapsApi.LatLng(-33.8750, 151.2400),
new mapsApi.LatLng(-33.8760, 151.2450),
new mapsApi.LatLng(-33.8770, 151.2500),
new mapsApi.LatLng(-33.8780, 151.2550),
new mapsApi.LatLng(-33.8790, 151.2600),
new mapsApi.LatLng(-33.8800, 151.2650),
new mapsApi.LatLng(-33.8810, 151.2700),
])
})
</script>
Expand All @@ -89,13 +89,12 @@ whenever(() => googleMapsRef.value?.googleMaps, (googleMaps) => {
<div>
<ScriptGoogleMaps
ref="googleMapsRef"
api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU"
:width="1280"
:height="720"
:zoom="zoom"
:map-options="{
center: { lat: -34.397, lng: 150.644 },
mapId: 'DEMO_MAP_ID',
zoom,
}"
>
<ScriptGoogleMapsInfoWindow
Expand Down
19 changes: 0 additions & 19 deletions playground/pages/third-parties/google-maps/styled.vue

This file was deleted.

Loading
Loading