UNPKG

places-autocomplete-svelte

Version:

A flexible, accessible, and secure Svelte component leveraging the Google Maps Places Autocomplete API (New) to provide a user-friendly way to search for and retrieve detailed address information.

88 lines (87 loc) 3.27 kB
import { getContext, setContext } from 'svelte'; import { writable, get } from 'svelte/store'; import { setOptions, importLibrary } from "@googlemaps/js-api-loader"; const LOADER_CONTEXT_KEY = Symbol('gmaps-loader'); /** * Creates and sets the Google Maps context with writable stores. * This is synchronous and should be called once in a top-level component's script. */ export function setGMapsContext() { // Only set the context if it doesn't already exist. if (getContext(LOADER_CONTEXT_KEY)) return; setContext(LOADER_CONTEXT_KEY, { isInitialized: writable(false), error: writable(null), initializationPromise: null, // Will be set by the loader function }); } /** * Retrieves the shared Google Maps context. * @returns {GMapsContext} The stores for initialization status and errors. */ export function getGMapsContext() { const context = getContext(LOADER_CONTEXT_KEY); if (!context) { throw new Error('Google Maps context not found. Call setGMapsContext in a parent component.'); } return context; } export function hasGMapsContext() { const context = getContext(LOADER_CONTEXT_KEY); return !!context; } /** * Asynchronously initializes the Google Maps loader using the provided context. * This function is idempotent and safe to be called multiple times. * @param context - The GMapsContext object. * @param options - The options for the JS API loader, including your API key. * @returns {Promise<void>} */ export async function initialiseGMaps(options) { // Get the context internally const context = getGMapsContext(); // If the promise already exists, just await it. Don't re-initialize. if (context.initializationPromise) { return context.initializationPromise; } // If it's already marked as initialized (e.g., from a previous page navigation), resolve immediately. if (get(context.isInitialized)) { return Promise.resolve(); } // Create the promise and store it in the context object. context.initializationPromise = new Promise((resolve, reject) => { try { setOptions(options); // Await the setOptions which returns a promise context.isInitialized.set(true); resolve(); } catch (e) { const error = e instanceof Error ? e : new Error(String(e)); context.error.set(error); console.error("Failed to set Google Maps API options.", error); reject(error); } }); return context.initializationPromise; } /** * Initializes the Google Maps API without using the context. * @param options The options for the JS API loader, including your API key. * @returns A promise that resolves when the API is initialized. */ export function initialiseGMapsNoContext(options) { return new Promise((resolve, reject) => { try { setOptions(options); resolve(); } catch (e) { const error = e instanceof Error ? e : new Error(String(e)); console.error("Failed to set Google Maps API options.", error); reject(error); } }); } // Re-export importLibrary for components to use. export { importLibrary };