UNPKG

@georgemunyoro/use-places-autocomplete

Version:

React hook for Google Maps Places Autocomplete.

303 lines (257 loc) 8.74 kB
import { useRef, useState, useCallback, useEffect } from 'react'; function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } var useLatest = (function (val) { var ref = useRef(val); ref.current = val; return ref; }); var _debounce = (function (fn, delay) { var timer; // eslint-disable-next-line func-names return function () { var _this = this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (timer !== null) { clearTimeout(timer); timer = null; } timer = setTimeout(function () { return fn.apply(_this, args); }, delay); }; }); function useUncontrolled(_ref) { var value = _ref.value, defaultValue = _ref.defaultValue, finalValue = _ref.finalValue, _ref$onChange = _ref.onChange, onChange = _ref$onChange === void 0 ? function () {} : _ref$onChange; var _useState = useState(defaultValue !== undefined ? defaultValue : finalValue), uncontrolledValue = _useState[0], setUncontrolledValue = _useState[1]; var handleUncontrolledChange = function handleUncontrolledChange(val) { setUncontrolledValue(val); for (var _len = arguments.length, payload = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { payload[_key - 1] = arguments[_key]; } onChange == null ? void 0 : onChange.apply(void 0, [val].concat(payload)); }; if (value !== undefined) { return [value, onChange, true]; } return [uncontrolledValue, handleUncontrolledChange, false]; } var loadApiErr = "💡 use-places-autocomplete: Google Maps Places API library must be loaded. See: https://github.com/wellyshen/use-places-autocomplete#load-the-library"; var usePlacesAutocomplete = function usePlacesAutocomplete(_temp) { var _ref = _temp === void 0 ? {} : _temp, requestOptions = _ref.requestOptions, _ref$debounce = _ref.debounce, debounce = _ref$debounce === void 0 ? 200 : _ref$debounce, _ref$cache = _ref.cache, cache = _ref$cache === void 0 ? 24 * 60 * 60 : _ref$cache, _ref$cacheKey = _ref.cacheKey, cacheKey = _ref$cacheKey === void 0 ? "upa" : _ref$cacheKey, googleMaps = _ref.googleMaps, callbackName = _ref.callbackName, value = _ref.value, _ref$defaultValue = _ref.defaultValue, defaultValue = _ref$defaultValue === void 0 ? "" : _ref$defaultValue, onChange = _ref.onChange, _ref$initOnMount = _ref.initOnMount, initOnMount = _ref$initOnMount === void 0 ? true : _ref$initOnMount; var _useState = useState(false), ready = _useState[0], setReady = _useState[1]; var _useUncontrolled = useUncontrolled({ value: value, defaultValue: defaultValue, finalValue: "", onChange: onChange }), _value = _useUncontrolled[0], handleChange = _useUncontrolled[1]; var _useState2 = useState({ loading: false, status: "", data: [] }), suggestions = _useState2[0], setSuggestions = _useState2[1]; var asRef = useRef(); var requestOptionsRef = useLatest(requestOptions); var googleMapsRef = useLatest(googleMaps); var init = useCallback(function () { var _google$maps; if (asRef.current) return; var _window = window, google = _window.google; var gMaps = googleMapsRef.current; var placesLib = (gMaps == null ? void 0 : gMaps.places) || (google == null ? void 0 : (_google$maps = google.maps) == null ? void 0 : _google$maps.places); if (!placesLib) { console.error(loadApiErr); return; } asRef.current = new placesLib.AutocompleteService(); setReady(true); }, [googleMapsRef]); var clearSuggestions = useCallback(function () { setSuggestions({ loading: false, status: "", data: [] }); }, []); var clearCache = useCallback(function (key) { if (key === void 0) { key = cacheKey; } try { sessionStorage.removeItem(key); } catch (error) {// Skip exception } }, [cacheKey]); // eslint-disable-next-line react-hooks/exhaustive-deps var fetchPredictions = useCallback(_debounce(function (val) { var _asRef$current; if (!val) { clearSuggestions(); return; } setSuggestions(function (prevState) { return _extends({}, prevState, { loading: true }); }); var cachedData = {}; try { cachedData = JSON.parse(sessionStorage.getItem(cacheKey) || "{}"); } catch (error) {// Skip exception } if (cache) { cachedData = Object.keys(cachedData).reduce(function (acc, key) { if (cachedData[key].maxAge - Date.now() >= 0) acc[key] = cachedData[key]; return acc; }, {}); if (cachedData[val]) { setSuggestions({ loading: false, status: "OK", data: cachedData[val].data }); return; } } (_asRef$current = asRef.current) == null ? void 0 : _asRef$current.getPlacePredictions(_extends({}, requestOptionsRef.current, { input: val }), function (data, status) { setSuggestions({ loading: false, status: status, data: data || [] }); if (cache && status === "OK") { cachedData[val] = { data: data, maxAge: Date.now() + cache * 1000 }; try { sessionStorage.setItem(cacheKey, JSON.stringify(cachedData)); } catch (error) {// Skip exception } } }); }, debounce), [cache, cacheKey, clearSuggestions, requestOptionsRef]); var setValue = useCallback(function (val, shouldFetchData) { if (shouldFetchData === void 0) { shouldFetchData = true; } handleChange(val); if (asRef.current && shouldFetchData) fetchPredictions(val); }, [fetchPredictions, handleChange]); useEffect(function () { if (!initOnMount) return function () { return null; }; var _window2 = window, google = _window2.google; if (!googleMapsRef.current && !(google != null && google.maps) && callbackName) { window[callbackName] = init; } else { init(); } return function () { // @ts-ignore if (window[callbackName]) delete window[callbackName]; }; }, [callbackName, googleMapsRef, init, initOnMount]); return { ready: ready, value: _value, suggestions: suggestions, setValue: setValue, clearSuggestions: clearSuggestions, clearCache: clearCache, init: init }; }; /* eslint-disable compat/compat */ var geocodeErr = "💡 use-places-autocomplete: Please provide an address when using getGeocode() with the componentRestrictions."; var getGeocode = function getGeocode(args) { var geocoder = new window.google.maps.Geocoder(); return new Promise(function (resolve, reject) { geocoder.geocode(args, function (results, status) { if (status !== "OK") reject(status); if (!args.address && args.componentRestrictions) { console.error(geocodeErr); resolve(results); } resolve(results); }); }); }; var getLatLng = function getLatLng(result) { var _result$geometry$loca = result.geometry.location, lat = _result$geometry$loca.lat, lng = _result$geometry$loca.lng; return { lat: lat(), lng: lng() }; }; var getZipCode = function getZipCode(result, useShortName) { var foundZip = result.address_components.find(function (_ref) { var types = _ref.types; return types.includes("postal_code"); }); if (!foundZip) return undefined; return useShortName ? foundZip.short_name : foundZip.long_name; }; var getDetailsErr = "💡 use-places-autocomplete: Please provide a place Id when using getDetails() either as a string or as part of an Autocomplete Prediction."; var getDetails = function getDetails(args) { var PlacesService = new window.google.maps.places.PlacesService(document.createElement("div")); if (!args.placeId) { console.error(getDetailsErr); return Promise.reject(getDetailsErr); } return new Promise(function (resolve, reject) { PlacesService.getDetails(args, function (results, status) { if (status !== "OK") reject(status); resolve(results); }); }); }; export { usePlacesAutocomplete as default, getDetails, getGeocode, getLatLng, getZipCode }; //# sourceMappingURL=index.esm.js.map