From 32c6bbbcd47498cfc7a4d763794c9127d4e6944a Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Thu, 26 Mar 2026 15:02:34 +1100 Subject: [PATCH 1/4] feat!: extract static map into standalone ScriptGoogleMapsStaticMap component BREAKING CHANGE: Remove `placeholderOptions`, `placeholderAttrs`, and `aboveTheFold` props from ScriptGoogleMaps. The built-in static map placeholder image is no longer rendered by default. Use the new `ScriptGoogleMapsStaticMap` component in the `#placeholder` slot instead: ```vue ``` The new component can also be used standalone (store locators, contact pages, etc.) and fixes the percentage width/height bug that produced invalid Static Maps API `size` parameters by auto-measuring rendered dimensions on mount. --- .../GoogleMaps/ScriptGoogleMaps.vue | 117 +------- .../GoogleMaps/ScriptGoogleMapsStaticMap.vue | 258 ++++++++++++++++++ .../third-parties/google-maps/center.vue | 1 - .../third-parties/google-maps/emit-test.vue | 1 - .../google-maps/geojson-test.vue | 1 - .../third-parties/google-maps/markers.vue | 1 - .../pages/third-parties/google-maps/null.vue | 1 - .../google-maps/nuxt-scripts.vue | 13 +- .../google-maps/overlay-animated.vue | 1 - .../google-maps/overlay-popup.vue | 1 - .../pages/third-parties/google-maps/query.vue | 1 - .../pages/third-parties/google-maps/sfcs.vue | 1 - .../third-parties/google-maps/styled.vue | 1 - 13 files changed, 280 insertions(+), 118 deletions(-) create mode 100644 packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue index 9375e282..5ae0b7b2 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue @@ -1,14 +1,12 @@ + + + + diff --git a/playground/pages/third-parties/google-maps/center.vue b/playground/pages/third-parties/google-maps/center.vue index de95dc08..9ab6131b 100644 --- a/playground/pages/third-parties/google-maps/center.vue +++ b/playground/pages/third-parties/google-maps/center.vue @@ -24,7 +24,6 @@ function changeQuery() { :width="1200" :height="600" :map-options="mapOptions" - above-the-fold @ready="() => {}" /> diff --git a/playground/pages/third-parties/google-maps/emit-test.vue b/playground/pages/third-parties/google-maps/emit-test.vue index 927e7e35..973a5b91 100644 --- a/playground/pages/third-parties/google-maps/emit-test.vue +++ b/playground/pages/third-parties/google-maps/emit-test.vue @@ -62,7 +62,6 @@ const circleOptions = { api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU" :width="800" :height="500" - above-the-fold :zoom="12" :map-options="{ center: { lat: -33.87, lng: 151.21 }, diff --git a/playground/pages/third-parties/google-maps/geojson-test.vue b/playground/pages/third-parties/google-maps/geojson-test.vue index 68a70bd8..da73b8f1 100644 --- a/playground/pages/third-parties/google-maps/geojson-test.vue +++ b/playground/pages/third-parties/google-maps/geojson-test.vue @@ -95,7 +95,6 @@ const secondGeoJson = { api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU" :width="800" :height="450" - above-the-fold :zoom="13" :map-options="{ center: { lat: -33.875, lng: 151.22 } }" > diff --git a/playground/pages/third-parties/google-maps/markers.vue b/playground/pages/third-parties/google-maps/markers.vue index 701abcd9..fe20447c 100644 --- a/playground/pages/third-parties/google-maps/markers.vue +++ b/playground/pages/third-parties/google-maps/markers.vue @@ -32,7 +32,6 @@ function removeMarkers() { :width="1200" :height="600" :map-options="{ center }" - above-the-fold > diff --git a/playground/pages/third-parties/google-maps/nuxt-scripts.vue b/playground/pages/third-parties/google-maps/nuxt-scripts.vue index 3ec39857..ec85b3f9 100644 --- a/playground/pages/third-parties/google-maps/nuxt-scripts.vue +++ b/playground/pages/third-parties/google-maps/nuxt-scripts.vue @@ -22,8 +22,17 @@ function changeQuery() { :width="640" :height="500" :map-options="mapOptions" - above-the-fold - /> + > + +
diff --git a/playground/pages/third-parties/google-maps/sfcs.vue b/playground/pages/third-parties/google-maps/sfcs.vue index ed4e565e..c3617dac 100644 --- a/playground/pages/third-parties/google-maps/sfcs.vue +++ b/playground/pages/third-parties/google-maps/sfcs.vue @@ -92,7 +92,6 @@ whenever(() => googleMapsRef.value?.googleMaps, (googleMaps) => { api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU" :width="1280" :height="720" - above-the-fold :zoom="zoom" :map-options="{ center: { lat: -34.397, lng: 150.644 }, diff --git a/playground/pages/third-parties/google-maps/styled.vue b/playground/pages/third-parties/google-maps/styled.vue index 0e6c33d5..0c562215 100644 --- a/playground/pages/third-parties/google-maps/styled.vue +++ b/playground/pages/third-parties/google-maps/styled.vue @@ -12,7 +12,6 @@ const mapOptions = { api-key="AIzaSyAOEIQ_xOdLx2dNwnFMzyJoswwvPCTcGzU" :width="1200" :height="600" - above-the-fold :map-options="mapOptions" />
From 335a9535cb65be8c0db8af9ff2422edfef0dd9c6 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Thu, 26 Mar 2026 15:04:55 +1100 Subject: [PATCH 2/4] fix: move regex to module scope for lint compliance --- .../components/GoogleMaps/ScriptGoogleMapsStaticMap.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue index 559fb94d..e647f3bd 100644 --- a/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue +++ b/packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsStaticMap.vue @@ -132,10 +132,12 @@ function toCssUnit(value: string | number): string { return typeof value === 'number' ? `${value}px` : value } +const PIXEL_VALUE_RE = /^\d+(?:px)?$/i + function isPixelValue(value: string | number): boolean { if (typeof value === 'number') return true - return /^\d+(px)?$/i.test(value) + return PIXEL_VALUE_RE.test(value) } function transformMapStyles(styles: google.maps.MapTypeStyle[]): string[] { From f64da30ad9c5a3cf461e7faa6f2df1fd641fa434 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Thu, 26 Mar 2026 16:25:23 +1100 Subject: [PATCH 3/4] fix: address CodeRabbit review + add docs for ScriptGoogleMapsStaticMap - Restrict scale prop to 1 | 2 (matches Static Maps API) - Explicit apiKey prop now takes priority over proxy - Clamp auto-measured sizes to 640x640 API limit - Remove hardcoded API key from playground - Add ScriptGoogleMapsStaticMap API doc page - Update ScriptGoogleMaps docs for new placeholder pattern - Add Google Maps breaking changes to v0-to-v1 migration guide --- .../docs/4.migration-guide/1.v0-to-v1.md | 36 +++++++ .../google-maps/2.api/1.script-google-maps.md | 16 +-- .../google-maps/2.api/1b.static-map.md | 99 +++++++++++++++++++ .../GoogleMaps/ScriptGoogleMapsStaticMap.vue | 25 +++-- .../google-maps/nuxt-scripts.vue | 2 - 5 files changed, 160 insertions(+), 18 deletions(-) create mode 100644 docs/content/scripts/google-maps/2.api/1b.static-map.md diff --git a/docs/content/docs/4.migration-guide/1.v0-to-v1.md b/docs/content/docs/4.migration-guide/1.v0-to-v1.md index 2c264404..6e2389c5 100644 --- a/docs/content/docs/4.migration-guide/1.v0-to-v1.md +++ b/docs/content/docs/4.migration-guide/1.v0-to-v1.md @@ -301,6 +301,42 @@ Default `object-fit` changed from `contain` to `cover`: Player instances are now properly isolated. Remove any workarounds for multiple players. +### Google Maps Static Placeholder ([#673](https://github.com/nuxt/scripts/pull/673)) + +The built-in static map placeholder was extracted into a standalone [``{lang="html"}](/scripts/google-maps/api/static-map) component. The following props were removed from ``{lang="html"}: + +- `placeholderOptions` +- `placeholderAttrs` +- `aboveTheFold` + +The `#placeholder` slot no longer passes a `placeholder` URL string. It is now empty by default. + +```diff + + + + ++ ++ ++ +``` + +The new component can also be used standalone for store locators, contact pages, and directions previews without loading the interactive Maps API. + ### Google Tag Manager #### onBeforeGtmStart Callback diff --git a/docs/content/scripts/google-maps/2.api/1.script-google-maps.md b/docs/content/scripts/google-maps/2.api/1.script-google-maps.md index 12922ad9..425a400d 100644 --- a/docs/content/scripts/google-maps/2.api/1.script-google-maps.md +++ b/docs/content/scripts/google-maps/2.api/1.script-google-maps.md @@ -9,7 +9,7 @@ The [``{lang="html"}](/scripts/google-maps){lang="html"} compo It's optimized for performance by using the [Element Event Triggers](/docs/guides/script-triggers#element-event-triggers), only loading the Google Maps when specific elements events happen. -Before Google Maps loads, it shows a placeholder using [Maps Static API](https://developers.google.com/maps/documentation/maps-static). +The `#placeholder` slot is empty by default. Use [``{lang="html"}](/scripts/google-maps/api/static-map) inside it to show a static map image while the interactive map loads. By default, it will load on the `mouseenter`, `mouseover`, and `mousedown` events. @@ -124,15 +124,17 @@ override this component. Make sure you provide a loading indicator. **placeholder** -This slot displays a placeholder image before Google Maps loads. By default, this will show the Google Maps Static API image for the map. - -Provide custom `#placeholder` content without rendering the provided `placeholder` URL to skip the Static Maps API request and avoid those charges. +The placeholder slot is empty by default. Use [``{lang="html"}](/scripts/google-maps/api/static-map) to show a static map preview while the interactive map loads. ```vue From 3ad32358f6a8ad3576d3a15b99b4cf12078f1c01 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Thu, 26 Mar 2026 16:46:43 +1100 Subject: [PATCH 4/4] fix: resolve doc linting issues (em-dashes, passive voice) --- .../docs/4.migration-guide/1.v0-to-v1.md | 4 +-- .../google-maps/2.api/1b.static-map.md | 30 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/content/docs/4.migration-guide/1.v0-to-v1.md b/docs/content/docs/4.migration-guide/1.v0-to-v1.md index 6e2389c5..7fe33de0 100644 --- a/docs/content/docs/4.migration-guide/1.v0-to-v1.md +++ b/docs/content/docs/4.migration-guide/1.v0-to-v1.md @@ -303,7 +303,7 @@ Player instances are now properly isolated. Remove any workarounds for multiple ### Google Maps Static Placeholder ([#673](https://github.com/nuxt/scripts/pull/673)) -The built-in static map placeholder was extracted into a standalone [``{lang="html"}](/scripts/google-maps/api/static-map) component. The following props were removed from ``{lang="html"}: +v1 extracts the built-in static map placeholder into a standalone [``{lang="html"}](/scripts/google-maps/api/static-map) component. This removes the following props from ``{lang="html"}: - `placeholderOptions` - `placeholderAttrs` @@ -335,7 +335,7 @@ The `#placeholder` slot no longer passes a `placeholder` URL string. It is now e + ``` -The new component can also be used standalone for store locators, contact pages, and directions previews without loading the interactive Maps API. +Use the new component standalone for store locators, contact pages, and directions previews without loading the interactive Maps API. ### Google Tag Manager diff --git a/docs/content/scripts/google-maps/2.api/1b.static-map.md b/docs/content/scripts/google-maps/2.api/1b.static-map.md index 3473c259..9f84a93d 100644 --- a/docs/content/scripts/google-maps/2.api/1b.static-map.md +++ b/docs/content/scripts/google-maps/2.api/1b.static-map.md @@ -47,26 +47,26 @@ Use inside [``{lang="html"}](/scripts/google-maps/api/script-g | Prop | Type | Default | Description | |------|------|---------|-------------| -| `center` | `string \| { lat: number, lng: number }` | — | Map center as `"lat,lng"` string or `LatLngLiteral`. | -| `zoom` | `number` | `15` | Zoom level (0–21). | +| `center` | `string \| { lat: number, lng: number }` | | Map center as `"lat,lng"` string or `LatLngLiteral`. | +| `zoom` | `number` | `15` | Zoom level (0 to 21). | | `size` | `` `${number}x${number}` `` | auto | Explicit pixel size for the API request. When omitted, measures the rendered container on mount. Falls back to `640x400` during SSR. | | `scale` | `1 \| 2` | `2` | Device pixel ratio. | -| `format` | `StaticMapFormat` | — | Image format: `png`, `jpg`, `gif`, `png8`, `png32`, `jpg-baseline`. | -| `maptype` | `StaticMapType` | — | Map type: `roadmap`, `satellite`, `terrain`, `hybrid`. | -| `mapId` | `string` | — | Cloud-based map styling ID. | -| `markers` | `string \| string[]` | — | [Marker descriptors](https://developers.google.com/maps/documentation/maps-static/start#Markers). | -| `path` | `string \| string[]` | — | [Polyline path descriptors](https://developers.google.com/maps/documentation/maps-static/start#Paths). | -| `visible` | `string \| string[]` | — | Locations that should be visible on the map. | -| `style` | `string \| string[] \| MapTypeStyle[]` | — | Map styling. Accepts raw Static Maps API style strings or Google Maps JS API `MapTypeStyle[]` objects. | -| `language` | `string` | — | Language code for map labels. | -| `region` | `string` | — | Region bias. | -| `signature` | `string` | — | Digital signature for keyless requests. | -| `apiKey` | `string` | — | API key override. When the proxy is enabled and no explicit key is passed, the server-side key is used instead. | +| `format` | `StaticMapFormat` | | Image format: `png`, `jpg`, `gif`, `png8`, `png32`, `jpg-baseline`. | +| `maptype` | `StaticMapType` | | Map type: `roadmap`, `satellite`, `terrain`, `hybrid`. | +| `mapId` | `string` | | Cloud-based map styling ID. | +| `markers` | `string \| string[]` | | [Marker descriptors](https://developers.google.com/maps/documentation/maps-static/start#Markers). | +| `path` | `string \| string[]` | | [Polyline path descriptors](https://developers.google.com/maps/documentation/maps-static/start#Paths). | +| `visible` | `string \| string[]` | | Locations that should be visible on the map. | +| `style` | `string \| string[] \| MapTypeStyle[]` | | Map styling. Accepts raw Static Maps API style strings or Google Maps JS API `MapTypeStyle[]` objects. | +| `language` | `string` | | Language code for map labels. | +| `region` | `string` | | Region bias. | +| `signature` | `string` | | Digital signature for keyless requests. | +| `apiKey` | `string` | | API key override. Takes priority over the proxy; the component falls back to the server-side key when omitted. | | `width` | `number \| string` | `640` | CSS width for the container. | | `height` | `number \| string` | `400` | CSS height for the container. | | `loading` | `'eager' \| 'lazy'` | `'lazy'` | Image loading strategy. | | `objectFit` | `string` | `'cover'` | Object-fit for the ``{lang="html"} within its container. | -| `imgAttrs` | `ImgHTMLAttributes` | — | Additional attributes for the ``{lang="html"} element. | +| `imgAttrs` | `ImgHTMLAttributes` | | Additional attributes for the ``{lang="html"} element. | ## Size Handling @@ -80,7 +80,7 @@ Set `size` explicitly to bypass auto-measurement. ## Proxy Support -When `googleMaps` is configured in `scripts.registry`, a server-side proxy is automatically enabled. The component routes requests through the proxy unless an explicit `apiKey` prop is provided. +Configuring `googleMaps` in `scripts.registry` enables a server-side proxy automatically. The component routes requests through the proxy unless you provide an explicit `apiKey` prop. ## Slots