UNPKG

places-autocomplete-hook

Version:
193 lines (192 loc) 6.54 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { usePlacesAutocomplete: () => usePlacesAutocomplete }); module.exports = __toCommonJS(index_exports); var import_react = require("react"); function usePlacesAutocomplete({ apiKey, debounceMs = 300, language = "en", types, sessionToken, location, setSelectedPlace }) { const [value, setValue] = (0, import_react.useState)(""); const [predictions, setPredictions] = (0, import_react.useState)([]); const [loading, setLoading] = (0, import_react.useState)(false); const [error, setError] = (0, import_react.useState)(null); const debounceTimer = (0, import_react.useRef)(null); const clear = (0, import_react.useCallback)(() => { setPredictions([]); setError(null); setValue(""); }, []); const extractAddressComponent = (components, type) => { const component = components.find((comp) => comp.types.includes(type)); return component?.longText; }; const getPlaceDetails = (0, import_react.useCallback)( async (placeId) => { try { const response = await fetch( `https://places.googleapis.com/v1/places/${placeId}?key=${apiKey}&languageCode=${language}`, { method: "GET", headers: { "Content-Type": "application/json", "X-Goog-FieldMask": "formattedAddress,addressComponents,location", ...sessionToken && { "X-Goog-Api-Key": apiKey } } } ); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`); } const data = await response.json(); const addressComponents = data.addressComponents || []; return { placeId, formattedAddress: data.formattedAddress, addressComponents, location: data.location, streetNumber: extractAddressComponent(addressComponents, "street_number"), streetName: extractAddressComponent(addressComponents, "route"), city: extractAddressComponent(addressComponents, "locality"), state: extractAddressComponent(addressComponents, "administrative_area_level_1"), country: extractAddressComponent(addressComponents, "country"), postalCode: extractAddressComponent(addressComponents, "postal_code") }; } catch (err) { throw err instanceof Error ? err : new Error("An error occurred while fetching place details"); } }, [apiKey, language, sessionToken] ); const handlePlaceSelect = (0, import_react.useCallback)( async (placeId) => { setSelectedPlace?.(placeId); }, [setSelectedPlace] ); const search = (0, import_react.useCallback)( async (input) => { if (!input.trim()) { clear(); return; } try { setLoading(true); setError(null); const requestBody = { input, languageCode: language }; if (types) { requestBody.types = types; } if (location) { requestBody.locationBias = { circle: { center: { latitude: location.lat, longitude: location.lng }, radius: location.radius } }; } const response = await fetch( `https://places.googleapis.com/v1/places:autocomplete?key=${apiKey}`, { method: "POST", headers: { "Content-Type": "application/json", "X-Goog-FieldMask": "suggestions.placePrediction.place,suggestions.placePrediction.placeId,suggestions.placePrediction.text,suggestions.placePrediction.structuredFormat,suggestions.placePrediction.types", ...sessionToken && { "X-Goog-Api-Key": apiKey } }, body: JSON.stringify(requestBody) } ); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`); } const data = await response.json(); setPredictions(data.suggestions.map((suggestion) => suggestion.placePrediction) || []); } catch (err) { setError(err instanceof Error ? err : new Error("An error occurred")); setPredictions([]); } finally { setLoading(false); } }, [apiKey, language, sessionToken, types, location, clear] ); const debouncedSearch = (0, import_react.useCallback)( async (input) => { if (debounceTimer.current) { clearTimeout(debounceTimer.current); } return new Promise((resolve) => { debounceTimer.current = setTimeout(async () => { await search(input); resolve(); }, debounceMs); }); }, [search, debounceMs] ); (0, import_react.useEffect)(() => { return () => { if (debounceTimer.current) { clearTimeout(debounceTimer.current); } }; }, []); return { value, suggestions: { status: error ? "ERROR" : loading ? "LOADING" : predictions.length > 0 ? "OK" : "ZERO_RESULTS", data: predictions }, setValue: (newValue, shouldFetchData = true) => { setValue(newValue); if (shouldFetchData) { debouncedSearch(newValue); } }, clearSuggestions: clear, search: debouncedSearch, loading, error, getPlaceDetails, handlePlaceSelect }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { usePlacesAutocomplete }); //# sourceMappingURL=index.js.map