UNPKG

react-geolocated

Version:
117 lines (116 loc) 4.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useGeolocated = useGeolocated; const react_1 = require("react"); /** * Hook abstracting away the interaction with the Geolocation API. * @param config - the configuration to use */ function useGeolocated(config = {}) { const { positionOptions = { enableHighAccuracy: true, maximumAge: 0, timeout: Infinity, }, isOptimisticGeolocationEnabled = true, userDecisionTimeout = undefined, suppressLocationOnMount = false, watchPosition = false, geolocationProvider = typeof navigator !== "undefined" ? navigator.geolocation : undefined, watchLocationPermissionChange = false, onError, onSuccess, } = config; const userDecisionTimeoutId = (0, react_1.useRef)(0); const isCurrentlyMounted = (0, react_1.useRef)(true); const watchId = (0, react_1.useRef)(0); const [isGeolocationEnabled, setIsGeolocationEnabled] = (0, react_1.useState)(isOptimisticGeolocationEnabled); const [coords, setCoords] = (0, react_1.useState)(); const [timestamp, setTimestamp] = (0, react_1.useState)(); const [positionError, setPositionError] = (0, react_1.useState)(); const [permissionState, setPermissionState] = (0, react_1.useState)(); const cancelUserDecisionTimeout = (0, react_1.useCallback)(() => { if (userDecisionTimeoutId.current) { window.clearTimeout(userDecisionTimeoutId.current); } }, []); const handlePositionError = (0, react_1.useCallback)((error) => { cancelUserDecisionTimeout(); if (isCurrentlyMounted.current) { setCoords(() => undefined); setIsGeolocationEnabled(false); setPositionError(error); } onError === null || onError === void 0 ? void 0 : onError(error); }, [onError, cancelUserDecisionTimeout]); const handlePositionSuccess = (0, react_1.useCallback)((position) => { cancelUserDecisionTimeout(); if (isCurrentlyMounted.current) { setCoords(position.coords); setTimestamp(position.timestamp); setIsGeolocationEnabled(true); setPositionError(() => undefined); } onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(position); }, [onSuccess, cancelUserDecisionTimeout]); const getPosition = (0, react_1.useCallback)(() => { if (!geolocationProvider || !geolocationProvider.getCurrentPosition || !geolocationProvider.watchPosition) { throw new Error("The provided geolocation provider is invalid"); } if (userDecisionTimeout) { userDecisionTimeoutId.current = window.setTimeout(() => { handlePositionError(); }, userDecisionTimeout); } if (watchPosition) { watchId.current = geolocationProvider.watchPosition(handlePositionSuccess, handlePositionError, positionOptions); } else { geolocationProvider.getCurrentPosition(handlePositionSuccess, handlePositionError, positionOptions); } }, [ geolocationProvider, watchPosition, userDecisionTimeout, handlePositionError, handlePositionSuccess, positionOptions, ]); (0, react_1.useEffect)(() => { let permission; if (watchLocationPermissionChange && geolocationProvider && "permissions" in navigator) { navigator.permissions .query({ name: "geolocation" }) .then((result) => { permission = result; permission.onchange = () => { setPermissionState(permission.state); }; }) .catch((e) => { console.error("Error updating the permissions", e); }); } return () => { if (permission) { permission.onchange = null; } }; }, []); // eslint-disable-line react-hooks/exhaustive-deps (0, react_1.useEffect)(() => { if (!suppressLocationOnMount) { getPosition(); } return () => { cancelUserDecisionTimeout(); if (watchPosition && watchId.current) { geolocationProvider === null || geolocationProvider === void 0 ? void 0 : geolocationProvider.clearWatch(watchId.current); } }; }, [permissionState]); // eslint-disable-line react-hooks/exhaustive-deps return { getPosition, coords, timestamp, isGeolocationEnabled, isGeolocationAvailable: Boolean(geolocationProvider), positionError, }; }