From 79025364a32e192c9767196ca54ea6de0e331c9c Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 00:20:26 +0000 Subject: [PATCH 01/16] feat(samples): add advanced place details and search samples --- .../README.md | 35 +++++ .../index.html | 64 +++++++++ .../index.ts | 81 +++++++++++ .../package.json | 12 ++ .../style.css | 26 ++++ .../tsconfig.json | 7 + .../ui-kit-advanced-place-details/README.md | 35 +++++ .../ui-kit-advanced-place-details/index.html | 52 +++++++ .../ui-kit-advanced-place-details/index.ts | 69 +++++++++ .../package.json | 12 ++ .../ui-kit-advanced-place-details/style.css | 38 +++++ .../tsconfig.json | 7 + .../README.md | 35 +++++ .../index.html | 82 +++++++++++ .../index.ts | 125 ++++++++++++++++ .../package.json | 12 ++ .../style.css | 49 +++++++ .../tsconfig.json | 7 + .../README.md | 35 +++++ .../index.html | 79 ++++++++++ .../index.ts | 135 ++++++++++++++++++ .../package.json | 12 ++ .../style.css | 73 ++++++++++ .../tsconfig.json | 7 + 24 files changed, 1089 insertions(+) create mode 100644 samples/ui-kit-advanced-place-details-compact/README.md create mode 100644 samples/ui-kit-advanced-place-details-compact/index.html create mode 100644 samples/ui-kit-advanced-place-details-compact/index.ts create mode 100644 samples/ui-kit-advanced-place-details-compact/package.json create mode 100644 samples/ui-kit-advanced-place-details-compact/style.css create mode 100644 samples/ui-kit-advanced-place-details-compact/tsconfig.json create mode 100644 samples/ui-kit-advanced-place-details/README.md create mode 100644 samples/ui-kit-advanced-place-details/index.html create mode 100644 samples/ui-kit-advanced-place-details/index.ts create mode 100644 samples/ui-kit-advanced-place-details/package.json create mode 100644 samples/ui-kit-advanced-place-details/style.css create mode 100644 samples/ui-kit-advanced-place-details/tsconfig.json create mode 100644 samples/ui-kit-advanced-place-search-nearby/README.md create mode 100644 samples/ui-kit-advanced-place-search-nearby/index.html create mode 100644 samples/ui-kit-advanced-place-search-nearby/index.ts create mode 100644 samples/ui-kit-advanced-place-search-nearby/package.json create mode 100644 samples/ui-kit-advanced-place-search-nearby/style.css create mode 100644 samples/ui-kit-advanced-place-search-nearby/tsconfig.json create mode 100644 samples/ui-kit-advanced-place-search-text/README.md create mode 100644 samples/ui-kit-advanced-place-search-text/index.html create mode 100644 samples/ui-kit-advanced-place-search-text/index.ts create mode 100644 samples/ui-kit-advanced-place-search-text/package.json create mode 100644 samples/ui-kit-advanced-place-search-text/style.css create mode 100644 samples/ui-kit-advanced-place-search-text/tsconfig.json diff --git a/samples/ui-kit-advanced-place-details-compact/README.md b/samples/ui-kit-advanced-place-details-compact/README.md new file mode 100644 index 000000000..6cd66b77b --- /dev/null +++ b/samples/ui-kit-advanced-place-details-compact/README.md @@ -0,0 +1,35 @@ +# Google Maps JavaScript Sample + +## ui-kit-place-details-compact + +The ui-kit-place-details-compact sample demonstrates how to use the UI Kit for Place Details in a compact layout. + +Follow these instructions to set up and run ui-kit-place-details-compact sample on your local computer. + +## Setup + +### Before starting run: + +`$npm i` + +### Run an example on a local web server + +First `cd` to the folder for the sample to run, then: + +`$npm start` + +### Build an individual example + +From `samples/`: + +`$npm run build --workspace=ui-kit-place-details-compact/` + +### Build all of the examples. + +From `samples/`: +`$npm run build-all` + +## Feedback + +For feedback related to this sample, please open a new issue on +[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues). diff --git a/samples/ui-kit-advanced-place-details-compact/index.html b/samples/ui-kit-advanced-place-details-compact/index.html new file mode 100644 index 000000000..8f593c805 --- /dev/null +++ b/samples/ui-kit-advanced-place-details-compact/index.html @@ -0,0 +1,64 @@ + + + + + + Place Details Compact with Google Maps + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/samples/ui-kit-advanced-place-details-compact/index.ts b/samples/ui-kit-advanced-place-details-compact/index.ts new file mode 100644 index 000000000..22f8550d3 --- /dev/null +++ b/samples/ui-kit-advanced-place-details-compact/index.ts @@ -0,0 +1,81 @@ +/* eslint-disable */ +// @ts-nocheck +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_advanced_place_details_compact] */ +// Use querySelector to select elements for interaction. +/* [START maps_ui_kit_advanced_place_details_compact_query_selector] */ +const map = document.querySelector('gmp-map')!; +const placeDetails = document.querySelector( + 'gmp-advanced-place-details-compact' +)!; +const placeDetailsRequest = document.querySelector( + 'gmp-place-details-place-request' +)!; +const marker = document.querySelector('gmp-advanced-marker')!; +/* [END maps_ui_kit_advanced_place_details_compact_query_selector] */ +async function init(): Promise { + // Request needed libraries. + void Promise.all([ + google.maps.importLibrary('marker'), + google.maps.importLibrary('places'), + ]); + const { InfoWindow } = await google.maps.importLibrary('maps'); + + await window.customElements.whenDefined('gmp-map'); + // Set the inner map options. + map.innerMap.setOptions({ + mapTypeControl: false, + streetViewControl: false, + }); + + await window.customElements.whenDefined('gmp-advanced-marker'); + marker.collisionBehavior = 'REQUIRED_AND_HIDES_OPTIONAL'; + + const infoWindow = new InfoWindow(); + infoWindow.addListener('close', () => { + marker.position = null; + }); + + const showInfoWindow = () => { + if (infoWindow.isOpen) return; + infoWindow.setContent(placeDetails); + infoWindow.open({ anchor: marker }); + }; + + placeDetails.addEventListener('gmp-load', () => { + // For the initial load case, with no user click, we fall back to the place's location, and ensure the map has a center set and the InfoWindow is show. + // (The clicked POI LatLng will be a more natural marker position, when available.) + if (!map.center && placeDetails.place?.location) { + map.center = marker.position = placeDetails.place.location; + showInfoWindow(); + } + }); + + /* [START maps_ui_kit_advanced_place_details_compact_event] */ + // Add an event listener to handle clicks. + map.innerMap.addListener( + 'click', + (event: google.maps.MapMouseEvent | google.maps.IconMouseEvent) => { + event.stop(); + + if ('placeId' in event) { + // When the user clicks a POI. + marker.position = event.latLng; + placeDetailsRequest.place = event.placeId; + showInfoWindow(); + } else { + // When the user clicks the map (not on a POI). + marker.position = null; + placeDetailsRequest.place = null; + console.log('No place was selected.'); + } + } + ); +} +/* [END maps_ui_kit_advanced_place_details_compact_event] */ +void init(); +/* [END maps_ui_kit_advanced_place_details_compact] */ diff --git a/samples/ui-kit-advanced-place-details-compact/package.json b/samples/ui-kit-advanced-place-details-compact/package.json new file mode 100644 index 000000000..60d74f26f --- /dev/null +++ b/samples/ui-kit-advanced-place-details-compact/package.json @@ -0,0 +1,12 @@ +{ + "name": "@js-api-samples/ui-kit-advanced-place-details-compact", + "version": "1.0.0", + "scripts": { + "build": "bash ../build-single.sh", + "test": "tsc && npm run build:vite --workspace=.", + "start": "tsc && vite build --config ../../vite.config.js --base './' && vite --config ../../vite.config.js", + "build:vite": "vite build --config ../../vite.config.js --base './'", + "preview": "vite preview --config ../../vite.config.js" + }, + "author": "Google LLC" +} diff --git a/samples/ui-kit-advanced-place-details-compact/style.css b/samples/ui-kit-advanced-place-details-compact/style.css new file mode 100644 index 000000000..58d94bdad --- /dev/null +++ b/samples/ui-kit-advanced-place-details-compact/style.css @@ -0,0 +1,26 @@ +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_place_details_compact] */ +/* + * Optional: Makes the sample page fill the window. + */ +html, +body { + height: 100%; + margin: 0; + padding: 0; +} + +.container { + display: flex; + height: 100vh; + width: 100%; +} + +gmp-map { + flex-grow: 1; +} +/* [END maps_ui_kit_place_details_compact] */ diff --git a/samples/ui-kit-advanced-place-details-compact/tsconfig.json b/samples/ui-kit-advanced-place-details-compact/tsconfig.json new file mode 100644 index 000000000..976bcc6ef --- /dev/null +++ b/samples/ui-kit-advanced-place-details-compact/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./*.ts"] +} diff --git a/samples/ui-kit-advanced-place-details/README.md b/samples/ui-kit-advanced-place-details/README.md new file mode 100644 index 000000000..462c2b3bb --- /dev/null +++ b/samples/ui-kit-advanced-place-details/README.md @@ -0,0 +1,35 @@ +# Google Maps JavaScript Sample + +## ui-kit-place-details + +The ui-kit-place-details sample demonstrates how to use the UI Kit Place Details element. + +Follow these instructions to set up and run ui-kit-place-details sample on your local computer. + +## Setup + +### Before starting run: + +`$npm i` + +### Run an example on a local web server + +First `cd` to the folder for the sample to run, then: + +`$npm start` + +### Build an individual example + +From `samples/`: + +`$npm run build --workspace=ui-kit-place-details/` + +### Build all of the examples. + +From `samples/`: +`$npm run build-all` + +## Feedback + +For feedback related to this sample, please open a new issue on +[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues). diff --git a/samples/ui-kit-advanced-place-details/index.html b/samples/ui-kit-advanced-place-details/index.html new file mode 100644 index 000000000..592a9fc9d --- /dev/null +++ b/samples/ui-kit-advanced-place-details/index.html @@ -0,0 +1,52 @@ + + + + + + Place Details with Google Maps + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + +
+
+ + + + diff --git a/samples/ui-kit-advanced-place-details/index.ts b/samples/ui-kit-advanced-place-details/index.ts new file mode 100644 index 000000000..87423df8b --- /dev/null +++ b/samples/ui-kit-advanced-place-details/index.ts @@ -0,0 +1,69 @@ +/* eslint-disable */ +// @ts-nocheck +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_advanced_place_details] */ + +// Use querySelector to select elements for interaction. +/* [START maps_ui_kit_advanced_place_details_query_selector] */ +const map = document.querySelector('gmp-map')!; +const placeDetails: any = document.querySelector('gmp-advanced-place-details')!; +const placeDetailsRequest = document.querySelector( + 'gmp-place-details-place-request' +)!; +const marker = document.querySelector('gmp-advanced-marker')!; +/* [END maps_ui_kit_advanced_place_details_query_selector] */ + +async function init(): Promise { + // Request needed libraries. + await Promise.all([ + google.maps.importLibrary('maps'), + google.maps.importLibrary('marker'), + google.maps.importLibrary('places'), + ]); + + // Hide the map type control. + map.innerMap.setOptions({ mapTypeControl: false }); + + // Function to update map and marker based on place details + const updateMapAndMarker = () => { + if (placeDetails.place?.location) { + map.innerMap.panTo(placeDetails.place.location); + map.innerMap.setZoom(16); // Set zoom after panning if needed + marker.position = placeDetails.place.location; + marker.collisionBehavior = 'REQUIRED_AND_HIDES_OPTIONAL'; + marker.style.display = 'block'; + } + }; + + // Set up map once widget is loaded. + placeDetails.addEventListener('gmp-load', () => { + updateMapAndMarker(); + }); + + /* [START maps_ui_kit_advanced_place_details_event] */ + // Add an event listener to handle clicks. + map.innerMap.addListener( + 'click', + (event: google.maps.MapMouseEvent | google.maps.IconMouseEvent) => { + marker.position = null; + event.stop(); + if ('placeId' in event && event.placeId) { + // Fire when the user clicks a POI. + placeDetailsRequest.place = event.placeId; + updateMapAndMarker(); + } else { + // Fire when the user clicks the map (not on a POI). + console.log('No place was selected.'); + marker.style.display = 'none'; + } + } + ); +} +/* [END maps_ui_kit_advanced_place_details_event] */ + +void init(); +/* [END maps_ui_kit_advanced_place_details] */ diff --git a/samples/ui-kit-advanced-place-details/package.json b/samples/ui-kit-advanced-place-details/package.json new file mode 100644 index 000000000..2389197c2 --- /dev/null +++ b/samples/ui-kit-advanced-place-details/package.json @@ -0,0 +1,12 @@ +{ + "name": "@js-api-samples/ui-kit-advanced-place-details", + "version": "1.0.0", + "scripts": { + "build": "bash ../build-single.sh", + "test": "tsc && npm run build:vite --workspace=.", + "start": "tsc && vite build --config ../../vite.config.js --base './' && vite --config ../../vite.config.js", + "build:vite": "vite build --config ../../vite.config.js --base './'", + "preview": "vite preview --config ../../vite.config.js" + }, + "author": "Google LLC" +} diff --git a/samples/ui-kit-advanced-place-details/style.css b/samples/ui-kit-advanced-place-details/style.css new file mode 100644 index 000000000..00b52b867 --- /dev/null +++ b/samples/ui-kit-advanced-place-details/style.css @@ -0,0 +1,38 @@ +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_place_details] */ +/* + * Optional: Makes the sample page fill the window. + */ +html, +body { + height: 100%; + margin: 0; + padding: 0; +} + +.container { + display: flex; + height: 100vh; + width: 100%; +} + +gmp-map { + flex-grow: 1; +} + +.ui-panel { + width: 400px; + margin-left: 20px; + margin-top: 10px; +} + +gmp-place-details { + width: 100%; + margin: 0; + border: none; +} +/* [END maps_ui_kit_place_details] */ diff --git a/samples/ui-kit-advanced-place-details/tsconfig.json b/samples/ui-kit-advanced-place-details/tsconfig.json new file mode 100644 index 000000000..976bcc6ef --- /dev/null +++ b/samples/ui-kit-advanced-place-details/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./*.ts"] +} diff --git a/samples/ui-kit-advanced-place-search-nearby/README.md b/samples/ui-kit-advanced-place-search-nearby/README.md new file mode 100644 index 000000000..a8ca7cb72 --- /dev/null +++ b/samples/ui-kit-advanced-place-search-nearby/README.md @@ -0,0 +1,35 @@ +# Google Maps JavaScript Sample + +## ui-kit-place-search-nearby + +The ui-kit-place-search-nearby sample demonstrates using the Places UI Kit PlaceSearchElement. + +Follow these instructions to set up and run ui-kit-place-search-nearby sample on your local computer. + +## Setup + +### Before starting run: + +`$npm i` + +### Run an example on a local web server + +First `cd` to the folder for the sample to run, then: + +`$npm start` + +### Build an individual example + +From `samples/`: + +`$npm run build --workspace=ui-kit-place-search-nearby/` + +### Build all of the examples. + +From `samples/`: +`$npm run build-all` + +## Feedback + +For feedback related to this sample, please open a new issue on +[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues). diff --git a/samples/ui-kit-advanced-place-search-nearby/index.html b/samples/ui-kit-advanced-place-search-nearby/index.html new file mode 100644 index 000000000..0427806ad --- /dev/null +++ b/samples/ui-kit-advanced-place-search-nearby/index.html @@ -0,0 +1,82 @@ + + + + + + Place Search Nearby with Google Maps + + + + + + + + +
+ + + +
+
+ +
+
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + diff --git a/samples/ui-kit-advanced-place-search-nearby/index.ts b/samples/ui-kit-advanced-place-search-nearby/index.ts new file mode 100644 index 000000000..c0d17581b --- /dev/null +++ b/samples/ui-kit-advanced-place-search-nearby/index.ts @@ -0,0 +1,125 @@ +/* eslint-disable */ +// @ts-nocheck +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_advanced_place_search_nearby] */ + +/* [START maps_ui_kit_advanced_place_search_nearby_query_selectors] */ +// Query selectors for various elements in the HTML file. +const map = document.querySelector('gmp-map')!; +const placeSearch: any = document.querySelector('gmp-advanced-place-search')!; +const placeSearchQuery: any = document.querySelector( + 'gmp-place-nearby-search-request' +)!; +const placeDetails = document.querySelector( + 'gmp-advanced-place-details-compact' +)!; +const placeRequest: any = document.querySelector( + 'gmp-place-details-place-request' +)!; +const typeSelect = document.querySelector('.type-select') as HTMLSelectElement; +/* [END maps_ui_kit_advanced_place_search_nearby_query_selectors] */ + +// Global variables for the map, markers, and info window. +const markers = new Map(); +let infoWindow: google.maps.InfoWindow; + +// The init function is called when the page loads. +async function init(): Promise { + // Import the necessary libraries from the Google Maps API. + const [{ InfoWindow }] = await Promise.all([ + google.maps.importLibrary('maps'), + google.maps.importLibrary('places'), + ]); + + // Create a new info window and set its content to the place details element. + placeDetails.remove(); // Hide the place details element because it is not needed until the info window opens + infoWindow = new InfoWindow({ + content: placeDetails, + ariaLabel: 'Place Details', + }); + + // Set the map options. + map.innerMap.setOptions({ + clickableIcons: false, + mapTypeControl: false, + streetViewControl: false, + }); + + /* [START maps_ui_kit_advanced_place_search_nearby_event] */ + // Add event listeners to the type select and place search elements. + typeSelect.addEventListener('change', () => { + searchPlaces(); + }); + + placeSearch.addEventListener('gmp-select', (event) => { + const { place } = event; + markers.get(place.id)?.click(); + }); + placeSearch.addEventListener('gmp-load', () => { + void addMarkers(); + }); + + searchPlaces(); +} +/* [END maps_ui_kit_advanced_place_search_nearby_event] */ +/* [START maps_ui_kit_advanced_place_search_nearby_function] */ +// The searchPlaces function is called when the user changes the type select or when the page loads. +function searchPlaces() { + // Close the info window and clear the markers. + infoWindow.close(); + for (const marker of markers.values()) { + marker.remove(); + } + markers.clear(); + + // Set the place search query and add an event listener to the place search element. + if (typeSelect.value) { + const center = map.center!; + placeSearchQuery.locationRestriction = { + center, + radius: 50000, // 50km radius + }; + placeSearchQuery.includedTypes = [typeSelect.value]; + } +} +/* [END maps_ui_kit_advanced_place_search_nearby_function] */ + +// The addMarkers function is called when the place search element loads. +async function addMarkers() { + // Import the necessary libraries from the Google Maps API. + const [{ AdvancedMarkerElement }, { LatLngBounds }] = await Promise.all([ + google.maps.importLibrary('marker'), + google.maps.importLibrary('core'), + ]); + const bounds = new LatLngBounds(); + + if (placeSearch.places.length === 0) { + return; + } + + for (const place of placeSearch.places) { + if (!place.location) continue; + const marker = new AdvancedMarkerElement({ + map: map.innerMap, + position: place.location, + collisionBehavior: 'REQUIRED_AND_HIDES_OPTIONAL', + }); + + markers.set(place.id, marker); + bounds.extend(place.location); + + marker.addListener('click', () => { + placeRequest.place = place; + infoWindow.open(map.innerMap, marker); + }); + } + + map.innerMap.fitBounds(bounds); +} + +void init(); +/* [END maps_ui_kit_advanced_place_search_nearby] */ diff --git a/samples/ui-kit-advanced-place-search-nearby/package.json b/samples/ui-kit-advanced-place-search-nearby/package.json new file mode 100644 index 000000000..9c0fa33dc --- /dev/null +++ b/samples/ui-kit-advanced-place-search-nearby/package.json @@ -0,0 +1,12 @@ +{ + "name": "@js-api-samples/ui-kit-advanced-place-search-nearby-nearby", + "version": "1.0.0", + "scripts": { + "build": "bash ../build-single.sh", + "test": "tsc && npm run build:vite --workspace=.", + "start": "tsc && vite build --config ../../vite.config.js --base './' && vite --config ../../vite.config.js", + "build:vite": "vite build --config ../../vite.config.js --base './'", + "preview": "vite preview --config ../../vite.config.js" + }, + "author": "Google LLC" +} diff --git a/samples/ui-kit-advanced-place-search-nearby/style.css b/samples/ui-kit-advanced-place-search-nearby/style.css new file mode 100644 index 000000000..fbbf74498 --- /dev/null +++ b/samples/ui-kit-advanced-place-search-nearby/style.css @@ -0,0 +1,49 @@ +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_place_search_nearby] */ +html, +body { + height: 100%; + margin: 0; +} + +body { + display: flex; + flex-direction: column; + font-family: Arial, Helvetica, sans-serif; +} + +.container { + display: flex; + height: 100vh; + width: 100%; +} + +gmp-map { + flex-grow: 1; +} + +.ui-panel { + width: 400px; + margin-left: 20px; + margin-top: 10px; + overflow-y: auto; + font-family: Arial, Helvetica, sans-serif; +} + +.list-container { + display: flex; + flex-direction: column; +} + +gmp-place-search { + width: 100%; + margin: 0; + border: none; + color-scheme: light; +} + +/* [END maps_ui_kit_place_search_nearby] */ diff --git a/samples/ui-kit-advanced-place-search-nearby/tsconfig.json b/samples/ui-kit-advanced-place-search-nearby/tsconfig.json new file mode 100644 index 000000000..976bcc6ef --- /dev/null +++ b/samples/ui-kit-advanced-place-search-nearby/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./*.ts"] +} diff --git a/samples/ui-kit-advanced-place-search-text/README.md b/samples/ui-kit-advanced-place-search-text/README.md new file mode 100644 index 000000000..60ec6494e --- /dev/null +++ b/samples/ui-kit-advanced-place-search-text/README.md @@ -0,0 +1,35 @@ +# Google Maps JavaScript Sample + +## ui-kit-place-search-text + +The ui-kit-place-search-text-compact sample demonstrates performing a text search using the Places UI Kit Place Search element. + +Follow these instructions to set up and run ui-kit-place-search-text sample on your local computer. + +## Setup + +### Before starting run: + +`$npm i` + +### Run an example on a local web server + +First `cd` to the folder for the sample to run, then: + +`$npm start` + +### Build an individual example + +From `samples/`: + +`$npm run build --workspace=ui-kit-place-search-text/` + +### Build all of the examples. + +From `samples/`: +`$npm run build-all` + +## Feedback + +For feedback related to this sample, please open a new issue on +[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues). diff --git a/samples/ui-kit-advanced-place-search-text/index.html b/samples/ui-kit-advanced-place-search-text/index.html new file mode 100644 index 000000000..3298789db --- /dev/null +++ b/samples/ui-kit-advanced-place-search-text/index.html @@ -0,0 +1,79 @@ + + + + + + Place Text Search with Google Maps + + + + + + + + +
+
+
+ + +
+
+ + + + +
+
+ + + +
+ + + + + + + + + + + + + + + + + diff --git a/samples/ui-kit-advanced-place-search-text/index.ts b/samples/ui-kit-advanced-place-search-text/index.ts new file mode 100644 index 000000000..53003dafb --- /dev/null +++ b/samples/ui-kit-advanced-place-search-text/index.ts @@ -0,0 +1,135 @@ +/* eslint-disable */ +// @ts-nocheck +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_advanced_place_search_text] */ + +/* [START maps_ui_kit_advanced_place_search_text_query_selectors] */ +// Query selectors for various elements in the HTML file. +const map = document.querySelector('gmp-map')!; +const placeSearch: any = document.querySelector('gmp-advanced-place-search')!; +const placeSearchQuery: any = document.querySelector( + 'gmp-place-text-search-request' +)!; +const placeDetails = document.querySelector( + 'gmp-advanced-place-details-compact' +)!; +const placeRequest: any = document.querySelector( + 'gmp-place-details-place-request' +)!; +const queryInput = document.querySelector('.query-input') as HTMLInputElement; +const searchButton = document.querySelector('.search-button')!; +/* [END maps_ui_kit_advanced_place_search_text_query_selectors] */ + +// Global variables for the map, markers, and info window. +const markers = new Map(); +let infoWindow: google.maps.InfoWindow; + +// The init function is called when the page loads. +async function init(): Promise { + // Import the necessary libraries from the Google Maps API. + const [{ InfoWindow }] = await Promise.all([ + google.maps.importLibrary('maps'), + google.maps.importLibrary('places'), + ]); + + // Create a new info window and set its content to the place details element. + placeDetails.remove(); // Hide the place details element because it is not needed until the info window opens + infoWindow = new InfoWindow({ + content: placeDetails, + ariaLabel: 'Place Details', + }); + + // Set the map options. + map.innerMap.setOptions({ + clickableIcons: false, + mapTypeControl: false, + streetViewControl: false, + }); + + /* [START maps_ui_kit_advanced_place_search_text_event] */ + // Add event listeners to the query input and place search elements. + searchButton.addEventListener('click', () => { + searchPlaces(); + }); + queryInput.addEventListener('keydown', (event) => { + if (event.key === 'Enter') { + searchPlaces(); + } + }); + + placeSearch.addEventListener('gmp-select', (event) => { + const { place } = event; + markers.get(place.id)?.click(); + }); + placeSearch.addEventListener('gmp-load', () => { + void addMarkers(); + }); + + searchPlaces(); +} +/* [END maps_ui_kit_advanced_place_search_text_event] */ +/* [START maps_ui_kit_advanced_place_search_text_function] */ +// The searchPlaces function is called when the user changes the query input or when the page loads. +function searchPlaces() { + // Close the info window and clear the markers. + infoWindow.close(); + for (const marker of markers.values()) { + marker.remove(); + } + markers.clear(); + + // Set the place search query and add an event listener to the place search element. + if (queryInput.value) { + const center = map.center; + if (center) { + placeSearchQuery.locationBias = center; + } + // The textQuery property is required for the search element to load. + // Any other configured properties will be ignored if textQuery is not set. + placeSearchQuery.textQuery = queryInput.value; + } +} +/* [END maps_ui_kit_advanced_place_search_text_function] */ + +// The addMarkers function is called when the place search element loads. +async function addMarkers() { + // Import the necessary libraries from the Google Maps API. + const [{ AdvancedMarkerElement }, { LatLngBounds }] = await Promise.all([ + google.maps.importLibrary('marker'), + google.maps.importLibrary('core'), + ]); + const bounds = new LatLngBounds(); + + if (placeSearch.places.length === 0) { + return; + } + + for (const place of placeSearch.places) { + if (!place.location) { + continue; + } + + const marker = new AdvancedMarkerElement({ + map: map.innerMap, + position: place.location, + collisionBehavior: 'REQUIRED_AND_HIDES_OPTIONAL', + }); + + markers.set(place.id, marker); + bounds.extend(place.location); + + marker.addListener('click', () => { + placeRequest.place = place; + infoWindow.open(map.innerMap, marker); + }); + } + + map.innerMap.fitBounds(bounds); +} + +void init(); +/* [END maps_ui_kit_advanced_place_search_text] */ diff --git a/samples/ui-kit-advanced-place-search-text/package.json b/samples/ui-kit-advanced-place-search-text/package.json new file mode 100644 index 000000000..f794c35d1 --- /dev/null +++ b/samples/ui-kit-advanced-place-search-text/package.json @@ -0,0 +1,12 @@ +{ + "name": "@js-api-samples/ui-kit-advanced-place-search-text", + "version": "1.0.0", + "scripts": { + "build": "bash ../build-single.sh", + "test": "tsc && npm run build:vite --workspace=.", + "start": "tsc && vite build --config ../../vite.config.js --base './' && vite --config ../../vite.config.js", + "build:vite": "vite build --config ../../vite.config.js --base './'", + "preview": "vite preview --config ../../vite.config.js" + }, + "author": "Google LLC" +} diff --git a/samples/ui-kit-advanced-place-search-text/style.css b/samples/ui-kit-advanced-place-search-text/style.css new file mode 100644 index 000000000..59d984af0 --- /dev/null +++ b/samples/ui-kit-advanced-place-search-text/style.css @@ -0,0 +1,73 @@ +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* [START maps_ui_kit_place_search_text] */ +html, +body { + height: 100%; + margin: 0; +} + +body { + display: flex; + flex-direction: column; + font-family: Arial, Helvetica, sans-serif; +} + +.container { + display: flex; + height: 100vh; + width: 100%; +} + +gmp-map { + flex-grow: 1; +} + +.ui-panel { + width: 400px; + margin-left: 20px; + margin-right: 20px; + margin-top: 10px; + overflow-y: auto; + font-family: Arial, Helvetica, sans-serif; +} + +.list-container { + display: flex; + flex-direction: column; +} + +gmp-place-search { + width: 100%; + margin: 0; + border: none; + color-scheme: light; +} + +.query-input { + width: 100%; + padding: 8px; + margin-bottom: 10px; + box-sizing: border-box; +} + +.search-button { + width: 100%; + padding: 8px; + margin-bottom: 10px; + box-sizing: border-box; + background-color: #1a73e8; + color: white; + border: none; + cursor: pointer; +} + +.search-button:hover, +.search-button:focus-visible { + background-color: #1765cc; +} + +/* [END maps_ui_kit_place_search_text] */ diff --git a/samples/ui-kit-advanced-place-search-text/tsconfig.json b/samples/ui-kit-advanced-place-search-text/tsconfig.json new file mode 100644 index 000000000..976bcc6ef --- /dev/null +++ b/samples/ui-kit-advanced-place-search-text/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./*.ts"] +} From 405e8494b9618433d2e69379222aa9eda5f87065 Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 01:14:09 +0000 Subject: [PATCH 02/16] fix(samples): add v=alpha to preview advanced place UI elements --- samples/ui-kit-advanced-place-details-compact/index.html | 3 ++- samples/ui-kit-advanced-place-details/index.html | 3 ++- samples/ui-kit-advanced-place-search-nearby/index.html | 3 ++- samples/ui-kit-advanced-place-search-text/index.html | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/samples/ui-kit-advanced-place-details-compact/index.html b/samples/ui-kit-advanced-place-details-compact/index.html index 8f593c805..d3726af9c 100644 --- a/samples/ui-kit-advanced-place-details-compact/index.html +++ b/samples/ui-kit-advanced-place-details-compact/index.html @@ -14,7 +14,8 @@ diff --git a/samples/ui-kit-advanced-place-details/index.html b/samples/ui-kit-advanced-place-details/index.html index 592a9fc9d..f07d0cb43 100644 --- a/samples/ui-kit-advanced-place-details/index.html +++ b/samples/ui-kit-advanced-place-details/index.html @@ -14,7 +14,8 @@ diff --git a/samples/ui-kit-advanced-place-search-nearby/index.html b/samples/ui-kit-advanced-place-search-nearby/index.html index 0427806ad..71188a70e 100644 --- a/samples/ui-kit-advanced-place-search-nearby/index.html +++ b/samples/ui-kit-advanced-place-search-nearby/index.html @@ -14,7 +14,8 @@ diff --git a/samples/ui-kit-advanced-place-search-text/index.html b/samples/ui-kit-advanced-place-search-text/index.html index 3298789db..d998edc83 100644 --- a/samples/ui-kit-advanced-place-search-text/index.html +++ b/samples/ui-kit-advanced-place-search-text/index.html @@ -14,7 +14,8 @@ From 21b6e40923a8107db9b665c482022b1daa4fb97a Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 01:44:23 +0000 Subject: [PATCH 03/16] fix(samples): change v=alpha to v=beta for advanced place elements --- samples/ui-kit-advanced-place-details-compact/index.html | 2 +- samples/ui-kit-advanced-place-details/index.html | 2 +- samples/ui-kit-advanced-place-search-nearby/index.html | 2 +- samples/ui-kit-advanced-place-search-text/index.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/ui-kit-advanced-place-details-compact/index.html b/samples/ui-kit-advanced-place-details-compact/index.html index d3726af9c..f006e36ee 100644 --- a/samples/ui-kit-advanced-place-details-compact/index.html +++ b/samples/ui-kit-advanced-place-details-compact/index.html @@ -15,7 +15,7 @@ // prettier-ignore (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({ key: "GOOGLE_MAPS_API_KEY", - v: "alpha" + v: "beta" }); diff --git a/samples/ui-kit-advanced-place-details/index.html b/samples/ui-kit-advanced-place-details/index.html index f07d0cb43..da2005a5b 100644 --- a/samples/ui-kit-advanced-place-details/index.html +++ b/samples/ui-kit-advanced-place-details/index.html @@ -15,7 +15,7 @@ // prettier-ignore (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({ key: "GOOGLE_MAPS_API_KEY", - v: "alpha" + v: "beta" }); diff --git a/samples/ui-kit-advanced-place-search-nearby/index.html b/samples/ui-kit-advanced-place-search-nearby/index.html index 71188a70e..c22df900f 100644 --- a/samples/ui-kit-advanced-place-search-nearby/index.html +++ b/samples/ui-kit-advanced-place-search-nearby/index.html @@ -15,7 +15,7 @@ // prettier-ignore (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({ key: "GOOGLE_MAPS_API_KEY", - v: "alpha" + v: "beta" }); diff --git a/samples/ui-kit-advanced-place-search-text/index.html b/samples/ui-kit-advanced-place-search-text/index.html index d998edc83..dffe0f582 100644 --- a/samples/ui-kit-advanced-place-search-text/index.html +++ b/samples/ui-kit-advanced-place-search-text/index.html @@ -15,7 +15,7 @@ // prettier-ignore (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({ key: "GOOGLE_MAPS_API_KEY", - v: "alpha" + v: "beta" }); From c9c9141c9d898772baf85223ac051e95efd817e9 Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 01:53:54 +0000 Subject: [PATCH 04/16] fix(samples): explicitly list gmp-place-name so Place titles render in advanced details --- package-lock.json | 564 ++++++++++++++++++ .../index.html | 1 + .../ui-kit-advanced-place-details/index.html | 1 + samples/ui-kit-place-details-demo/index.html | 87 +++ .../index.html.metadata.json | 5 + samples/ui-kit-place-details-demo/index.ts | 381 ++++++++++++ .../index.ts.metadata.json | 5 + .../ui-kit-place-details-demo/package.json | 15 + .../package.json.metadata.json | 5 + samples/ui-kit-place-details-demo/style.css | 508 ++++++++++++++++ .../style.css.metadata.json | 5 + 11 files changed, 1577 insertions(+) create mode 100644 samples/ui-kit-place-details-demo/index.html create mode 100644 samples/ui-kit-place-details-demo/index.html.metadata.json create mode 100644 samples/ui-kit-place-details-demo/index.ts create mode 100644 samples/ui-kit-place-details-demo/index.ts.metadata.json create mode 100644 samples/ui-kit-place-details-demo/package.json create mode 100644 samples/ui-kit-place-details-demo/package.json.metadata.json create mode 100644 samples/ui-kit-place-details-demo/style.css create mode 100644 samples/ui-kit-place-details-demo/style.css.metadata.json diff --git a/package-lock.json b/package-lock.json index 7585616a0..4538ae22e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1483,6 +1483,22 @@ "resolved": "samples/test-example", "link": true }, + "node_modules/@js-api-samples/ui-kit-advanced-place-details": { + "resolved": "samples/ui-kit-advanced-place-details", + "link": true + }, + "node_modules/@js-api-samples/ui-kit-advanced-place-details-compact": { + "resolved": "samples/ui-kit-advanced-place-details-compact", + "link": true + }, + "node_modules/@js-api-samples/ui-kit-advanced-place-search-nearby-nearby": { + "resolved": "samples/ui-kit-advanced-place-search-nearby", + "link": true + }, + "node_modules/@js-api-samples/ui-kit-advanced-place-search-text": { + "resolved": "samples/ui-kit-advanced-place-search-text", + "link": true + }, "node_modules/@js-api-samples/ui-kit-place-details": { "resolved": "samples/ui-kit-place-details", "link": true @@ -1491,6 +1507,10 @@ "resolved": "samples/ui-kit-place-details-compact", "link": true }, + "node_modules/@js-api-samples/ui-kit-place-details-demo": { + "resolved": "samples/ui-kit-place-details-demo", + "link": true + }, "node_modules/@js-api-samples/ui-kit-place-search-nearby-nearby": { "resolved": "samples/ui-kit-place-search-nearby", "link": true @@ -7015,6 +7035,22 @@ "name": "@js-api-samples/test-example", "version": "1.0.0" }, + "samples/ui-kit-advanced-place-details": { + "name": "@js-api-samples/ui-kit-advanced-place-details", + "version": "1.0.0" + }, + "samples/ui-kit-advanced-place-details-compact": { + "name": "@js-api-samples/ui-kit-advanced-place-details-compact", + "version": "1.0.0" + }, + "samples/ui-kit-advanced-place-search-nearby": { + "name": "@js-api-samples/ui-kit-advanced-place-search-nearby-nearby", + "version": "1.0.0" + }, + "samples/ui-kit-advanced-place-search-text": { + "name": "@js-api-samples/ui-kit-advanced-place-search-text", + "version": "1.0.0" + }, "samples/ui-kit-place-details": { "name": "@js-api-samples/ui-kit-place-details", "version": "1.0.0" @@ -7023,6 +7059,534 @@ "name": "@js-api-samples/ui-kit-place-details-compact", "version": "1.0.0" }, + "samples/ui-kit-place-details-demo": { + "name": "@js-api-samples/ui-kit-place-details-demo", + "version": "1.0.0", + "devDependencies": { + "@types/google.maps": "^3.58.1", + "typescript": "^5.4.5", + "vite": "^5.2.11" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "samples/ui-kit-place-details-demo/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "samples/ui-kit-place-details-demo/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "samples/ui-kit-place-details-demo/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "samples/ui-kit-place-details-demo/node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, "samples/ui-kit-place-search-nearby": { "name": "@js-api-samples/ui-kit-place-search-nearby-nearby", "version": "1.0.0" diff --git a/samples/ui-kit-advanced-place-details-compact/index.html b/samples/ui-kit-advanced-place-details-compact/index.html index f006e36ee..7e3bfa075 100644 --- a/samples/ui-kit-advanced-place-details-compact/index.html +++ b/samples/ui-kit-advanced-place-details-compact/index.html @@ -48,6 +48,7 @@ + diff --git a/samples/ui-kit-advanced-place-details/index.html b/samples/ui-kit-advanced-place-details/index.html index da2005a5b..f8d6aa905 100644 --- a/samples/ui-kit-advanced-place-details/index.html +++ b/samples/ui-kit-advanced-place-details/index.html @@ -31,6 +31,7 @@ + diff --git a/samples/ui-kit-place-details-demo/index.html b/samples/ui-kit-place-details-demo/index.html new file mode 100644 index 000000000..f972f3bd3 --- /dev/null +++ b/samples/ui-kit-place-details-demo/index.html @@ -0,0 +1,87 @@ + + + + + + + Place Details Demo — Google Maps Platform Places UI Kit + + + + + + + + + + + + +
+
+ + +
+ + + + +
+
+
+ + diff --git a/samples/ui-kit-place-details-demo/index.html.metadata.json b/samples/ui-kit-place-details-demo/index.html.metadata.json new file mode 100644 index 000000000..490843e19 --- /dev/null +++ b/samples/ui-kit-place-details-demo/index.html.metadata.json @@ -0,0 +1,5 @@ +{ + "summary": "HTML file for the Place Details interactive customizer demo.", + "updatedAt": "2026-08-16T17:37:49.145049639Z", + "userFacing": true +} \ No newline at end of file diff --git a/samples/ui-kit-place-details-demo/index.ts b/samples/ui-kit-place-details-demo/index.ts new file mode 100644 index 000000000..244dee962 --- /dev/null +++ b/samples/ui-kit-place-details-demo/index.ts @@ -0,0 +1,381 @@ +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* [START maps_ui_kit_place_details_customizer] */ + +interface SuggestionItem { + placeId: string; + mainText: string; + mainMatches: Array<{ startOffset: number; endOffset: number }>; + secondaryText?: string; + distanceText?: string; + fullText: string; +} + +let sessionToken: google.maps.places.AutocompleteSessionToken | null = null; +let currentSuggestions: SuggestionItem[] = []; +let selectedSuggestionIndex = -1; +let debounceTimeout: number | undefined; + +async function init(): Promise { + // 1. Request required Google Maps libraries + const [, placesLib] = await Promise.all([ + google.maps.importLibrary('maps'), + google.maps.importLibrary('places') as Promise, + google.maps.importLibrary('marker'), + ]); + + const placeDetailsWidget = document.querySelector('#place-details-widget')!; + const placeDetailsRequest = document.querySelector('#place-details-request')!; + const addressInput = document.querySelector('#address')!; + const autocompleteList = document.querySelector('#autocomplete-list')!; + + // -------------------------------------------------------------------------- + // Content Configuration Switching + // -------------------------------------------------------------------------- + const contentConfigButtons = document.querySelectorAll( + '#content-config-buttons .segmented-button' + ); + + contentConfigButtons.forEach((button) => { + button.addEventListener('click', () => { + contentConfigButtons.forEach((btn) => { + btn.classList.remove('active'); + btn.setAttribute('aria-pressed', 'false'); + }); + button.classList.add('active'); + button.setAttribute('aria-pressed', 'true'); + + const mode = button.getAttribute('data-value'); + applyContentConfig(mode); + }); + }); + + function applyContentConfig(mode: string | null) { + // Preserve the place-request child element + const currentPlace = placeDetailsRequest.getAttribute('place') || 'places/ChIJ5abCmkWHhYARH3zgiLVc_Ew'; + placeDetailsWidget.innerHTML = ''; + + const newRequest = document.createElement('gmp-place-details-place-request'); + newRequest.id = 'place-details-request'; + newRequest.setAttribute('place', currentPlace); + placeDetailsWidget.appendChild(newRequest); + + if (mode === 'standard') { + const standardContent = document.createElement('gmp-place-standard-content'); + placeDetailsWidget.appendChild(standardContent); + } else if (mode === 'all') { + const allContent = document.createElement('gmp-place-all-content'); + placeDetailsWidget.appendChild(allContent); + } else if (mode === 'custom') { + const customConfig = document.createElement('gmp-place-content-config'); + + const elementsToInclude = [ + { tag: 'gmp-place-media', attrs: { 'lightbox-preferred': '' } }, + { tag: 'gmp-place-summary' }, + { tag: 'gmp-place-address' }, + { tag: 'gmp-place-rating' }, + { tag: 'gmp-place-open-now-status' }, + { tag: 'gmp-place-price' }, + { tag: 'gmp-place-type' }, + { tag: 'gmp-place-website' }, + { tag: 'gmp-place-phone-number' }, + { tag: 'gmp-place-plus-code' }, + { tag: 'gmp-place-accessible-entrance-icon' }, + ]; + + elementsToInclude.forEach(({ tag, attrs }) => { + const el = document.createElement(tag); + if (attrs) { + Object.entries(attrs).forEach(([key, val]) => el.setAttribute(key, val)); + } + customConfig.appendChild(el); + }); + + placeDetailsWidget.appendChild(customConfig); + } + } + + // -------------------------------------------------------------------------- + // Theme Switching + // -------------------------------------------------------------------------- + const themeButtons = document.querySelectorAll( + '#theme-buttons .segmented-button' + ); + + themeButtons.forEach((button) => { + button.addEventListener('click', () => { + themeButtons.forEach((btn) => { + btn.classList.remove('active'); + btn.setAttribute('aria-pressed', 'false'); + }); + button.classList.add('active'); + button.setAttribute('aria-pressed', 'true'); + + const theme = button.getAttribute('data-value'); + placeDetailsWidget.classList.remove('theme-google', 'theme-miami', 'theme-redwood'); + + if (theme === 'example1') { + placeDetailsWidget.classList.add('theme-miami'); + } else if (theme === 'example2') { + placeDetailsWidget.classList.add('theme-redwood'); + } else { + placeDetailsWidget.classList.add('theme-google'); + } + }); + }); + + // -------------------------------------------------------------------------- + // Autocomplete Search Logic + // -------------------------------------------------------------------------- + function getSessionToken(): google.maps.places.AutocompleteSessionToken { + if (!sessionToken && placesLib.AutocompleteSessionToken) { + sessionToken = new placesLib.AutocompleteSessionToken(); + } + return sessionToken!; + } + + async function fetchSuggestions(query: string): Promise { + if (!query.trim()) { + closeDropdown(); + return; + } + + try { + if (placesLib.AutocompleteSuggestion?.fetchAutocompleteSuggestions) { + const response = await placesLib.AutocompleteSuggestion.fetchAutocompleteSuggestions({ + input: query, + sessionToken: getSessionToken(), + }); + + if (response?.suggestions && response.suggestions.length > 0) { + currentSuggestions = response.suggestions + .filter((s) => s.placePrediction) + .map((s) => { + const pred = s.placePrediction!; + const mainText = + typeof pred.mainText === 'string' + ? pred.mainText + : pred.mainText?.text ?? pred.text?.text ?? ''; + const secondaryText = + typeof pred.secondaryText === 'string' + ? pred.secondaryText + : pred.secondaryText?.text ?? ''; + const fullText = + typeof pred.text === 'string' ? pred.text : pred.text?.text ?? mainText; + + let distanceText: string | undefined; + if (pred.distanceMeters && pred.distanceMeters > 0) { + distanceText = `${(pred.distanceMeters / 1609.34).toFixed(1)} mi`; + } + + const mainMatches = (pred.mainText?.matches || []).map((m) => ({ + startOffset: m.startOffset, + endOffset: m.endOffset, + })); + + return { + placeId: pred.placeId, + mainText, + mainMatches, + secondaryText, + distanceText, + fullText, + }; + }); + + renderDropdown(); + return; + } + } + } catch (err) { + console.warn('Error fetching autocomplete suggestions:', err); + } + + closeDropdown(); + } + + function renderDropdown(): void { + if (currentSuggestions.length === 0) { + closeDropdown(); + return; + } + + autocompleteList.innerHTML = ''; + autocompleteList.removeAttribute('hidden'); + selectedSuggestionIndex = -1; + + currentSuggestions.forEach((item, index) => { + const itemEl = document.createElement('div'); + itemEl.className = 'autocomplete-list-item'; + itemEl.setAttribute('data-index', String(index)); + + // Pin Icon Container + const iconContainer = document.createElement('div'); + iconContainer.className = 'autocomplete-icon-container'; + iconContainer.innerHTML = ` + + `; + itemEl.appendChild(iconContainer); + + // Text Container + const textContainer = document.createElement('div'); + textContainer.className = 'autocomplete-text-container'; + + const titleEl = document.createElement('p'); + titleEl.className = 'autocomplete-item-title'; + titleEl.innerHTML = buildHighlightedText(item.mainText, item.mainMatches); + textContainer.appendChild(titleEl); + + if (item.secondaryText || item.distanceText) { + const subtitleEl = document.createElement('div'); + subtitleEl.className = 'autocomplete-item-subtitle'; + + if (item.distanceText) { + const distSpan = document.createElement('span'); + distSpan.className = 'autocomplete-distance'; + distSpan.textContent = item.distanceText; + subtitleEl.appendChild(distSpan); + + const dotSpan = document.createElement('span'); + dotSpan.className = 'autocomplete-dot'; + dotSpan.textContent = '·'; + subtitleEl.appendChild(dotSpan); + } + + if (item.secondaryText) { + const secSpan = document.createElement('span'); + secSpan.className = 'autocomplete-secondary'; + secSpan.textContent = item.secondaryText; + subtitleEl.appendChild(secSpan); + } + + textContainer.appendChild(subtitleEl); + } + + itemEl.appendChild(textContainer); + + itemEl.addEventListener('click', () => selectSuggestion(item)); + autocompleteList.appendChild(itemEl); + }); + + // Attribution Footer + const footer = document.createElement('div'); + footer.className = 'autocomplete-attribution-footer'; + footer.innerHTML = 'Google Maps'; + autocompleteList.appendChild(footer); + } + + function buildHighlightedText( + text: string, + matches: Array<{ startOffset: number; endOffset: number }> + ): string { + if (!matches || matches.length === 0) { + return `${escapeHtml(text)}`; + } + + let html = ''; + let lastIndex = 0; + + matches.forEach(({ startOffset, endOffset }) => { + if (startOffset > lastIndex) { + html += `${escapeHtml(text.slice(lastIndex, startOffset))}`; + } + html += `${escapeHtml(text.slice(startOffset, endOffset))}`; + lastIndex = endOffset; + }); + + if (lastIndex < text.length) { + html += `${escapeHtml(text.slice(lastIndex))}`; + } + + return html; + } + + function escapeHtml(str: string): string { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + } + + function selectSuggestion(item: SuggestionItem): void { + addressInput.value = ''; + addressInput.placeholder = item.mainText || item.fullText; + closeDropdown(); + + // Update Place Request + const activeRequest = document.querySelector('#place-details-request'); + if (activeRequest) { + activeRequest.setAttribute('place', `places/${item.placeId}`); + } + + // Reset session token after selection + sessionToken = null; + } + + function closeDropdown(): void { + autocompleteList.setAttribute('hidden', ''); + autocompleteList.innerHTML = ''; + currentSuggestions = []; + selectedSuggestionIndex = -1; + } + + addressInput.addEventListener('input', () => { + window.clearTimeout(debounceTimeout); + debounceTimeout = window.setTimeout(() => { + fetchSuggestions(addressInput.value); + }, 150); + }); + + addressInput.addEventListener('keydown', (e: KeyboardEvent) => { + if (currentSuggestions.length === 0) return; + + const items = autocompleteList.querySelectorAll('.autocomplete-list-item'); + + if (e.key === 'ArrowDown') { + e.preventDefault(); + selectedSuggestionIndex = (selectedSuggestionIndex + 1) % items.length; + updateSelection(items); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + selectedSuggestionIndex = (selectedSuggestionIndex - 1 + items.length) % items.length; + updateSelection(items); + } else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedSuggestionIndex >= 0 && selectedSuggestionIndex < currentSuggestions.length) { + selectSuggestion(currentSuggestions[selectedSuggestionIndex]); + } else if (currentSuggestions.length > 0) { + selectSuggestion(currentSuggestions[0]); + } + } else if (e.key === 'Escape') { + closeDropdown(); + } + }); + + function updateSelection(items: NodeListOf): void { + items.forEach((item, index) => { + if (index === selectedSuggestionIndex) { + item.classList.add('selected'); + item.scrollIntoView({ block: 'nearest' }); + } else { + item.classList.remove('selected'); + } + }); + } + + document.addEventListener('click', (e) => { + if (!autocompleteList.contains(e.target as Node) && e.target !== addressInput) { + closeDropdown(); + } + }); +} + +void init(); +/* [END maps_ui_kit_place_details_customizer] */ diff --git a/samples/ui-kit-place-details-demo/index.ts.metadata.json b/samples/ui-kit-place-details-demo/index.ts.metadata.json new file mode 100644 index 000000000..659e02dc0 --- /dev/null +++ b/samples/ui-kit-place-details-demo/index.ts.metadata.json @@ -0,0 +1,5 @@ +{ + "summary": "TypeScript controller for Place Details interactive customizer demo.", + "updatedAt": "2026-08-16T17:38:05.012911974Z", + "userFacing": true +} \ No newline at end of file diff --git a/samples/ui-kit-place-details-demo/package.json b/samples/ui-kit-place-details-demo/package.json new file mode 100644 index 000000000..949e4ee6f --- /dev/null +++ b/samples/ui-kit-place-details-demo/package.json @@ -0,0 +1,15 @@ +{ + "name": "@js-api-samples/ui-kit-place-details-demo", + "version": "1.0.0", + "description": "Interactive Place Details customization demo with autocomplete search, content configurations, and custom brand themes.", + "main": "index.ts", + "scripts": { + "start": "vite", + "build": "vite build" + }, + "devDependencies": { + "@types/google.maps": "^3.58.1", + "typescript": "^5.4.5", + "vite": "^5.2.11" + } +} diff --git a/samples/ui-kit-place-details-demo/package.json.metadata.json b/samples/ui-kit-place-details-demo/package.json.metadata.json new file mode 100644 index 000000000..da38d377f --- /dev/null +++ b/samples/ui-kit-place-details-demo/package.json.metadata.json @@ -0,0 +1,5 @@ +{ + "summary": "package.json configuration for Place Details interactive customizer demo.", + "updatedAt": "2026-08-16T17:38:07.654115810Z", + "userFacing": true +} \ No newline at end of file diff --git a/samples/ui-kit-place-details-demo/style.css b/samples/ui-kit-place-details-demo/style.css new file mode 100644 index 000000000..ed107b995 --- /dev/null +++ b/samples/ui-kit-place-details-demo/style.css @@ -0,0 +1,508 @@ +/* + * @license + * Copyright 2025 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* ========================================================================== + Place Details Themes + ========================================================================== */ + +gmp-place-details { + box-sizing: border-box; + color-scheme: light dark; + display: block; + width: 400px; + height: 700px; + max-height: 700px; + flex-shrink: 0; +} + +@media (max-width: 880px) { + gmp-place-details { + width: 100%; + max-width: 400px; + } +} + +gmp-place-details.theme-google { + box-sizing: border-box; +} + +/* Miami Theme (Teal / Bold Accent / Pill Buttons) */ +gmp-place-details.theme-miami { + --gmp-mat-color-surface: light-dark(#fdf8f5, #1a2e3b); + --gmp-mat-color-on-surface: light-dark(#2f3f4f, #e0ebf5); + --gmp-mat-color-on-surface-variant: light-dark(#6a7a8a, #aabbdd); + --gmp-mat-color-primary: light-dark(#0097a7, #80deea); + --gmp-mat-color-info: light-dark(#0097a7, #80deea); + --gmp-mat-color-secondary-container: light-dark(#ffebee, #3b1b1f); + --gmp-mat-color-on-secondary-container: light-dark(#d81b60, #ffcdd2); + --gmp-mat-color-outline-decorative: light-dark(#e0e0e0, #4f5f6f); + --gmp-mat-color-negative: light-dark(#e53935, #ffcdd2); + --gmp-mat-color-positive: light-dark(#4caf50, #a5d6a7); + --gmp-star-rating-color: light-dark(#d81b60, #ffcdd2); + --gmp-mat-font-family: "Inter", "Roboto", sans-serif; + --gmp-mat-font-headline-medium: normal 600 1.25em / 1.3 var(--gmp-mat-font-family, "Inter", sans-serif); + --gmp-mat-font-title-small: normal 500 1em / 1.375 var(--gmp-mat-font-family, "Inter", sans-serif); + --gmp-mat-font-body-medium: normal 400 0.875em / calc(20 / 14) var(--gmp-mat-font-family, "Roboto", sans-serif); + --gmp-mat-font-body-small: normal 400 0.75em / calc(16 / 12) var(--gmp-mat-font-family, "Roboto", sans-serif); + --gmp-mat-font-label-large: normal 600 0.875em / calc(20 / 14) var(--gmp-mat-font-family, "Roboto", sans-serif); + --gmp-mat-spacing-extra-small: 4px; + --gmp-mat-spacing-small: 8px; + --gmp-mat-spacing-medium: 12px; + --gmp-mat-spacing-large: 16px; + --gmp-mat-spacing-extra-large: 20px; + --gmp-mat-spacing-two-extra-large: 24px; + --gmp-mat-border-radius: 10px; + --gmp-button-border-radius: 9999px; + --gmp-thumbnail-border-radius: 6px; + --gmp-collage-border-radius-outer: 10px; + --gmp-card-border-radius: 10px; + --gmp-dialog-border-radius: 18px; + box-sizing: border-box; +} + +/* Redwood Theme (Warm Earthy / Serif Headings) */ +gmp-place-details.theme-redwood { + --gmp-theme-font-family-headings-labels: "Domine", serif; + --gmp-theme-font-family-content: "Nunito Sans", sans-serif; + --gmp-mat-color-surface: light-dark(#f5f0e8, #3a2e29); + --gmp-mat-color-on-surface: light-dark(#5d4037, #e8e0d8); + --gmp-mat-color-on-surface-variant: light-dark(#795548, #b0a191); + --gmp-mat-color-surface-container: light-dark(#ebe5db, #2f2521); + --gmp-mat-color-primary: light-dark(#386641, #7cb342); + --gmp-mat-color-secondary-container: light-dark(#6a4c3b, #558b2f); + --gmp-mat-color-on-secondary-container: light-dark(#ffffff, #ffffff); + --gmp-mat-color-outline-decorative: light-dark(#c0b5a8, #5c4a42); + --gmp-mat-color-info: light-dark(#386641, #7cb342); + --gmp-mat-color-positive: light-dark(#4caf50, #8bc34a); + --gmp-mat-color-negative: light-dark(#b85c5c, #e57373); + --gmp-mat-color-disabled-surface: light-dark(#e0d8cd, #4e3f3a); + --gmp-mat-color-neutral-container: light-dark(#eae0d5, #4a3c35); + --gmp-mat-color-on-neutral-container: light-dark(#5d4037, #b0a191); + --gmp-mat-color-positive-container: light-dark(#d5e8d4, #33691e); + --gmp-mat-color-on-positive-container: light-dark(#2e5336, #c5e1a5); + --gmp-star-rating-color: light-dark(#bc6c25, #dda15e); + --gmp-mat-font-family: var(--gmp-theme-font-family-content); + --gmp-mat-font-body-medium: normal 400 0.9375em / calc(22 / 15) var(--gmp-mat-font-family); + --gmp-mat-font-body-small: normal 400 0.8125em / calc(18 / 13) var(--gmp-mat-font-family); + --gmp-mat-font-headline-large: normal 500 1.75em / calc(32 / 28) var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-headline-medium: normal 500 1.375em / calc(28 / 22) var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-title-small: normal 500 1.125em / calc(24 / 18) var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-display-small: normal 400 1.625em / calc(30 / 26) var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-label-large: normal 500 0.875em / calc(20 / 14) var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-label-medium: normal 500 0.75em / calc(16 / 12) var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-label-small: normal 500 0.6875em / calc(12 / 11) var(--gmp-theme-font-family-headings-labels); + box-sizing: border-box; +} + +/* ========================================================================== + Demo Page Layout + ========================================================================== */ + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, +body { + min-height: 100vh; + background-color: #f8f9fa; + font-family: "Google Sans", "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + color: #202124; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.page-wrapper { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 24px 16px; +} + +.demo-frame { + width: 839px; + min-height: 750px; + background-color: #ffffff; + border-radius: 16px; + box-shadow: 0 1px 3px rgba(60, 64, 67, 0.12), 0 4px 8px rgba(60, 64, 67, 0.08); + border: 1px solid #dadce0; + padding: 25px; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + gap: 50px; +} + +@media (max-width: 880px) { + .demo-frame { + width: 100%; + max-width: 839px; + flex-direction: column; + align-items: center; + gap: 32px; + padding: 20px; + } +} + +.left-column { + width: 339px; + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 20px; +} + +@media (max-width: 880px) { + .left-column { + width: 100%; + max-width: 400px; + } +} + +.demo-header { + width: 100%; + display: flex; + flex-direction: column; + gap: 8px; + align-items: flex-start; +} + +.demo-title-container { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; +} + +.demo-title { + font-family: "Roboto", sans-serif; + font-weight: 300; + font-size: 24px; + line-height: 32px; + color: #202124; + margin: 0; + white-space: nowrap; +} + +.component-description { + font-family: "Google Sans", "Roboto", sans-serif; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #202124; + margin: 0; + width: 100%; + white-space: pre-wrap; +} + +/* ========================================================================== + Search & Autocomplete Controls + ========================================================================== */ + +.address-input { + width: 100%; + display: flex; + flex-direction: column; + margin: 0; +} + +.form-group { + width: 100%; + display: flex; + flex-direction: column; + gap: 4px; + position: relative; +} + +.form-group label { + font-family: "Roboto", "Google Sans", sans-serif; + font-weight: 400; + font-size: 12px; + line-height: 16px; + color: #606368; + display: block; + margin: 0; + cursor: pointer; +} + +.form-group input[type="text"] { + width: 100%; + height: 40px; + background: #ffffff; + border: 1px solid #dadce0; + border-radius: 4px; + padding: 8px 12px; + font-family: "Roboto", sans-serif; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #202124; + outline: none; + box-sizing: border-box; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.form-group input[type="text"]:focus { + border-color: #1a73e8; + border-bottom: 2px solid #1a73e8; + padding-bottom: 7px; +} + +#autocomplete-list-wrapper { + position: relative; + width: 100%; +} + +.autocomplete-dropdown { + position: absolute; + top: 100%; + left: 0; + margin-top: 4px; + width: 100%; + background-color: #ffffff; + border-radius: 8px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 6px 2px rgba(0, 0, 0, 0.15); + overflow: hidden; + z-index: 10000; + box-sizing: border-box; + display: flex; + flex-direction: column; +} + +.autocomplete-list-item { + display: flex; + gap: 12px; + align-items: center; + padding: 8px 12px; + background-color: #ffffff; + border-bottom: 1px solid #e3e3e3; + cursor: pointer; + box-sizing: border-box; + width: 100%; + transition: background-color 0.15s ease; +} + +.autocomplete-list-item:hover, +.autocomplete-list-item.selected { + background-color: #f2f2f2; +} + +.autocomplete-icon-container { + width: 32px; + height: 32px; + min-width: 32px; + border-radius: 50%; + background-color: #f2f2f2; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.autocomplete-text-container { + display: flex; + flex-direction: column; + align-items: flex-start; + flex: 1 0 0; + min-width: 0; + overflow: hidden; +} + +.autocomplete-item-title { + font-family: "Google Sans Text", "Google Sans", "Roboto", sans-serif; + font-weight: 500; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.1px; + color: #1f1f1f; + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; +} + +.autocomplete-matched { + color: #5e5e5e; + font-weight: 500; +} + +.autocomplete-unmatched { + color: #1f1f1f; + font-weight: 500; +} + +.autocomplete-item-subtitle { + font-family: "Google Sans Text", "Google Sans", "Roboto", sans-serif; + font-weight: 400; + font-size: 12px; + line-height: 16px; + letter-spacing: 0.2px; + color: #5e5e5e; + display: flex; + gap: 4px; + align-items: center; + width: 100%; + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.autocomplete-distance { + color: #5e5e5e; + flex-shrink: 0; +} + +.autocomplete-dot { + color: #1f1f1f; + flex-shrink: 0; +} + +.autocomplete-secondary { + color: #5e5e5e; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.autocomplete-attribution-footer { + height: 36px; + display: flex; + align-items: center; + justify-content: flex-end; + padding: 0 12px; + background-color: #ffffff; + box-sizing: border-box; +} + +.gmp-attribution-text { + font-family: "Roboto", "Google Sans Text", "Google Sans", sans-serif; + font-size: 12px; + line-height: 16px; + color: #70757a; + font-weight: 400; + user-select: none; +} + +/* ========================================================================== + Configuration Sections & Segmented Controls + ========================================================================== */ + +.config-section { + width: 100%; + display: flex; + flex-direction: column; + gap: 12px; + margin: 0; +} + +.section-header { + width: 100%; + display: flex; + flex-direction: column; + gap: 6px; +} + +.section-title { + font-family: "Roboto", sans-serif; + font-weight: 500; + font-size: 16px; + line-height: 24px; + color: #202124; + margin: 0; + white-space: nowrap; +} + +.section-description { + font-family: "Google Sans", sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.2px; + color: #202124; + margin: 0; +} + +.config-bullets { + list-style-type: disc; + padding-left: 21px; + margin: 0; + display: flex; + flex-direction: column; + gap: 0; +} + +.config-bullets li { + font-family: "Google Sans", sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.2px; + color: #202124; + margin: 0; +} + +.segmented-button-group { + display: flex; + width: 100%; + height: 36px; + align-items: center; +} + +.segmented-button { + flex: 1 0 0; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + padding: 8px 24px; + font-family: "Google Sans", sans-serif; + font-weight: 500; + font-size: 14px; + line-height: 20px; + text-align: center; + white-space: nowrap; + cursor: pointer; + border: 1px solid #dadce0; + background-color: #ffffff; + color: #1a73e8; + position: relative; + user-select: none; + transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; +} + +.segmented-button:not(:first-child) { + margin-left: -1px; +} + +.segmented-button:first-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.segmented-button:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.segmented-button.active { + background-color: #1a73e8; + color: #ffffff; + border-color: #1a73e8; + z-index: 1; +} + +.segmented-button:hover:not(.active) { + background-color: #f1f3f4; +} diff --git a/samples/ui-kit-place-details-demo/style.css.metadata.json b/samples/ui-kit-place-details-demo/style.css.metadata.json new file mode 100644 index 000000000..366d8d909 --- /dev/null +++ b/samples/ui-kit-place-details-demo/style.css.metadata.json @@ -0,0 +1,5 @@ +{ + "summary": "CSS stylesheet for Place Details interactive customizer demo including Google, Miami, and Redwood themes.", + "updatedAt": "2026-08-16T17:37:57.547471700Z", + "userFacing": true +} \ No newline at end of file From e3d008d986b1bd69d1590bcacdd49d5905443391 Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 02:12:59 +0000 Subject: [PATCH 05/16] feat(samples): deliberately omit gmp-place-name in advanced place details payload --- samples/ui-kit-advanced-place-details-compact/index.html | 1 - samples/ui-kit-advanced-place-details/index.html | 1 - 2 files changed, 2 deletions(-) diff --git a/samples/ui-kit-advanced-place-details-compact/index.html b/samples/ui-kit-advanced-place-details-compact/index.html index 7e3bfa075..f006e36ee 100644 --- a/samples/ui-kit-advanced-place-details-compact/index.html +++ b/samples/ui-kit-advanced-place-details-compact/index.html @@ -48,7 +48,6 @@ - diff --git a/samples/ui-kit-advanced-place-details/index.html b/samples/ui-kit-advanced-place-details/index.html index f8d6aa905..da2005a5b 100644 --- a/samples/ui-kit-advanced-place-details/index.html +++ b/samples/ui-kit-advanced-place-details/index.html @@ -31,7 +31,6 @@ - From a7a2639eb39a786928dee10fec353f8ebc545782 Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 02:28:22 +0000 Subject: [PATCH 06/16] style(samples): format ui-kit-place-details-demo files to satisfy prettier --- samples/ui-kit-place-details-demo/index.html | 220 ++++-- .../index.html.metadata.json | 8 +- samples/ui-kit-place-details-demo/index.ts | 699 +++++++++-------- .../index.ts.metadata.json | 8 +- .../package.json.metadata.json | 8 +- samples/ui-kit-place-details-demo/style.css | 710 +++++++++--------- .../style.css.metadata.json | 8 +- 7 files changed, 906 insertions(+), 755 deletions(-) diff --git a/samples/ui-kit-place-details-demo/index.html b/samples/ui-kit-place-details-demo/index.html index f972f3bd3..78312c793 100644 --- a/samples/ui-kit-place-details-demo/index.html +++ b/samples/ui-kit-place-details-demo/index.html @@ -5,83 +5,153 @@ SPDX-License-Identifier: Apache-2.0 --> - - - - Place Details Demo — Google Maps Platform Places UI Kit - - - - - - - - - - - - -
-
- + + + + +
+
+
-
- +
+
+ + +
+ +
+
+
+ +
+
+

Content configuration

+
    +
  • + Standard configuration will change over time + and represents Google’s opinion on the best + content for most users. +
  • +
  • + All configuration will change over time and + is intended to easily demonstrate all + content. +
  • +
  • + Custom configuration offers the ability to + choose exactly which content is included. +
  • +
+
+
+ + + +
+
+ +
+
+

Custom brand styling

+

+ The color, typography, spacing, borders, and + corners can all be customized to conform to your + visual design standards. +

+
+
+ + + +
+
+ + +
+ + + + +
+
+
+ diff --git a/samples/ui-kit-place-details-demo/index.html.metadata.json b/samples/ui-kit-place-details-demo/index.html.metadata.json index 490843e19..74069de23 100644 --- a/samples/ui-kit-place-details-demo/index.html.metadata.json +++ b/samples/ui-kit-place-details-demo/index.html.metadata.json @@ -1,5 +1,5 @@ { - "summary": "HTML file for the Place Details interactive customizer demo.", - "updatedAt": "2026-08-16T17:37:49.145049639Z", - "userFacing": true -} \ No newline at end of file + "summary": "HTML file for the Place Details interactive customizer demo.", + "updatedAt": "2026-08-16T17:37:49.145049639Z", + "userFacing": true +} diff --git a/samples/ui-kit-place-details-demo/index.ts b/samples/ui-kit-place-details-demo/index.ts index 244dee962..4008b196d 100644 --- a/samples/ui-kit-place-details-demo/index.ts +++ b/samples/ui-kit-place-details-demo/index.ts @@ -7,12 +7,12 @@ /* [START maps_ui_kit_place_details_customizer] */ interface SuggestionItem { - placeId: string; - mainText: string; - mainMatches: Array<{ startOffset: number; endOffset: number }>; - secondaryText?: string; - distanceText?: string; - fullText: string; + placeId: string; + mainText: string; + mainMatches: Array<{ startOffset: number; endOffset: number }>; + secondaryText?: string; + distanceText?: string; + fullText: string; } let sessionToken: google.maps.places.AutocompleteSessionToken | null = null; @@ -21,360 +21,411 @@ let selectedSuggestionIndex = -1; let debounceTimeout: number | undefined; async function init(): Promise { - // 1. Request required Google Maps libraries - const [, placesLib] = await Promise.all([ - google.maps.importLibrary('maps'), - google.maps.importLibrary('places') as Promise, - google.maps.importLibrary('marker'), - ]); - - const placeDetailsWidget = document.querySelector('#place-details-widget')!; - const placeDetailsRequest = document.querySelector('#place-details-request')!; - const addressInput = document.querySelector('#address')!; - const autocompleteList = document.querySelector('#autocomplete-list')!; - - // -------------------------------------------------------------------------- - // Content Configuration Switching - // -------------------------------------------------------------------------- - const contentConfigButtons = document.querySelectorAll( - '#content-config-buttons .segmented-button' - ); - - contentConfigButtons.forEach((button) => { - button.addEventListener('click', () => { - contentConfigButtons.forEach((btn) => { - btn.classList.remove('active'); - btn.setAttribute('aria-pressed', 'false'); - }); - button.classList.add('active'); - button.setAttribute('aria-pressed', 'true'); - - const mode = button.getAttribute('data-value'); - applyContentConfig(mode); - }); - }); - - function applyContentConfig(mode: string | null) { - // Preserve the place-request child element - const currentPlace = placeDetailsRequest.getAttribute('place') || 'places/ChIJ5abCmkWHhYARH3zgiLVc_Ew'; - placeDetailsWidget.innerHTML = ''; - - const newRequest = document.createElement('gmp-place-details-place-request'); - newRequest.id = 'place-details-request'; - newRequest.setAttribute('place', currentPlace); - placeDetailsWidget.appendChild(newRequest); - - if (mode === 'standard') { - const standardContent = document.createElement('gmp-place-standard-content'); - placeDetailsWidget.appendChild(standardContent); - } else if (mode === 'all') { - const allContent = document.createElement('gmp-place-all-content'); - placeDetailsWidget.appendChild(allContent); - } else if (mode === 'custom') { - const customConfig = document.createElement('gmp-place-content-config'); - - const elementsToInclude = [ - { tag: 'gmp-place-media', attrs: { 'lightbox-preferred': '' } }, - { tag: 'gmp-place-summary' }, - { tag: 'gmp-place-address' }, - { tag: 'gmp-place-rating' }, - { tag: 'gmp-place-open-now-status' }, - { tag: 'gmp-place-price' }, - { tag: 'gmp-place-type' }, - { tag: 'gmp-place-website' }, - { tag: 'gmp-place-phone-number' }, - { tag: 'gmp-place-plus-code' }, - { tag: 'gmp-place-accessible-entrance-icon' }, - ]; - - elementsToInclude.forEach(({ tag, attrs }) => { - const el = document.createElement(tag); - if (attrs) { - Object.entries(attrs).forEach(([key, val]) => el.setAttribute(key, val)); - } - customConfig.appendChild(el); - }); + // 1. Request required Google Maps libraries + const [, placesLib] = await Promise.all([ + google.maps.importLibrary('maps'), + google.maps.importLibrary('places') as Promise< + typeof google.maps.places + >, + google.maps.importLibrary('marker'), + ]); + + const placeDetailsWidget = document.querySelector( + '#place-details-widget' + )!; + const placeDetailsRequest = document.querySelector( + '#place-details-request' + )!; + const addressInput = document.querySelector('#address')!; + const autocompleteList = + document.querySelector('#autocomplete-list')!; + + // -------------------------------------------------------------------------- + // Content Configuration Switching + // -------------------------------------------------------------------------- + const contentConfigButtons = document.querySelectorAll( + '#content-config-buttons .segmented-button' + ); + + contentConfigButtons.forEach((button) => { + button.addEventListener('click', () => { + contentConfigButtons.forEach((btn) => { + btn.classList.remove('active'); + btn.setAttribute('aria-pressed', 'false'); + }); + button.classList.add('active'); + button.setAttribute('aria-pressed', 'true'); - placeDetailsWidget.appendChild(customConfig); - } - } - - // -------------------------------------------------------------------------- - // Theme Switching - // -------------------------------------------------------------------------- - const themeButtons = document.querySelectorAll( - '#theme-buttons .segmented-button' - ); - - themeButtons.forEach((button) => { - button.addEventListener('click', () => { - themeButtons.forEach((btn) => { - btn.classList.remove('active'); - btn.setAttribute('aria-pressed', 'false'); - }); - button.classList.add('active'); - button.setAttribute('aria-pressed', 'true'); - - const theme = button.getAttribute('data-value'); - placeDetailsWidget.classList.remove('theme-google', 'theme-miami', 'theme-redwood'); - - if (theme === 'example1') { - placeDetailsWidget.classList.add('theme-miami'); - } else if (theme === 'example2') { - placeDetailsWidget.classList.add('theme-redwood'); - } else { - placeDetailsWidget.classList.add('theme-google'); - } + const mode = button.getAttribute('data-value'); + applyContentConfig(mode); + }); }); - }); - - // -------------------------------------------------------------------------- - // Autocomplete Search Logic - // -------------------------------------------------------------------------- - function getSessionToken(): google.maps.places.AutocompleteSessionToken { - if (!sessionToken && placesLib.AutocompleteSessionToken) { - sessionToken = new placesLib.AutocompleteSessionToken(); - } - return sessionToken!; - } - async function fetchSuggestions(query: string): Promise { - if (!query.trim()) { - closeDropdown(); - return; - } + function applyContentConfig(mode: string | null) { + // Preserve the place-request child element + const currentPlace = + placeDetailsRequest.getAttribute('place') || + 'places/ChIJ5abCmkWHhYARH3zgiLVc_Ew'; + placeDetailsWidget.innerHTML = ''; + + const newRequest = document.createElement( + 'gmp-place-details-place-request' + ); + newRequest.id = 'place-details-request'; + newRequest.setAttribute('place', currentPlace); + placeDetailsWidget.appendChild(newRequest); + + if (mode === 'standard') { + const standardContent = document.createElement( + 'gmp-place-standard-content' + ); + placeDetailsWidget.appendChild(standardContent); + } else if (mode === 'all') { + const allContent = document.createElement('gmp-place-all-content'); + placeDetailsWidget.appendChild(allContent); + } else if (mode === 'custom') { + const customConfig = document.createElement( + 'gmp-place-content-config' + ); + + const elementsToInclude = [ + { tag: 'gmp-place-media', attrs: { 'lightbox-preferred': '' } }, + { tag: 'gmp-place-summary' }, + { tag: 'gmp-place-address' }, + { tag: 'gmp-place-rating' }, + { tag: 'gmp-place-open-now-status' }, + { tag: 'gmp-place-price' }, + { tag: 'gmp-place-type' }, + { tag: 'gmp-place-website' }, + { tag: 'gmp-place-phone-number' }, + { tag: 'gmp-place-plus-code' }, + { tag: 'gmp-place-accessible-entrance-icon' }, + ]; + + elementsToInclude.forEach(({ tag, attrs }) => { + const el = document.createElement(tag); + if (attrs) { + Object.entries(attrs).forEach(([key, val]) => + el.setAttribute(key, val) + ); + } + customConfig.appendChild(el); + }); - try { - if (placesLib.AutocompleteSuggestion?.fetchAutocompleteSuggestions) { - const response = await placesLib.AutocompleteSuggestion.fetchAutocompleteSuggestions({ - input: query, - sessionToken: getSessionToken(), - }); + placeDetailsWidget.appendChild(customConfig); + } + } - if (response?.suggestions && response.suggestions.length > 0) { - currentSuggestions = response.suggestions - .filter((s) => s.placePrediction) - .map((s) => { - const pred = s.placePrediction!; - const mainText = - typeof pred.mainText === 'string' - ? pred.mainText - : pred.mainText?.text ?? pred.text?.text ?? ''; - const secondaryText = - typeof pred.secondaryText === 'string' - ? pred.secondaryText - : pred.secondaryText?.text ?? ''; - const fullText = - typeof pred.text === 'string' ? pred.text : pred.text?.text ?? mainText; - - let distanceText: string | undefined; - if (pred.distanceMeters && pred.distanceMeters > 0) { - distanceText = `${(pred.distanceMeters / 1609.34).toFixed(1)} mi`; - } - - const mainMatches = (pred.mainText?.matches || []).map((m) => ({ - startOffset: m.startOffset, - endOffset: m.endOffset, - })); - - return { - placeId: pred.placeId, - mainText, - mainMatches, - secondaryText, - distanceText, - fullText, - }; + // -------------------------------------------------------------------------- + // Theme Switching + // -------------------------------------------------------------------------- + const themeButtons = document.querySelectorAll( + '#theme-buttons .segmented-button' + ); + + themeButtons.forEach((button) => { + button.addEventListener('click', () => { + themeButtons.forEach((btn) => { + btn.classList.remove('active'); + btn.setAttribute('aria-pressed', 'false'); }); + button.classList.add('active'); + button.setAttribute('aria-pressed', 'true'); + + const theme = button.getAttribute('data-value'); + placeDetailsWidget.classList.remove( + 'theme-google', + 'theme-miami', + 'theme-redwood' + ); + + if (theme === 'example1') { + placeDetailsWidget.classList.add('theme-miami'); + } else if (theme === 'example2') { + placeDetailsWidget.classList.add('theme-redwood'); + } else { + placeDetailsWidget.classList.add('theme-google'); + } + }); + }); - renderDropdown(); - return; + // -------------------------------------------------------------------------- + // Autocomplete Search Logic + // -------------------------------------------------------------------------- + function getSessionToken(): google.maps.places.AutocompleteSessionToken { + if (!sessionToken && placesLib.AutocompleteSessionToken) { + sessionToken = new placesLib.AutocompleteSessionToken(); } - } - } catch (err) { - console.warn('Error fetching autocomplete suggestions:', err); + return sessionToken!; } - closeDropdown(); - } + async function fetchSuggestions(query: string): Promise { + if (!query.trim()) { + closeDropdown(); + return; + } - function renderDropdown(): void { - if (currentSuggestions.length === 0) { - closeDropdown(); - return; + try { + if ( + placesLib.AutocompleteSuggestion?.fetchAutocompleteSuggestions + ) { + const response = + await placesLib.AutocompleteSuggestion.fetchAutocompleteSuggestions( + { + input: query, + sessionToken: getSessionToken(), + } + ); + + if (response?.suggestions && response.suggestions.length > 0) { + currentSuggestions = response.suggestions + .filter((s) => s.placePrediction) + .map((s) => { + const pred = s.placePrediction!; + const mainText = + typeof pred.mainText === 'string' + ? pred.mainText + : (pred.mainText?.text ?? + pred.text?.text ?? + ''); + const secondaryText = + typeof pred.secondaryText === 'string' + ? pred.secondaryText + : (pred.secondaryText?.text ?? ''); + const fullText = + typeof pred.text === 'string' + ? pred.text + : (pred.text?.text ?? mainText); + + let distanceText: string | undefined; + if ( + pred.distanceMeters && + pred.distanceMeters > 0 + ) { + distanceText = `${(pred.distanceMeters / 1609.34).toFixed(1)} mi`; + } + + const mainMatches = ( + pred.mainText?.matches || [] + ).map((m) => ({ + startOffset: m.startOffset, + endOffset: m.endOffset, + })); + + return { + placeId: pred.placeId, + mainText, + mainMatches, + secondaryText, + distanceText, + fullText, + }; + }); + + renderDropdown(); + return; + } + } + } catch (err) { + console.warn('Error fetching autocomplete suggestions:', err); + } + + closeDropdown(); } - autocompleteList.innerHTML = ''; - autocompleteList.removeAttribute('hidden'); - selectedSuggestionIndex = -1; + function renderDropdown(): void { + if (currentSuggestions.length === 0) { + closeDropdown(); + return; + } + + autocompleteList.innerHTML = ''; + autocompleteList.removeAttribute('hidden'); + selectedSuggestionIndex = -1; - currentSuggestions.forEach((item, index) => { - const itemEl = document.createElement('div'); - itemEl.className = 'autocomplete-list-item'; - itemEl.setAttribute('data-index', String(index)); + currentSuggestions.forEach((item, index) => { + const itemEl = document.createElement('div'); + itemEl.className = 'autocomplete-list-item'; + itemEl.setAttribute('data-index', String(index)); - // Pin Icon Container - const iconContainer = document.createElement('div'); - iconContainer.className = 'autocomplete-icon-container'; - iconContainer.innerHTML = ` + // Pin Icon Container + const iconContainer = document.createElement('div'); + iconContainer.className = 'autocomplete-icon-container'; + iconContainer.innerHTML = ` `; - itemEl.appendChild(iconContainer); - - // Text Container - const textContainer = document.createElement('div'); - textContainer.className = 'autocomplete-text-container'; - - const titleEl = document.createElement('p'); - titleEl.className = 'autocomplete-item-title'; - titleEl.innerHTML = buildHighlightedText(item.mainText, item.mainMatches); - textContainer.appendChild(titleEl); - - if (item.secondaryText || item.distanceText) { - const subtitleEl = document.createElement('div'); - subtitleEl.className = 'autocomplete-item-subtitle'; - - if (item.distanceText) { - const distSpan = document.createElement('span'); - distSpan.className = 'autocomplete-distance'; - distSpan.textContent = item.distanceText; - subtitleEl.appendChild(distSpan); - - const dotSpan = document.createElement('span'); - dotSpan.className = 'autocomplete-dot'; - dotSpan.textContent = '·'; - subtitleEl.appendChild(dotSpan); - } + itemEl.appendChild(iconContainer); + + // Text Container + const textContainer = document.createElement('div'); + textContainer.className = 'autocomplete-text-container'; + + const titleEl = document.createElement('p'); + titleEl.className = 'autocomplete-item-title'; + titleEl.innerHTML = buildHighlightedText( + item.mainText, + item.mainMatches + ); + textContainer.appendChild(titleEl); + + if (item.secondaryText || item.distanceText) { + const subtitleEl = document.createElement('div'); + subtitleEl.className = 'autocomplete-item-subtitle'; + + if (item.distanceText) { + const distSpan = document.createElement('span'); + distSpan.className = 'autocomplete-distance'; + distSpan.textContent = item.distanceText; + subtitleEl.appendChild(distSpan); + + const dotSpan = document.createElement('span'); + dotSpan.className = 'autocomplete-dot'; + dotSpan.textContent = '·'; + subtitleEl.appendChild(dotSpan); + } + + if (item.secondaryText) { + const secSpan = document.createElement('span'); + secSpan.className = 'autocomplete-secondary'; + secSpan.textContent = item.secondaryText; + subtitleEl.appendChild(secSpan); + } + + textContainer.appendChild(subtitleEl); + } + + itemEl.appendChild(textContainer); + + itemEl.addEventListener('click', () => selectSuggestion(item)); + autocompleteList.appendChild(itemEl); + }); - if (item.secondaryText) { - const secSpan = document.createElement('span'); - secSpan.className = 'autocomplete-secondary'; - secSpan.textContent = item.secondaryText; - subtitleEl.appendChild(secSpan); + // Attribution Footer + const footer = document.createElement('div'); + footer.className = 'autocomplete-attribution-footer'; + footer.innerHTML = + 'Google Maps'; + autocompleteList.appendChild(footer); + } + + function buildHighlightedText( + text: string, + matches: Array<{ startOffset: number; endOffset: number }> + ): string { + if (!matches || matches.length === 0) { + return `${escapeHtml(text)}`; } - textContainer.appendChild(subtitleEl); - } + let html = ''; + let lastIndex = 0; - itemEl.appendChild(textContainer); + matches.forEach(({ startOffset, endOffset }) => { + if (startOffset > lastIndex) { + html += `${escapeHtml(text.slice(lastIndex, startOffset))}`; + } + html += `${escapeHtml(text.slice(startOffset, endOffset))}`; + lastIndex = endOffset; + }); - itemEl.addEventListener('click', () => selectSuggestion(item)); - autocompleteList.appendChild(itemEl); - }); + if (lastIndex < text.length) { + html += `${escapeHtml(text.slice(lastIndex))}`; + } - // Attribution Footer - const footer = document.createElement('div'); - footer.className = 'autocomplete-attribution-footer'; - footer.innerHTML = 'Google Maps'; - autocompleteList.appendChild(footer); - } - - function buildHighlightedText( - text: string, - matches: Array<{ startOffset: number; endOffset: number }> - ): string { - if (!matches || matches.length === 0) { - return `${escapeHtml(text)}`; + return html; } - let html = ''; - let lastIndex = 0; + function escapeHtml(str: string): string { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + } - matches.forEach(({ startOffset, endOffset }) => { - if (startOffset > lastIndex) { - html += `${escapeHtml(text.slice(lastIndex, startOffset))}`; - } - html += `${escapeHtml(text.slice(startOffset, endOffset))}`; - lastIndex = endOffset; - }); + function selectSuggestion(item: SuggestionItem): void { + addressInput.value = ''; + addressInput.placeholder = item.mainText || item.fullText; + closeDropdown(); + + // Update Place Request + const activeRequest = document.querySelector( + '#place-details-request' + ); + if (activeRequest) { + activeRequest.setAttribute('place', `places/${item.placeId}`); + } - if (lastIndex < text.length) { - html += `${escapeHtml(text.slice(lastIndex))}`; + // Reset session token after selection + sessionToken = null; } - return html; - } - - function escapeHtml(str: string): string { - return str - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - - function selectSuggestion(item: SuggestionItem): void { - addressInput.value = ''; - addressInput.placeholder = item.mainText || item.fullText; - closeDropdown(); - - // Update Place Request - const activeRequest = document.querySelector('#place-details-request'); - if (activeRequest) { - activeRequest.setAttribute('place', `places/${item.placeId}`); + function closeDropdown(): void { + autocompleteList.setAttribute('hidden', ''); + autocompleteList.innerHTML = ''; + currentSuggestions = []; + selectedSuggestionIndex = -1; } - // Reset session token after selection - sessionToken = null; - } - - function closeDropdown(): void { - autocompleteList.setAttribute('hidden', ''); - autocompleteList.innerHTML = ''; - currentSuggestions = []; - selectedSuggestionIndex = -1; - } - - addressInput.addEventListener('input', () => { - window.clearTimeout(debounceTimeout); - debounceTimeout = window.setTimeout(() => { - fetchSuggestions(addressInput.value); - }, 150); - }); - - addressInput.addEventListener('keydown', (e: KeyboardEvent) => { - if (currentSuggestions.length === 0) return; - - const items = autocompleteList.querySelectorAll('.autocomplete-list-item'); - - if (e.key === 'ArrowDown') { - e.preventDefault(); - selectedSuggestionIndex = (selectedSuggestionIndex + 1) % items.length; - updateSelection(items); - } else if (e.key === 'ArrowUp') { - e.preventDefault(); - selectedSuggestionIndex = (selectedSuggestionIndex - 1 + items.length) % items.length; - updateSelection(items); - } else if (e.key === 'Enter') { - e.preventDefault(); - if (selectedSuggestionIndex >= 0 && selectedSuggestionIndex < currentSuggestions.length) { - selectSuggestion(currentSuggestions[selectedSuggestionIndex]); - } else if (currentSuggestions.length > 0) { - selectSuggestion(currentSuggestions[0]); - } - } else if (e.key === 'Escape') { - closeDropdown(); - } - }); - - function updateSelection(items: NodeListOf): void { - items.forEach((item, index) => { - if (index === selectedSuggestionIndex) { - item.classList.add('selected'); - item.scrollIntoView({ block: 'nearest' }); - } else { - item.classList.remove('selected'); - } + addressInput.addEventListener('input', () => { + window.clearTimeout(debounceTimeout); + debounceTimeout = window.setTimeout(() => { + fetchSuggestions(addressInput.value); + }, 150); + }); + + addressInput.addEventListener('keydown', (e: KeyboardEvent) => { + if (currentSuggestions.length === 0) return; + + const items = autocompleteList.querySelectorAll( + '.autocomplete-list-item' + ); + + if (e.key === 'ArrowDown') { + e.preventDefault(); + selectedSuggestionIndex = + (selectedSuggestionIndex + 1) % items.length; + updateSelection(items); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + selectedSuggestionIndex = + (selectedSuggestionIndex - 1 + items.length) % items.length; + updateSelection(items); + } else if (e.key === 'Enter') { + e.preventDefault(); + if ( + selectedSuggestionIndex >= 0 && + selectedSuggestionIndex < currentSuggestions.length + ) { + selectSuggestion(currentSuggestions[selectedSuggestionIndex]); + } else if (currentSuggestions.length > 0) { + selectSuggestion(currentSuggestions[0]); + } + } else if (e.key === 'Escape') { + closeDropdown(); + } }); - } - document.addEventListener('click', (e) => { - if (!autocompleteList.contains(e.target as Node) && e.target !== addressInput) { - closeDropdown(); + function updateSelection(items: NodeListOf): void { + items.forEach((item, index) => { + if (index === selectedSuggestionIndex) { + item.classList.add('selected'); + item.scrollIntoView({ block: 'nearest' }); + } else { + item.classList.remove('selected'); + } + }); } - }); + + document.addEventListener('click', (e) => { + if ( + !autocompleteList.contains(e.target as Node) && + e.target !== addressInput + ) { + closeDropdown(); + } + }); } void init(); diff --git a/samples/ui-kit-place-details-demo/index.ts.metadata.json b/samples/ui-kit-place-details-demo/index.ts.metadata.json index 659e02dc0..ca5acb970 100644 --- a/samples/ui-kit-place-details-demo/index.ts.metadata.json +++ b/samples/ui-kit-place-details-demo/index.ts.metadata.json @@ -1,5 +1,5 @@ { - "summary": "TypeScript controller for Place Details interactive customizer demo.", - "updatedAt": "2026-08-16T17:38:05.012911974Z", - "userFacing": true -} \ No newline at end of file + "summary": "TypeScript controller for Place Details interactive customizer demo.", + "updatedAt": "2026-08-16T17:38:05.012911974Z", + "userFacing": true +} diff --git a/samples/ui-kit-place-details-demo/package.json.metadata.json b/samples/ui-kit-place-details-demo/package.json.metadata.json index da38d377f..8f3e6fb0e 100644 --- a/samples/ui-kit-place-details-demo/package.json.metadata.json +++ b/samples/ui-kit-place-details-demo/package.json.metadata.json @@ -1,5 +1,5 @@ { - "summary": "package.json configuration for Place Details interactive customizer demo.", - "updatedAt": "2026-08-16T17:38:07.654115810Z", - "userFacing": true -} \ No newline at end of file + "summary": "package.json configuration for Place Details interactive customizer demo.", + "updatedAt": "2026-08-16T17:38:07.654115810Z", + "userFacing": true +} diff --git a/samples/ui-kit-place-details-demo/style.css b/samples/ui-kit-place-details-demo/style.css index ed107b995..3398fa357 100644 --- a/samples/ui-kit-place-details-demo/style.css +++ b/samples/ui-kit-place-details-demo/style.css @@ -9,92 +9,106 @@ ========================================================================== */ gmp-place-details { - box-sizing: border-box; - color-scheme: light dark; - display: block; - width: 400px; - height: 700px; - max-height: 700px; - flex-shrink: 0; + box-sizing: border-box; + color-scheme: light dark; + display: block; + width: 400px; + height: 700px; + max-height: 700px; + flex-shrink: 0; } @media (max-width: 880px) { - gmp-place-details { - width: 100%; - max-width: 400px; - } + gmp-place-details { + width: 100%; + max-width: 400px; + } } gmp-place-details.theme-google { - box-sizing: border-box; + box-sizing: border-box; } /* Miami Theme (Teal / Bold Accent / Pill Buttons) */ gmp-place-details.theme-miami { - --gmp-mat-color-surface: light-dark(#fdf8f5, #1a2e3b); - --gmp-mat-color-on-surface: light-dark(#2f3f4f, #e0ebf5); - --gmp-mat-color-on-surface-variant: light-dark(#6a7a8a, #aabbdd); - --gmp-mat-color-primary: light-dark(#0097a7, #80deea); - --gmp-mat-color-info: light-dark(#0097a7, #80deea); - --gmp-mat-color-secondary-container: light-dark(#ffebee, #3b1b1f); - --gmp-mat-color-on-secondary-container: light-dark(#d81b60, #ffcdd2); - --gmp-mat-color-outline-decorative: light-dark(#e0e0e0, #4f5f6f); - --gmp-mat-color-negative: light-dark(#e53935, #ffcdd2); - --gmp-mat-color-positive: light-dark(#4caf50, #a5d6a7); - --gmp-star-rating-color: light-dark(#d81b60, #ffcdd2); - --gmp-mat-font-family: "Inter", "Roboto", sans-serif; - --gmp-mat-font-headline-medium: normal 600 1.25em / 1.3 var(--gmp-mat-font-family, "Inter", sans-serif); - --gmp-mat-font-title-small: normal 500 1em / 1.375 var(--gmp-mat-font-family, "Inter", sans-serif); - --gmp-mat-font-body-medium: normal 400 0.875em / calc(20 / 14) var(--gmp-mat-font-family, "Roboto", sans-serif); - --gmp-mat-font-body-small: normal 400 0.75em / calc(16 / 12) var(--gmp-mat-font-family, "Roboto", sans-serif); - --gmp-mat-font-label-large: normal 600 0.875em / calc(20 / 14) var(--gmp-mat-font-family, "Roboto", sans-serif); - --gmp-mat-spacing-extra-small: 4px; - --gmp-mat-spacing-small: 8px; - --gmp-mat-spacing-medium: 12px; - --gmp-mat-spacing-large: 16px; - --gmp-mat-spacing-extra-large: 20px; - --gmp-mat-spacing-two-extra-large: 24px; - --gmp-mat-border-radius: 10px; - --gmp-button-border-radius: 9999px; - --gmp-thumbnail-border-radius: 6px; - --gmp-collage-border-radius-outer: 10px; - --gmp-card-border-radius: 10px; - --gmp-dialog-border-radius: 18px; - box-sizing: border-box; + --gmp-mat-color-surface: light-dark(#fdf8f5, #1a2e3b); + --gmp-mat-color-on-surface: light-dark(#2f3f4f, #e0ebf5); + --gmp-mat-color-on-surface-variant: light-dark(#6a7a8a, #aabbdd); + --gmp-mat-color-primary: light-dark(#0097a7, #80deea); + --gmp-mat-color-info: light-dark(#0097a7, #80deea); + --gmp-mat-color-secondary-container: light-dark(#ffebee, #3b1b1f); + --gmp-mat-color-on-secondary-container: light-dark(#d81b60, #ffcdd2); + --gmp-mat-color-outline-decorative: light-dark(#e0e0e0, #4f5f6f); + --gmp-mat-color-negative: light-dark(#e53935, #ffcdd2); + --gmp-mat-color-positive: light-dark(#4caf50, #a5d6a7); + --gmp-star-rating-color: light-dark(#d81b60, #ffcdd2); + --gmp-mat-font-family: 'Inter', 'Roboto', sans-serif; + --gmp-mat-font-headline-medium: normal 600 1.25em / 1.3 + var(--gmp-mat-font-family, 'Inter', sans-serif); + --gmp-mat-font-title-small: normal 500 1em / 1.375 + var(--gmp-mat-font-family, 'Inter', sans-serif); + --gmp-mat-font-body-medium: normal 400 0.875em / calc(20 / 14) + var(--gmp-mat-font-family, 'Roboto', sans-serif); + --gmp-mat-font-body-small: normal 400 0.75em / calc(16 / 12) + var(--gmp-mat-font-family, 'Roboto', sans-serif); + --gmp-mat-font-label-large: normal 600 0.875em / calc(20 / 14) + var(--gmp-mat-font-family, 'Roboto', sans-serif); + --gmp-mat-spacing-extra-small: 4px; + --gmp-mat-spacing-small: 8px; + --gmp-mat-spacing-medium: 12px; + --gmp-mat-spacing-large: 16px; + --gmp-mat-spacing-extra-large: 20px; + --gmp-mat-spacing-two-extra-large: 24px; + --gmp-mat-border-radius: 10px; + --gmp-button-border-radius: 9999px; + --gmp-thumbnail-border-radius: 6px; + --gmp-collage-border-radius-outer: 10px; + --gmp-card-border-radius: 10px; + --gmp-dialog-border-radius: 18px; + box-sizing: border-box; } /* Redwood Theme (Warm Earthy / Serif Headings) */ gmp-place-details.theme-redwood { - --gmp-theme-font-family-headings-labels: "Domine", serif; - --gmp-theme-font-family-content: "Nunito Sans", sans-serif; - --gmp-mat-color-surface: light-dark(#f5f0e8, #3a2e29); - --gmp-mat-color-on-surface: light-dark(#5d4037, #e8e0d8); - --gmp-mat-color-on-surface-variant: light-dark(#795548, #b0a191); - --gmp-mat-color-surface-container: light-dark(#ebe5db, #2f2521); - --gmp-mat-color-primary: light-dark(#386641, #7cb342); - --gmp-mat-color-secondary-container: light-dark(#6a4c3b, #558b2f); - --gmp-mat-color-on-secondary-container: light-dark(#ffffff, #ffffff); - --gmp-mat-color-outline-decorative: light-dark(#c0b5a8, #5c4a42); - --gmp-mat-color-info: light-dark(#386641, #7cb342); - --gmp-mat-color-positive: light-dark(#4caf50, #8bc34a); - --gmp-mat-color-negative: light-dark(#b85c5c, #e57373); - --gmp-mat-color-disabled-surface: light-dark(#e0d8cd, #4e3f3a); - --gmp-mat-color-neutral-container: light-dark(#eae0d5, #4a3c35); - --gmp-mat-color-on-neutral-container: light-dark(#5d4037, #b0a191); - --gmp-mat-color-positive-container: light-dark(#d5e8d4, #33691e); - --gmp-mat-color-on-positive-container: light-dark(#2e5336, #c5e1a5); - --gmp-star-rating-color: light-dark(#bc6c25, #dda15e); - --gmp-mat-font-family: var(--gmp-theme-font-family-content); - --gmp-mat-font-body-medium: normal 400 0.9375em / calc(22 / 15) var(--gmp-mat-font-family); - --gmp-mat-font-body-small: normal 400 0.8125em / calc(18 / 13) var(--gmp-mat-font-family); - --gmp-mat-font-headline-large: normal 500 1.75em / calc(32 / 28) var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-headline-medium: normal 500 1.375em / calc(28 / 22) var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-title-small: normal 500 1.125em / calc(24 / 18) var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-display-small: normal 400 1.625em / calc(30 / 26) var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-label-large: normal 500 0.875em / calc(20 / 14) var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-label-medium: normal 500 0.75em / calc(16 / 12) var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-label-small: normal 500 0.6875em / calc(12 / 11) var(--gmp-theme-font-family-headings-labels); - box-sizing: border-box; + --gmp-theme-font-family-headings-labels: 'Domine', serif; + --gmp-theme-font-family-content: 'Nunito Sans', sans-serif; + --gmp-mat-color-surface: light-dark(#f5f0e8, #3a2e29); + --gmp-mat-color-on-surface: light-dark(#5d4037, #e8e0d8); + --gmp-mat-color-on-surface-variant: light-dark(#795548, #b0a191); + --gmp-mat-color-surface-container: light-dark(#ebe5db, #2f2521); + --gmp-mat-color-primary: light-dark(#386641, #7cb342); + --gmp-mat-color-secondary-container: light-dark(#6a4c3b, #558b2f); + --gmp-mat-color-on-secondary-container: light-dark(#ffffff, #ffffff); + --gmp-mat-color-outline-decorative: light-dark(#c0b5a8, #5c4a42); + --gmp-mat-color-info: light-dark(#386641, #7cb342); + --gmp-mat-color-positive: light-dark(#4caf50, #8bc34a); + --gmp-mat-color-negative: light-dark(#b85c5c, #e57373); + --gmp-mat-color-disabled-surface: light-dark(#e0d8cd, #4e3f3a); + --gmp-mat-color-neutral-container: light-dark(#eae0d5, #4a3c35); + --gmp-mat-color-on-neutral-container: light-dark(#5d4037, #b0a191); + --gmp-mat-color-positive-container: light-dark(#d5e8d4, #33691e); + --gmp-mat-color-on-positive-container: light-dark(#2e5336, #c5e1a5); + --gmp-star-rating-color: light-dark(#bc6c25, #dda15e); + --gmp-mat-font-family: var(--gmp-theme-font-family-content); + --gmp-mat-font-body-medium: normal 400 0.9375em / calc(22 / 15) + var(--gmp-mat-font-family); + --gmp-mat-font-body-small: normal 400 0.8125em / calc(18 / 13) + var(--gmp-mat-font-family); + --gmp-mat-font-headline-large: normal 500 1.75em / calc(32 / 28) + var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-headline-medium: normal 500 1.375em / calc(28 / 22) + var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-title-small: normal 500 1.125em / calc(24 / 18) + var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-display-small: normal 400 1.625em / calc(30 / 26) + var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-label-large: normal 500 0.875em / calc(20 / 14) + var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-label-medium: normal 500 0.75em / calc(16 / 12) + var(--gmp-theme-font-family-headings-labels); + --gmp-mat-font-label-small: normal 500 0.6875em / calc(12 / 11) + var(--gmp-theme-font-family-headings-labels); + box-sizing: border-box; } /* ========================================================================== @@ -104,105 +118,114 @@ gmp-place-details.theme-redwood { *, *::before, *::after { - box-sizing: border-box; - margin: 0; - padding: 0; + box-sizing: border-box; + margin: 0; + padding: 0; } html, body { - min-height: 100vh; - background-color: #f8f9fa; - font-family: "Google Sans", "Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - color: #202124; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + min-height: 100vh; + background-color: #f8f9fa; + font-family: + 'Google Sans', + 'Roboto', + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + sans-serif; + color: #202124; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } .page-wrapper { - min-height: 100vh; - display: flex; - align-items: center; - justify-content: center; - padding: 24px 16px; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 24px 16px; } .demo-frame { - width: 839px; - min-height: 750px; - background-color: #ffffff; - border-radius: 16px; - box-shadow: 0 1px 3px rgba(60, 64, 67, 0.12), 0 4px 8px rgba(60, 64, 67, 0.08); - border: 1px solid #dadce0; - padding: 25px; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: flex-start; - gap: 50px; + width: 839px; + min-height: 750px; + background-color: #ffffff; + border-radius: 16px; + box-shadow: + 0 1px 3px rgba(60, 64, 67, 0.12), + 0 4px 8px rgba(60, 64, 67, 0.08); + border: 1px solid #dadce0; + padding: 25px; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + gap: 50px; } @media (max-width: 880px) { - .demo-frame { - width: 100%; - max-width: 839px; - flex-direction: column; - align-items: center; - gap: 32px; - padding: 20px; - } + .demo-frame { + width: 100%; + max-width: 839px; + flex-direction: column; + align-items: center; + gap: 32px; + padding: 20px; + } } .left-column { - width: 339px; - flex-shrink: 0; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 20px; + width: 339px; + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 20px; } @media (max-width: 880px) { - .left-column { - width: 100%; - max-width: 400px; - } + .left-column { + width: 100%; + max-width: 400px; + } } .demo-header { - width: 100%; - display: flex; - flex-direction: column; - gap: 8px; - align-items: flex-start; + width: 100%; + display: flex; + flex-direction: column; + gap: 8px; + align-items: flex-start; } .demo-title-container { - width: 100%; - display: flex; - flex-direction: column; - align-items: flex-start; + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; } .demo-title { - font-family: "Roboto", sans-serif; - font-weight: 300; - font-size: 24px; - line-height: 32px; - color: #202124; - margin: 0; - white-space: nowrap; + font-family: 'Roboto', sans-serif; + font-weight: 300; + font-size: 24px; + line-height: 32px; + color: #202124; + margin: 0; + white-space: nowrap; } .component-description { - font-family: "Google Sans", "Roboto", sans-serif; - font-weight: 400; - font-size: 16px; - line-height: 24px; - color: #202124; - margin: 0; - width: 100%; - white-space: pre-wrap; + font-family: 'Google Sans', 'Roboto', sans-serif; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #202124; + margin: 0; + width: 100%; + white-space: pre-wrap; } /* ========================================================================== @@ -210,189 +233,193 @@ body { ========================================================================== */ .address-input { - width: 100%; - display: flex; - flex-direction: column; - margin: 0; + width: 100%; + display: flex; + flex-direction: column; + margin: 0; } .form-group { - width: 100%; - display: flex; - flex-direction: column; - gap: 4px; - position: relative; + width: 100%; + display: flex; + flex-direction: column; + gap: 4px; + position: relative; } .form-group label { - font-family: "Roboto", "Google Sans", sans-serif; - font-weight: 400; - font-size: 12px; - line-height: 16px; - color: #606368; - display: block; - margin: 0; - cursor: pointer; -} - -.form-group input[type="text"] { - width: 100%; - height: 40px; - background: #ffffff; - border: 1px solid #dadce0; - border-radius: 4px; - padding: 8px 12px; - font-family: "Roboto", sans-serif; - font-weight: 400; - font-size: 16px; - line-height: 24px; - color: #202124; - outline: none; - box-sizing: border-box; - transition: border-color 0.2s ease, box-shadow 0.2s ease; -} - -.form-group input[type="text"]:focus { - border-color: #1a73e8; - border-bottom: 2px solid #1a73e8; - padding-bottom: 7px; + font-family: 'Roboto', 'Google Sans', sans-serif; + font-weight: 400; + font-size: 12px; + line-height: 16px; + color: #606368; + display: block; + margin: 0; + cursor: pointer; +} + +.form-group input[type='text'] { + width: 100%; + height: 40px; + background: #ffffff; + border: 1px solid #dadce0; + border-radius: 4px; + padding: 8px 12px; + font-family: 'Roboto', sans-serif; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #202124; + outline: none; + box-sizing: border-box; + transition: + border-color 0.2s ease, + box-shadow 0.2s ease; +} + +.form-group input[type='text']:focus { + border-color: #1a73e8; + border-bottom: 2px solid #1a73e8; + padding-bottom: 7px; } #autocomplete-list-wrapper { - position: relative; - width: 100%; + position: relative; + width: 100%; } .autocomplete-dropdown { - position: absolute; - top: 100%; - left: 0; - margin-top: 4px; - width: 100%; - background-color: #ffffff; - border-radius: 8px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 6px 2px rgba(0, 0, 0, 0.15); - overflow: hidden; - z-index: 10000; - box-sizing: border-box; - display: flex; - flex-direction: column; + position: absolute; + top: 100%; + left: 0; + margin-top: 4px; + width: 100%; + background-color: #ffffff; + border-radius: 8px; + box-shadow: + 0 1px 2px rgba(0, 0, 0, 0.3), + 0 2px 6px 2px rgba(0, 0, 0, 0.15); + overflow: hidden; + z-index: 10000; + box-sizing: border-box; + display: flex; + flex-direction: column; } .autocomplete-list-item { - display: flex; - gap: 12px; - align-items: center; - padding: 8px 12px; - background-color: #ffffff; - border-bottom: 1px solid #e3e3e3; - cursor: pointer; - box-sizing: border-box; - width: 100%; - transition: background-color 0.15s ease; + display: flex; + gap: 12px; + align-items: center; + padding: 8px 12px; + background-color: #ffffff; + border-bottom: 1px solid #e3e3e3; + cursor: pointer; + box-sizing: border-box; + width: 100%; + transition: background-color 0.15s ease; } .autocomplete-list-item:hover, .autocomplete-list-item.selected { - background-color: #f2f2f2; + background-color: #f2f2f2; } .autocomplete-icon-container { - width: 32px; - height: 32px; - min-width: 32px; - border-radius: 50%; - background-color: #f2f2f2; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; + width: 32px; + height: 32px; + min-width: 32px; + border-radius: 50%; + background-color: #f2f2f2; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; } .autocomplete-text-container { - display: flex; - flex-direction: column; - align-items: flex-start; - flex: 1 0 0; - min-width: 0; - overflow: hidden; + display: flex; + flex-direction: column; + align-items: flex-start; + flex: 1 0 0; + min-width: 0; + overflow: hidden; } .autocomplete-item-title { - font-family: "Google Sans Text", "Google Sans", "Roboto", sans-serif; - font-weight: 500; - font-size: 14px; - line-height: 20px; - letter-spacing: 0.1px; - color: #1f1f1f; - margin: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - width: 100%; + font-family: 'Google Sans Text', 'Google Sans', 'Roboto', sans-serif; + font-weight: 500; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.1px; + color: #1f1f1f; + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 100%; } .autocomplete-matched { - color: #5e5e5e; - font-weight: 500; + color: #5e5e5e; + font-weight: 500; } .autocomplete-unmatched { - color: #1f1f1f; - font-weight: 500; + color: #1f1f1f; + font-weight: 500; } .autocomplete-item-subtitle { - font-family: "Google Sans Text", "Google Sans", "Roboto", sans-serif; - font-weight: 400; - font-size: 12px; - line-height: 16px; - letter-spacing: 0.2px; - color: #5e5e5e; - display: flex; - gap: 4px; - align-items: center; - width: 100%; - margin: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + font-family: 'Google Sans Text', 'Google Sans', 'Roboto', sans-serif; + font-weight: 400; + font-size: 12px; + line-height: 16px; + letter-spacing: 0.2px; + color: #5e5e5e; + display: flex; + gap: 4px; + align-items: center; + width: 100%; + margin: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .autocomplete-distance { - color: #5e5e5e; - flex-shrink: 0; + color: #5e5e5e; + flex-shrink: 0; } .autocomplete-dot { - color: #1f1f1f; - flex-shrink: 0; + color: #1f1f1f; + flex-shrink: 0; } .autocomplete-secondary { - color: #5e5e5e; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + color: #5e5e5e; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .autocomplete-attribution-footer { - height: 36px; - display: flex; - align-items: center; - justify-content: flex-end; - padding: 0 12px; - background-color: #ffffff; - box-sizing: border-box; + height: 36px; + display: flex; + align-items: center; + justify-content: flex-end; + padding: 0 12px; + background-color: #ffffff; + box-sizing: border-box; } .gmp-attribution-text { - font-family: "Roboto", "Google Sans Text", "Google Sans", sans-serif; - font-size: 12px; - line-height: 16px; - color: #70757a; - font-weight: 400; - user-select: none; + font-family: 'Roboto', 'Google Sans Text', 'Google Sans', sans-serif; + font-size: 12px; + line-height: 16px; + color: #70757a; + font-weight: 400; + user-select: none; } /* ========================================================================== @@ -400,109 +427,112 @@ body { ========================================================================== */ .config-section { - width: 100%; - display: flex; - flex-direction: column; - gap: 12px; - margin: 0; + width: 100%; + display: flex; + flex-direction: column; + gap: 12px; + margin: 0; } .section-header { - width: 100%; - display: flex; - flex-direction: column; - gap: 6px; + width: 100%; + display: flex; + flex-direction: column; + gap: 6px; } .section-title { - font-family: "Roboto", sans-serif; - font-weight: 500; - font-size: 16px; - line-height: 24px; - color: #202124; - margin: 0; - white-space: nowrap; + font-family: 'Roboto', sans-serif; + font-weight: 500; + font-size: 16px; + line-height: 24px; + color: #202124; + margin: 0; + white-space: nowrap; } .section-description { - font-family: "Google Sans", sans-serif; - font-weight: 400; - font-size: 14px; - line-height: 20px; - letter-spacing: 0.2px; - color: #202124; - margin: 0; + font-family: 'Google Sans', sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.2px; + color: #202124; + margin: 0; } .config-bullets { - list-style-type: disc; - padding-left: 21px; - margin: 0; - display: flex; - flex-direction: column; - gap: 0; + list-style-type: disc; + padding-left: 21px; + margin: 0; + display: flex; + flex-direction: column; + gap: 0; } .config-bullets li { - font-family: "Google Sans", sans-serif; - font-weight: 400; - font-size: 14px; - line-height: 20px; - letter-spacing: 0.2px; - color: #202124; - margin: 0; + font-family: 'Google Sans', sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.2px; + color: #202124; + margin: 0; } .segmented-button-group { - display: flex; - width: 100%; - height: 36px; - align-items: center; + display: flex; + width: 100%; + height: 36px; + align-items: center; } .segmented-button { - flex: 1 0 0; - height: 36px; - display: flex; - align-items: center; - justify-content: center; - padding: 8px 24px; - font-family: "Google Sans", sans-serif; - font-weight: 500; - font-size: 14px; - line-height: 20px; - text-align: center; - white-space: nowrap; - cursor: pointer; - border: 1px solid #dadce0; - background-color: #ffffff; - color: #1a73e8; - position: relative; - user-select: none; - transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; + flex: 1 0 0; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + padding: 8px 24px; + font-family: 'Google Sans', sans-serif; + font-weight: 500; + font-size: 14px; + line-height: 20px; + text-align: center; + white-space: nowrap; + cursor: pointer; + border: 1px solid #dadce0; + background-color: #ffffff; + color: #1a73e8; + position: relative; + user-select: none; + transition: + background-color 0.15s ease, + color 0.15s ease, + border-color 0.15s ease; } .segmented-button:not(:first-child) { - margin-left: -1px; + margin-left: -1px; } .segmented-button:first-child { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; } .segmented-button:last-child { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; } .segmented-button.active { - background-color: #1a73e8; - color: #ffffff; - border-color: #1a73e8; - z-index: 1; + background-color: #1a73e8; + color: #ffffff; + border-color: #1a73e8; + z-index: 1; } .segmented-button:hover:not(.active) { - background-color: #f1f3f4; + background-color: #f1f3f4; } diff --git a/samples/ui-kit-place-details-demo/style.css.metadata.json b/samples/ui-kit-place-details-demo/style.css.metadata.json index 366d8d909..3de1f8219 100644 --- a/samples/ui-kit-place-details-demo/style.css.metadata.json +++ b/samples/ui-kit-place-details-demo/style.css.metadata.json @@ -1,5 +1,5 @@ { - "summary": "CSS stylesheet for Place Details interactive customizer demo including Google, Miami, and Redwood themes.", - "updatedAt": "2026-08-16T17:37:57.547471700Z", - "userFacing": true -} \ No newline at end of file + "summary": "CSS stylesheet for Place Details interactive customizer demo including Google, Miami, and Redwood themes.", + "updatedAt": "2026-08-16T17:37:57.547471700Z", + "userFacing": true +} From 980161fb043716fe43003de9f82ebb1141cb5dcb Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 02:31:10 +0000 Subject: [PATCH 07/16] chore(samples): remove mistakenly committed ui-kit-place-details-demo --- samples/ui-kit-place-details-demo/index.html | 157 ----- .../index.html.metadata.json | 5 - samples/ui-kit-place-details-demo/index.ts | 432 -------------- .../index.ts.metadata.json | 5 - .../ui-kit-place-details-demo/package.json | 15 - .../package.json.metadata.json | 5 - samples/ui-kit-place-details-demo/style.css | 538 ------------------ .../style.css.metadata.json | 5 - 8 files changed, 1162 deletions(-) delete mode 100644 samples/ui-kit-place-details-demo/index.html delete mode 100644 samples/ui-kit-place-details-demo/index.html.metadata.json delete mode 100644 samples/ui-kit-place-details-demo/index.ts delete mode 100644 samples/ui-kit-place-details-demo/index.ts.metadata.json delete mode 100644 samples/ui-kit-place-details-demo/package.json delete mode 100644 samples/ui-kit-place-details-demo/package.json.metadata.json delete mode 100644 samples/ui-kit-place-details-demo/style.css delete mode 100644 samples/ui-kit-place-details-demo/style.css.metadata.json diff --git a/samples/ui-kit-place-details-demo/index.html b/samples/ui-kit-place-details-demo/index.html deleted file mode 100644 index 78312c793..000000000 --- a/samples/ui-kit-place-details-demo/index.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - Place Details Demo — Google Maps Platform Places UI Kit - - - - - - - - - - - - -
-
- - -
- - - - -
-
-
- - diff --git a/samples/ui-kit-place-details-demo/index.html.metadata.json b/samples/ui-kit-place-details-demo/index.html.metadata.json deleted file mode 100644 index 74069de23..000000000 --- a/samples/ui-kit-place-details-demo/index.html.metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "summary": "HTML file for the Place Details interactive customizer demo.", - "updatedAt": "2026-08-16T17:37:49.145049639Z", - "userFacing": true -} diff --git a/samples/ui-kit-place-details-demo/index.ts b/samples/ui-kit-place-details-demo/index.ts deleted file mode 100644 index 4008b196d..000000000 --- a/samples/ui-kit-place-details-demo/index.ts +++ /dev/null @@ -1,432 +0,0 @@ -/* - * @license - * Copyright 2025 Google LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -/* [START maps_ui_kit_place_details_customizer] */ - -interface SuggestionItem { - placeId: string; - mainText: string; - mainMatches: Array<{ startOffset: number; endOffset: number }>; - secondaryText?: string; - distanceText?: string; - fullText: string; -} - -let sessionToken: google.maps.places.AutocompleteSessionToken | null = null; -let currentSuggestions: SuggestionItem[] = []; -let selectedSuggestionIndex = -1; -let debounceTimeout: number | undefined; - -async function init(): Promise { - // 1. Request required Google Maps libraries - const [, placesLib] = await Promise.all([ - google.maps.importLibrary('maps'), - google.maps.importLibrary('places') as Promise< - typeof google.maps.places - >, - google.maps.importLibrary('marker'), - ]); - - const placeDetailsWidget = document.querySelector( - '#place-details-widget' - )!; - const placeDetailsRequest = document.querySelector( - '#place-details-request' - )!; - const addressInput = document.querySelector('#address')!; - const autocompleteList = - document.querySelector('#autocomplete-list')!; - - // -------------------------------------------------------------------------- - // Content Configuration Switching - // -------------------------------------------------------------------------- - const contentConfigButtons = document.querySelectorAll( - '#content-config-buttons .segmented-button' - ); - - contentConfigButtons.forEach((button) => { - button.addEventListener('click', () => { - contentConfigButtons.forEach((btn) => { - btn.classList.remove('active'); - btn.setAttribute('aria-pressed', 'false'); - }); - button.classList.add('active'); - button.setAttribute('aria-pressed', 'true'); - - const mode = button.getAttribute('data-value'); - applyContentConfig(mode); - }); - }); - - function applyContentConfig(mode: string | null) { - // Preserve the place-request child element - const currentPlace = - placeDetailsRequest.getAttribute('place') || - 'places/ChIJ5abCmkWHhYARH3zgiLVc_Ew'; - placeDetailsWidget.innerHTML = ''; - - const newRequest = document.createElement( - 'gmp-place-details-place-request' - ); - newRequest.id = 'place-details-request'; - newRequest.setAttribute('place', currentPlace); - placeDetailsWidget.appendChild(newRequest); - - if (mode === 'standard') { - const standardContent = document.createElement( - 'gmp-place-standard-content' - ); - placeDetailsWidget.appendChild(standardContent); - } else if (mode === 'all') { - const allContent = document.createElement('gmp-place-all-content'); - placeDetailsWidget.appendChild(allContent); - } else if (mode === 'custom') { - const customConfig = document.createElement( - 'gmp-place-content-config' - ); - - const elementsToInclude = [ - { tag: 'gmp-place-media', attrs: { 'lightbox-preferred': '' } }, - { tag: 'gmp-place-summary' }, - { tag: 'gmp-place-address' }, - { tag: 'gmp-place-rating' }, - { tag: 'gmp-place-open-now-status' }, - { tag: 'gmp-place-price' }, - { tag: 'gmp-place-type' }, - { tag: 'gmp-place-website' }, - { tag: 'gmp-place-phone-number' }, - { tag: 'gmp-place-plus-code' }, - { tag: 'gmp-place-accessible-entrance-icon' }, - ]; - - elementsToInclude.forEach(({ tag, attrs }) => { - const el = document.createElement(tag); - if (attrs) { - Object.entries(attrs).forEach(([key, val]) => - el.setAttribute(key, val) - ); - } - customConfig.appendChild(el); - }); - - placeDetailsWidget.appendChild(customConfig); - } - } - - // -------------------------------------------------------------------------- - // Theme Switching - // -------------------------------------------------------------------------- - const themeButtons = document.querySelectorAll( - '#theme-buttons .segmented-button' - ); - - themeButtons.forEach((button) => { - button.addEventListener('click', () => { - themeButtons.forEach((btn) => { - btn.classList.remove('active'); - btn.setAttribute('aria-pressed', 'false'); - }); - button.classList.add('active'); - button.setAttribute('aria-pressed', 'true'); - - const theme = button.getAttribute('data-value'); - placeDetailsWidget.classList.remove( - 'theme-google', - 'theme-miami', - 'theme-redwood' - ); - - if (theme === 'example1') { - placeDetailsWidget.classList.add('theme-miami'); - } else if (theme === 'example2') { - placeDetailsWidget.classList.add('theme-redwood'); - } else { - placeDetailsWidget.classList.add('theme-google'); - } - }); - }); - - // -------------------------------------------------------------------------- - // Autocomplete Search Logic - // -------------------------------------------------------------------------- - function getSessionToken(): google.maps.places.AutocompleteSessionToken { - if (!sessionToken && placesLib.AutocompleteSessionToken) { - sessionToken = new placesLib.AutocompleteSessionToken(); - } - return sessionToken!; - } - - async function fetchSuggestions(query: string): Promise { - if (!query.trim()) { - closeDropdown(); - return; - } - - try { - if ( - placesLib.AutocompleteSuggestion?.fetchAutocompleteSuggestions - ) { - const response = - await placesLib.AutocompleteSuggestion.fetchAutocompleteSuggestions( - { - input: query, - sessionToken: getSessionToken(), - } - ); - - if (response?.suggestions && response.suggestions.length > 0) { - currentSuggestions = response.suggestions - .filter((s) => s.placePrediction) - .map((s) => { - const pred = s.placePrediction!; - const mainText = - typeof pred.mainText === 'string' - ? pred.mainText - : (pred.mainText?.text ?? - pred.text?.text ?? - ''); - const secondaryText = - typeof pred.secondaryText === 'string' - ? pred.secondaryText - : (pred.secondaryText?.text ?? ''); - const fullText = - typeof pred.text === 'string' - ? pred.text - : (pred.text?.text ?? mainText); - - let distanceText: string | undefined; - if ( - pred.distanceMeters && - pred.distanceMeters > 0 - ) { - distanceText = `${(pred.distanceMeters / 1609.34).toFixed(1)} mi`; - } - - const mainMatches = ( - pred.mainText?.matches || [] - ).map((m) => ({ - startOffset: m.startOffset, - endOffset: m.endOffset, - })); - - return { - placeId: pred.placeId, - mainText, - mainMatches, - secondaryText, - distanceText, - fullText, - }; - }); - - renderDropdown(); - return; - } - } - } catch (err) { - console.warn('Error fetching autocomplete suggestions:', err); - } - - closeDropdown(); - } - - function renderDropdown(): void { - if (currentSuggestions.length === 0) { - closeDropdown(); - return; - } - - autocompleteList.innerHTML = ''; - autocompleteList.removeAttribute('hidden'); - selectedSuggestionIndex = -1; - - currentSuggestions.forEach((item, index) => { - const itemEl = document.createElement('div'); - itemEl.className = 'autocomplete-list-item'; - itemEl.setAttribute('data-index', String(index)); - - // Pin Icon Container - const iconContainer = document.createElement('div'); - iconContainer.className = 'autocomplete-icon-container'; - iconContainer.innerHTML = ` - - `; - itemEl.appendChild(iconContainer); - - // Text Container - const textContainer = document.createElement('div'); - textContainer.className = 'autocomplete-text-container'; - - const titleEl = document.createElement('p'); - titleEl.className = 'autocomplete-item-title'; - titleEl.innerHTML = buildHighlightedText( - item.mainText, - item.mainMatches - ); - textContainer.appendChild(titleEl); - - if (item.secondaryText || item.distanceText) { - const subtitleEl = document.createElement('div'); - subtitleEl.className = 'autocomplete-item-subtitle'; - - if (item.distanceText) { - const distSpan = document.createElement('span'); - distSpan.className = 'autocomplete-distance'; - distSpan.textContent = item.distanceText; - subtitleEl.appendChild(distSpan); - - const dotSpan = document.createElement('span'); - dotSpan.className = 'autocomplete-dot'; - dotSpan.textContent = '·'; - subtitleEl.appendChild(dotSpan); - } - - if (item.secondaryText) { - const secSpan = document.createElement('span'); - secSpan.className = 'autocomplete-secondary'; - secSpan.textContent = item.secondaryText; - subtitleEl.appendChild(secSpan); - } - - textContainer.appendChild(subtitleEl); - } - - itemEl.appendChild(textContainer); - - itemEl.addEventListener('click', () => selectSuggestion(item)); - autocompleteList.appendChild(itemEl); - }); - - // Attribution Footer - const footer = document.createElement('div'); - footer.className = 'autocomplete-attribution-footer'; - footer.innerHTML = - 'Google Maps'; - autocompleteList.appendChild(footer); - } - - function buildHighlightedText( - text: string, - matches: Array<{ startOffset: number; endOffset: number }> - ): string { - if (!matches || matches.length === 0) { - return `${escapeHtml(text)}`; - } - - let html = ''; - let lastIndex = 0; - - matches.forEach(({ startOffset, endOffset }) => { - if (startOffset > lastIndex) { - html += `${escapeHtml(text.slice(lastIndex, startOffset))}`; - } - html += `${escapeHtml(text.slice(startOffset, endOffset))}`; - lastIndex = endOffset; - }); - - if (lastIndex < text.length) { - html += `${escapeHtml(text.slice(lastIndex))}`; - } - - return html; - } - - function escapeHtml(str: string): string { - return str - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - - function selectSuggestion(item: SuggestionItem): void { - addressInput.value = ''; - addressInput.placeholder = item.mainText || item.fullText; - closeDropdown(); - - // Update Place Request - const activeRequest = document.querySelector( - '#place-details-request' - ); - if (activeRequest) { - activeRequest.setAttribute('place', `places/${item.placeId}`); - } - - // Reset session token after selection - sessionToken = null; - } - - function closeDropdown(): void { - autocompleteList.setAttribute('hidden', ''); - autocompleteList.innerHTML = ''; - currentSuggestions = []; - selectedSuggestionIndex = -1; - } - - addressInput.addEventListener('input', () => { - window.clearTimeout(debounceTimeout); - debounceTimeout = window.setTimeout(() => { - fetchSuggestions(addressInput.value); - }, 150); - }); - - addressInput.addEventListener('keydown', (e: KeyboardEvent) => { - if (currentSuggestions.length === 0) return; - - const items = autocompleteList.querySelectorAll( - '.autocomplete-list-item' - ); - - if (e.key === 'ArrowDown') { - e.preventDefault(); - selectedSuggestionIndex = - (selectedSuggestionIndex + 1) % items.length; - updateSelection(items); - } else if (e.key === 'ArrowUp') { - e.preventDefault(); - selectedSuggestionIndex = - (selectedSuggestionIndex - 1 + items.length) % items.length; - updateSelection(items); - } else if (e.key === 'Enter') { - e.preventDefault(); - if ( - selectedSuggestionIndex >= 0 && - selectedSuggestionIndex < currentSuggestions.length - ) { - selectSuggestion(currentSuggestions[selectedSuggestionIndex]); - } else if (currentSuggestions.length > 0) { - selectSuggestion(currentSuggestions[0]); - } - } else if (e.key === 'Escape') { - closeDropdown(); - } - }); - - function updateSelection(items: NodeListOf): void { - items.forEach((item, index) => { - if (index === selectedSuggestionIndex) { - item.classList.add('selected'); - item.scrollIntoView({ block: 'nearest' }); - } else { - item.classList.remove('selected'); - } - }); - } - - document.addEventListener('click', (e) => { - if ( - !autocompleteList.contains(e.target as Node) && - e.target !== addressInput - ) { - closeDropdown(); - } - }); -} - -void init(); -/* [END maps_ui_kit_place_details_customizer] */ diff --git a/samples/ui-kit-place-details-demo/index.ts.metadata.json b/samples/ui-kit-place-details-demo/index.ts.metadata.json deleted file mode 100644 index ca5acb970..000000000 --- a/samples/ui-kit-place-details-demo/index.ts.metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "summary": "TypeScript controller for Place Details interactive customizer demo.", - "updatedAt": "2026-08-16T17:38:05.012911974Z", - "userFacing": true -} diff --git a/samples/ui-kit-place-details-demo/package.json b/samples/ui-kit-place-details-demo/package.json deleted file mode 100644 index 949e4ee6f..000000000 --- a/samples/ui-kit-place-details-demo/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@js-api-samples/ui-kit-place-details-demo", - "version": "1.0.0", - "description": "Interactive Place Details customization demo with autocomplete search, content configurations, and custom brand themes.", - "main": "index.ts", - "scripts": { - "start": "vite", - "build": "vite build" - }, - "devDependencies": { - "@types/google.maps": "^3.58.1", - "typescript": "^5.4.5", - "vite": "^5.2.11" - } -} diff --git a/samples/ui-kit-place-details-demo/package.json.metadata.json b/samples/ui-kit-place-details-demo/package.json.metadata.json deleted file mode 100644 index 8f3e6fb0e..000000000 --- a/samples/ui-kit-place-details-demo/package.json.metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "summary": "package.json configuration for Place Details interactive customizer demo.", - "updatedAt": "2026-08-16T17:38:07.654115810Z", - "userFacing": true -} diff --git a/samples/ui-kit-place-details-demo/style.css b/samples/ui-kit-place-details-demo/style.css deleted file mode 100644 index 3398fa357..000000000 --- a/samples/ui-kit-place-details-demo/style.css +++ /dev/null @@ -1,538 +0,0 @@ -/* - * @license - * Copyright 2025 Google LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -/* ========================================================================== - Place Details Themes - ========================================================================== */ - -gmp-place-details { - box-sizing: border-box; - color-scheme: light dark; - display: block; - width: 400px; - height: 700px; - max-height: 700px; - flex-shrink: 0; -} - -@media (max-width: 880px) { - gmp-place-details { - width: 100%; - max-width: 400px; - } -} - -gmp-place-details.theme-google { - box-sizing: border-box; -} - -/* Miami Theme (Teal / Bold Accent / Pill Buttons) */ -gmp-place-details.theme-miami { - --gmp-mat-color-surface: light-dark(#fdf8f5, #1a2e3b); - --gmp-mat-color-on-surface: light-dark(#2f3f4f, #e0ebf5); - --gmp-mat-color-on-surface-variant: light-dark(#6a7a8a, #aabbdd); - --gmp-mat-color-primary: light-dark(#0097a7, #80deea); - --gmp-mat-color-info: light-dark(#0097a7, #80deea); - --gmp-mat-color-secondary-container: light-dark(#ffebee, #3b1b1f); - --gmp-mat-color-on-secondary-container: light-dark(#d81b60, #ffcdd2); - --gmp-mat-color-outline-decorative: light-dark(#e0e0e0, #4f5f6f); - --gmp-mat-color-negative: light-dark(#e53935, #ffcdd2); - --gmp-mat-color-positive: light-dark(#4caf50, #a5d6a7); - --gmp-star-rating-color: light-dark(#d81b60, #ffcdd2); - --gmp-mat-font-family: 'Inter', 'Roboto', sans-serif; - --gmp-mat-font-headline-medium: normal 600 1.25em / 1.3 - var(--gmp-mat-font-family, 'Inter', sans-serif); - --gmp-mat-font-title-small: normal 500 1em / 1.375 - var(--gmp-mat-font-family, 'Inter', sans-serif); - --gmp-mat-font-body-medium: normal 400 0.875em / calc(20 / 14) - var(--gmp-mat-font-family, 'Roboto', sans-serif); - --gmp-mat-font-body-small: normal 400 0.75em / calc(16 / 12) - var(--gmp-mat-font-family, 'Roboto', sans-serif); - --gmp-mat-font-label-large: normal 600 0.875em / calc(20 / 14) - var(--gmp-mat-font-family, 'Roboto', sans-serif); - --gmp-mat-spacing-extra-small: 4px; - --gmp-mat-spacing-small: 8px; - --gmp-mat-spacing-medium: 12px; - --gmp-mat-spacing-large: 16px; - --gmp-mat-spacing-extra-large: 20px; - --gmp-mat-spacing-two-extra-large: 24px; - --gmp-mat-border-radius: 10px; - --gmp-button-border-radius: 9999px; - --gmp-thumbnail-border-radius: 6px; - --gmp-collage-border-radius-outer: 10px; - --gmp-card-border-radius: 10px; - --gmp-dialog-border-radius: 18px; - box-sizing: border-box; -} - -/* Redwood Theme (Warm Earthy / Serif Headings) */ -gmp-place-details.theme-redwood { - --gmp-theme-font-family-headings-labels: 'Domine', serif; - --gmp-theme-font-family-content: 'Nunito Sans', sans-serif; - --gmp-mat-color-surface: light-dark(#f5f0e8, #3a2e29); - --gmp-mat-color-on-surface: light-dark(#5d4037, #e8e0d8); - --gmp-mat-color-on-surface-variant: light-dark(#795548, #b0a191); - --gmp-mat-color-surface-container: light-dark(#ebe5db, #2f2521); - --gmp-mat-color-primary: light-dark(#386641, #7cb342); - --gmp-mat-color-secondary-container: light-dark(#6a4c3b, #558b2f); - --gmp-mat-color-on-secondary-container: light-dark(#ffffff, #ffffff); - --gmp-mat-color-outline-decorative: light-dark(#c0b5a8, #5c4a42); - --gmp-mat-color-info: light-dark(#386641, #7cb342); - --gmp-mat-color-positive: light-dark(#4caf50, #8bc34a); - --gmp-mat-color-negative: light-dark(#b85c5c, #e57373); - --gmp-mat-color-disabled-surface: light-dark(#e0d8cd, #4e3f3a); - --gmp-mat-color-neutral-container: light-dark(#eae0d5, #4a3c35); - --gmp-mat-color-on-neutral-container: light-dark(#5d4037, #b0a191); - --gmp-mat-color-positive-container: light-dark(#d5e8d4, #33691e); - --gmp-mat-color-on-positive-container: light-dark(#2e5336, #c5e1a5); - --gmp-star-rating-color: light-dark(#bc6c25, #dda15e); - --gmp-mat-font-family: var(--gmp-theme-font-family-content); - --gmp-mat-font-body-medium: normal 400 0.9375em / calc(22 / 15) - var(--gmp-mat-font-family); - --gmp-mat-font-body-small: normal 400 0.8125em / calc(18 / 13) - var(--gmp-mat-font-family); - --gmp-mat-font-headline-large: normal 500 1.75em / calc(32 / 28) - var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-headline-medium: normal 500 1.375em / calc(28 / 22) - var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-title-small: normal 500 1.125em / calc(24 / 18) - var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-display-small: normal 400 1.625em / calc(30 / 26) - var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-label-large: normal 500 0.875em / calc(20 / 14) - var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-label-medium: normal 500 0.75em / calc(16 / 12) - var(--gmp-theme-font-family-headings-labels); - --gmp-mat-font-label-small: normal 500 0.6875em / calc(12 / 11) - var(--gmp-theme-font-family-headings-labels); - box-sizing: border-box; -} - -/* ========================================================================== - Demo Page Layout - ========================================================================== */ - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -html, -body { - min-height: 100vh; - background-color: #f8f9fa; - font-family: - 'Google Sans', - 'Roboto', - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - Roboto, - sans-serif; - color: #202124; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.page-wrapper { - min-height: 100vh; - display: flex; - align-items: center; - justify-content: center; - padding: 24px 16px; -} - -.demo-frame { - width: 839px; - min-height: 750px; - background-color: #ffffff; - border-radius: 16px; - box-shadow: - 0 1px 3px rgba(60, 64, 67, 0.12), - 0 4px 8px rgba(60, 64, 67, 0.08); - border: 1px solid #dadce0; - padding: 25px; - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: flex-start; - gap: 50px; -} - -@media (max-width: 880px) { - .demo-frame { - width: 100%; - max-width: 839px; - flex-direction: column; - align-items: center; - gap: 32px; - padding: 20px; - } -} - -.left-column { - width: 339px; - flex-shrink: 0; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 20px; -} - -@media (max-width: 880px) { - .left-column { - width: 100%; - max-width: 400px; - } -} - -.demo-header { - width: 100%; - display: flex; - flex-direction: column; - gap: 8px; - align-items: flex-start; -} - -.demo-title-container { - width: 100%; - display: flex; - flex-direction: column; - align-items: flex-start; -} - -.demo-title { - font-family: 'Roboto', sans-serif; - font-weight: 300; - font-size: 24px; - line-height: 32px; - color: #202124; - margin: 0; - white-space: nowrap; -} - -.component-description { - font-family: 'Google Sans', 'Roboto', sans-serif; - font-weight: 400; - font-size: 16px; - line-height: 24px; - color: #202124; - margin: 0; - width: 100%; - white-space: pre-wrap; -} - -/* ========================================================================== - Search & Autocomplete Controls - ========================================================================== */ - -.address-input { - width: 100%; - display: flex; - flex-direction: column; - margin: 0; -} - -.form-group { - width: 100%; - display: flex; - flex-direction: column; - gap: 4px; - position: relative; -} - -.form-group label { - font-family: 'Roboto', 'Google Sans', sans-serif; - font-weight: 400; - font-size: 12px; - line-height: 16px; - color: #606368; - display: block; - margin: 0; - cursor: pointer; -} - -.form-group input[type='text'] { - width: 100%; - height: 40px; - background: #ffffff; - border: 1px solid #dadce0; - border-radius: 4px; - padding: 8px 12px; - font-family: 'Roboto', sans-serif; - font-weight: 400; - font-size: 16px; - line-height: 24px; - color: #202124; - outline: none; - box-sizing: border-box; - transition: - border-color 0.2s ease, - box-shadow 0.2s ease; -} - -.form-group input[type='text']:focus { - border-color: #1a73e8; - border-bottom: 2px solid #1a73e8; - padding-bottom: 7px; -} - -#autocomplete-list-wrapper { - position: relative; - width: 100%; -} - -.autocomplete-dropdown { - position: absolute; - top: 100%; - left: 0; - margin-top: 4px; - width: 100%; - background-color: #ffffff; - border-radius: 8px; - box-shadow: - 0 1px 2px rgba(0, 0, 0, 0.3), - 0 2px 6px 2px rgba(0, 0, 0, 0.15); - overflow: hidden; - z-index: 10000; - box-sizing: border-box; - display: flex; - flex-direction: column; -} - -.autocomplete-list-item { - display: flex; - gap: 12px; - align-items: center; - padding: 8px 12px; - background-color: #ffffff; - border-bottom: 1px solid #e3e3e3; - cursor: pointer; - box-sizing: border-box; - width: 100%; - transition: background-color 0.15s ease; -} - -.autocomplete-list-item:hover, -.autocomplete-list-item.selected { - background-color: #f2f2f2; -} - -.autocomplete-icon-container { - width: 32px; - height: 32px; - min-width: 32px; - border-radius: 50%; - background-color: #f2f2f2; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; -} - -.autocomplete-text-container { - display: flex; - flex-direction: column; - align-items: flex-start; - flex: 1 0 0; - min-width: 0; - overflow: hidden; -} - -.autocomplete-item-title { - font-family: 'Google Sans Text', 'Google Sans', 'Roboto', sans-serif; - font-weight: 500; - font-size: 14px; - line-height: 20px; - letter-spacing: 0.1px; - color: #1f1f1f; - margin: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - width: 100%; -} - -.autocomplete-matched { - color: #5e5e5e; - font-weight: 500; -} - -.autocomplete-unmatched { - color: #1f1f1f; - font-weight: 500; -} - -.autocomplete-item-subtitle { - font-family: 'Google Sans Text', 'Google Sans', 'Roboto', sans-serif; - font-weight: 400; - font-size: 12px; - line-height: 16px; - letter-spacing: 0.2px; - color: #5e5e5e; - display: flex; - gap: 4px; - align-items: center; - width: 100%; - margin: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.autocomplete-distance { - color: #5e5e5e; - flex-shrink: 0; -} - -.autocomplete-dot { - color: #1f1f1f; - flex-shrink: 0; -} - -.autocomplete-secondary { - color: #5e5e5e; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.autocomplete-attribution-footer { - height: 36px; - display: flex; - align-items: center; - justify-content: flex-end; - padding: 0 12px; - background-color: #ffffff; - box-sizing: border-box; -} - -.gmp-attribution-text { - font-family: 'Roboto', 'Google Sans Text', 'Google Sans', sans-serif; - font-size: 12px; - line-height: 16px; - color: #70757a; - font-weight: 400; - user-select: none; -} - -/* ========================================================================== - Configuration Sections & Segmented Controls - ========================================================================== */ - -.config-section { - width: 100%; - display: flex; - flex-direction: column; - gap: 12px; - margin: 0; -} - -.section-header { - width: 100%; - display: flex; - flex-direction: column; - gap: 6px; -} - -.section-title { - font-family: 'Roboto', sans-serif; - font-weight: 500; - font-size: 16px; - line-height: 24px; - color: #202124; - margin: 0; - white-space: nowrap; -} - -.section-description { - font-family: 'Google Sans', sans-serif; - font-weight: 400; - font-size: 14px; - line-height: 20px; - letter-spacing: 0.2px; - color: #202124; - margin: 0; -} - -.config-bullets { - list-style-type: disc; - padding-left: 21px; - margin: 0; - display: flex; - flex-direction: column; - gap: 0; -} - -.config-bullets li { - font-family: 'Google Sans', sans-serif; - font-weight: 400; - font-size: 14px; - line-height: 20px; - letter-spacing: 0.2px; - color: #202124; - margin: 0; -} - -.segmented-button-group { - display: flex; - width: 100%; - height: 36px; - align-items: center; -} - -.segmented-button { - flex: 1 0 0; - height: 36px; - display: flex; - align-items: center; - justify-content: center; - padding: 8px 24px; - font-family: 'Google Sans', sans-serif; - font-weight: 500; - font-size: 14px; - line-height: 20px; - text-align: center; - white-space: nowrap; - cursor: pointer; - border: 1px solid #dadce0; - background-color: #ffffff; - color: #1a73e8; - position: relative; - user-select: none; - transition: - background-color 0.15s ease, - color 0.15s ease, - border-color 0.15s ease; -} - -.segmented-button:not(:first-child) { - margin-left: -1px; -} - -.segmented-button:first-child { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; -} - -.segmented-button:last-child { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} - -.segmented-button.active { - background-color: #1a73e8; - color: #ffffff; - border-color: #1a73e8; - z-index: 1; -} - -.segmented-button:hover:not(.active) { - background-color: #f1f3f4; -} diff --git a/samples/ui-kit-place-details-demo/style.css.metadata.json b/samples/ui-kit-place-details-demo/style.css.metadata.json deleted file mode 100644 index 3de1f8219..000000000 --- a/samples/ui-kit-place-details-demo/style.css.metadata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "summary": "CSS stylesheet for Place Details interactive customizer demo including Google, Miami, and Redwood themes.", - "updatedAt": "2026-08-16T17:37:57.547471700Z", - "userFacing": true -} From 84a228566e3ea772efc2da61a4f77a63d5a9b008 Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 02:33:58 +0000 Subject: [PATCH 08/16] feat(samples): add advanced place list demo --- samples/ui-kit-advanced-place-list/README.md | 41 +++++++++++++++++++ samples/ui-kit-advanced-place-list/index.html | 34 +++++++++++++++ samples/ui-kit-advanced-place-list/index.ts | 21 ++++++++++ .../ui-kit-advanced-place-list/package.json | 12 ++++++ samples/ui-kit-advanced-place-list/style.css | 13 ++++++ .../ui-kit-advanced-place-list/tsconfig.json | 7 ++++ 6 files changed, 128 insertions(+) create mode 100644 samples/ui-kit-advanced-place-list/README.md create mode 100644 samples/ui-kit-advanced-place-list/index.html create mode 100644 samples/ui-kit-advanced-place-list/index.ts create mode 100644 samples/ui-kit-advanced-place-list/package.json create mode 100644 samples/ui-kit-advanced-place-list/style.css create mode 100644 samples/ui-kit-advanced-place-list/tsconfig.json diff --git a/samples/ui-kit-advanced-place-list/README.md b/samples/ui-kit-advanced-place-list/README.md new file mode 100644 index 000000000..4905ec71d --- /dev/null +++ b/samples/ui-kit-advanced-place-list/README.md @@ -0,0 +1,41 @@ +# Google Maps JavaScript Sample + +## ui-kit-advanced-place-list + +Advanced Place List + +## Setup + +### Before starting run: + +`npm i` + +### Run an example on a local web server + +`cd samples/ui-kit-advanced-place-list` +`npm start` + +### Build an individual example + +`cd samples/ui-kit-advanced-place-list` +`npm run build` + +From 'samples': + +`npm run build --workspace=ui-kit-advanced-place-list/` + +### Build all of the examples. + +From 'samples': + +`npm run build-all` + +### Run lint to check for problems + +`cd samples/ui-kit-advanced-place-list` +`npx eslint index.ts` + +## Feedback + +For feedback related to this sample, please open a new issue on +[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues). diff --git a/samples/ui-kit-advanced-place-list/index.html b/samples/ui-kit-advanced-place-list/index.html new file mode 100644 index 000000000..bac0a5cbf --- /dev/null +++ b/samples/ui-kit-advanced-place-list/index.html @@ -0,0 +1,34 @@ + + + + + + Advanced Place List + + + + + + + + + + + + + diff --git a/samples/ui-kit-advanced-place-list/index.ts b/samples/ui-kit-advanced-place-list/index.ts new file mode 100644 index 000000000..c7bbfd563 --- /dev/null +++ b/samples/ui-kit-advanced-place-list/index.ts @@ -0,0 +1,21 @@ +/** + * @license + * Copyright 2024 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* eslint-disable */ +// @ts-nocheck + +async function init() { + await customElements.whenDefined('gmp-advanced-place-list'); + const listElement = document.querySelector('gmp-advanced-place-list'); + + if (listElement) { + listElement.addEventListener('gmp-error', (e) => { + console.error('Failed to load places: ', e.detail.errors); + }); + } +} + +init(); diff --git a/samples/ui-kit-advanced-place-list/package.json b/samples/ui-kit-advanced-place-list/package.json new file mode 100644 index 000000000..f44f30217 --- /dev/null +++ b/samples/ui-kit-advanced-place-list/package.json @@ -0,0 +1,12 @@ +{ + "name": "@js-api-samples/ui-kit-advanced-place-list", + "version": "1.0.0", + "scripts": { + "build": "bash ../build-single.sh", + "test": "tsc && npm run build:vite --workspace=.", + "start": "tsc && vite build --config ../../vite.config.js --base './' && vite --config ../../vite.config.js", + "build:vite": "vite build --config ../../vite.config.js --base './'", + "preview": "vite preview --config ../../vite.config.js" + }, + "author": "Google LLC" +} diff --git a/samples/ui-kit-advanced-place-list/style.css b/samples/ui-kit-advanced-place-list/style.css new file mode 100644 index 000000000..824907ee6 --- /dev/null +++ b/samples/ui-kit-advanced-place-list/style.css @@ -0,0 +1,13 @@ +/** + * @license + * Copyright 2024 Google LLC. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +html, +body { + height: 100%; + margin: 0; + padding: 0; + font-family: Roboto, Arial, sans-serif; +} diff --git a/samples/ui-kit-advanced-place-list/tsconfig.json b/samples/ui-kit-advanced-place-list/tsconfig.json new file mode 100644 index 000000000..976bcc6ef --- /dev/null +++ b/samples/ui-kit-advanced-place-list/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "." + }, + "include": ["./*.ts"] +} From 1926a5c86f57383501164d39fe4999b8af270072 Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 02:51:02 +0000 Subject: [PATCH 09/16] fix(samples): import places API explicitly in advanced place list --- package-lock.json | 532 +------------------- samples/ui-kit-advanced-place-list/index.ts | 1 + 2 files changed, 10 insertions(+), 523 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d6d0a50a..604366635 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1031,6 +1031,10 @@ "resolved": "samples/ui-kit-advanced-place-details-compact", "link": true }, + "node_modules/@js-api-samples/ui-kit-advanced-place-list": { + "resolved": "samples/ui-kit-advanced-place-list", + "link": true + }, "node_modules/@js-api-samples/ui-kit-advanced-place-search-nearby-nearby": { "resolved": "samples/ui-kit-advanced-place-search-nearby", "link": true @@ -1047,10 +1051,6 @@ "resolved": "samples/ui-kit-place-details-compact", "link": true }, - "node_modules/@js-api-samples/ui-kit-place-details-demo": { - "resolved": "samples/ui-kit-place-details-demo", - "link": true - }, "node_modules/@js-api-samples/ui-kit-place-search-nearby-nearby": { "resolved": "samples/ui-kit-place-search-nearby", "link": true @@ -6251,6 +6251,10 @@ "name": "@js-api-samples/ui-kit-advanced-place-details-compact", "version": "1.0.0" }, + "samples/ui-kit-advanced-place-list": { + "name": "@js-api-samples/ui-kit-advanced-place-list", + "version": "1.0.0" + }, "samples/ui-kit-advanced-place-search-nearby": { "name": "@js-api-samples/ui-kit-advanced-place-search-nearby-nearby", "version": "1.0.0" @@ -6270,531 +6274,13 @@ "samples/ui-kit-place-details-demo": { "name": "@js-api-samples/ui-kit-place-details-demo", "version": "1.0.0", + "extraneous": true, "devDependencies": { "@types/google.maps": "^3.58.1", "typescript": "^5.4.5", "vite": "^5.2.11" } }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "samples/ui-kit-place-details-demo/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "samples/ui-kit-place-details-demo/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "samples/ui-kit-place-details-demo/node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "samples/ui-kit-place-details-demo/node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, "samples/ui-kit-place-search-nearby": { "name": "@js-api-samples/ui-kit-place-search-nearby-nearby", "version": "1.0.0" diff --git a/samples/ui-kit-advanced-place-list/index.ts b/samples/ui-kit-advanced-place-list/index.ts index c7bbfd563..5cd82a59f 100644 --- a/samples/ui-kit-advanced-place-list/index.ts +++ b/samples/ui-kit-advanced-place-list/index.ts @@ -8,6 +8,7 @@ // @ts-nocheck async function init() { + await google.maps.importLibrary('places'); await customElements.whenDefined('gmp-advanced-place-list'); const listElement = document.querySelector('gmp-advanced-place-list'); From eeeb916b59d4a787f971cb22e21579e411cb62da Mon Sep 17 00:00:00 2001 From: EJ Haselden Date: Thu, 27 Aug 2026 02:58:03 +0000 Subject: [PATCH 10/16] fix(samples): substitute missing dummy PRNs with known valid Place IDs for advanced place list demo --- samples/ui-kit-advanced-place-list/index.html | 2 +- samples/ui-kit-advanced-place-list/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/ui-kit-advanced-place-list/index.html b/samples/ui-kit-advanced-place-list/index.html index bac0a5cbf..ad8dd93a6 100644 --- a/samples/ui-kit-advanced-place-list/index.html +++ b/samples/ui-kit-advanced-place-list/index.html @@ -22,7 +22,7 @@ + places="places/ChIJC8HakaIRkFQRiOgkgdHmqkk,places/ChIJj61dQgK6j4AR4GeTYWZsKWw">