hookify-react
Version:
A collection of optimized and reusable React hooks for state management, dom interaction, responsive design, storage, location, asynchronous management and performance improvements.
829 lines (802 loc) • 28.1 kB
JavaScript
;
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, {
useAdvancedEffect: () => useAdvancedEffect,
useArray: () => useArray,
useClickOutside: () => useClickOutside,
useCopyToClipboard: () => useCopyToClipboard,
useCounter: () => useCounter,
useDebounce: () => useDebounce,
useEventListener: () => useEventListener,
useFormState: () => useFormState,
useGeoLocation: () => useGeoLocation,
useHistory: () => useHistory,
useHover: () => useHover,
useInterval: () => useInterval,
useLocalStorage: () => useLocalStorage,
useOnScreen: () => useOnScreen,
useOnlineStatus: () => useOnlineStatus,
usePress: () => usePress,
usePrevious: () => usePrevious,
useScrollInfo: () => useScrollInfo,
useSessionStorage: () => useSessionStorage,
useSize: () => useSize,
useStorage: () => useStorage,
useTimeout: () => useTimeout,
useToggle: () => useToggle,
useUpdatedEffect: () => useUpdatedEffect,
useWindowSize: () => useWindowSize
});
module.exports = __toCommonJS(index_exports);
// src/hooks/default/useAdvancedEffect.ts
var import_react = require("react");
function useAdvancedEffect(effect, deps) {
const isFirstRender = (0, import_react.useRef)(true);
const previousDepsRef = (0, import_react.useRef)(deps);
(0, import_react.useEffect)(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
previousDepsRef.current = deps;
return;
}
const prevDeps = previousDepsRef.current;
const hasDepsChanged = prevDeps.length !== deps.length || deps.some((dep, i) => !Object.is(dep, prevDeps[i]));
if (hasDepsChanged) {
previousDepsRef.current = deps;
return effect();
}
}, deps);
}
// src/hooks/default/useUpdatedEffect.ts
var import_react2 = require("react");
function useUpdatedEffect(effect, deps) {
const isFirstRender = (0, import_react2.useRef)(true);
(0, import_react2.useEffect)(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
return effect();
}, deps);
}
// src/hooks/state-management/useArray.ts
var import_react3 = require("react");
function useArray(initialValue = []) {
const [state, setState] = (0, import_react3.useState)(initialValue);
const stateRef = (0, import_react3.useRef)(initialValue);
stateRef.current = state;
const initialValueRef = (0, import_react3.useRef)(initialValue);
const push = (0, import_react3.useCallback)((value) => {
setState((prev) => [...prev, value]);
return stateRef.current.length + 1;
}, []);
const pop = (0, import_react3.useCallback)(() => {
const lastElement = stateRef.current[stateRef.current.length - 1];
setState((prev) => prev.slice(0, -1));
return lastElement;
}, []);
const unshift = (0, import_react3.useCallback)((value) => {
setState((prev) => [value, ...prev]);
return stateRef.current.length + 1;
}, []);
const shift = (0, import_react3.useCallback)(() => {
const firstElement = stateRef.current[0];
setState((prev) => prev.slice(1));
return firstElement;
}, []);
const removeByIndex = (0, import_react3.useCallback)((index) => {
setState((prev) => [...prev.slice(0, index), ...prev.slice(index + 1)]);
}, []);
const removeByValue = (0, import_react3.useCallback)((value) => {
setState(
(prev) => prev.filter(
(item) => typeof value === "object" && value !== null ? JSON.stringify(item) !== JSON.stringify(value) : item !== value
)
);
}, []);
const clear = (0, import_react3.useCallback)(() => setState([]), []);
const replace = (0, import_react3.useCallback)((newArray) => setState(newArray), []);
const reset = (0, import_react3.useCallback)(() => setState(initialValueRef.current), []);
const filter = (0, import_react3.useCallback)(
(predicate) => {
setState((prev) => prev.filter(predicate));
},
[]
);
const updateByIndex = (0, import_react3.useCallback)((index, value) => {
setState((prev) => prev.map((item, i) => i === index ? value : item));
}, []);
const updateByValue = (0, import_react3.useCallback)((prevValue, newValue) => {
setState(
(prev) => prev.map((item) => {
if (typeof item !== "object" || item === null) {
return item === prevValue ? newValue : item;
}
return JSON.stringify(item) === JSON.stringify(prevValue) ? newValue : item;
})
);
}, []);
const methods = (0, import_react3.useRef)({
push,
pop,
shift,
unshift,
removeByIndex,
removeByValue,
clear,
filter,
reset,
replace,
updateByIndex,
updateByValue
}).current;
return [state, setState, methods];
}
// src/hooks/state-management/useCounter.ts
var import_react4 = require("react");
function useCounter(initialValue = 0, options = {}) {
const { min, max } = options;
const clamp = (0, import_react4.useCallback)(
(value) => {
let next = value;
if (typeof min === "number") next = Math.max(min, next);
if (typeof max === "number") next = Math.min(max, next);
return next;
},
[min, max]
);
const [count, setCount] = (0, import_react4.useState)(() => clamp(initialValue));
const initialValueRef = (0, import_react4.useRef)(initialValue);
const increment = (0, import_react4.useCallback)(
() => setCount((prev) => clamp(prev + 1)),
[clamp]
);
const incrementByValue = (0, import_react4.useCallback)(
(value) => setCount((prev) => clamp(prev + value)),
[clamp]
);
const decrement = (0, import_react4.useCallback)(
() => setCount((prev) => clamp(prev - 1)),
[clamp]
);
const decrementByValue = (0, import_react4.useCallback)(
(value) => setCount((prev) => clamp(prev - value)),
[clamp]
);
const set = (0, import_react4.useCallback)((value) => setCount(clamp(value)), [clamp]);
const reset = (0, import_react4.useCallback)(
() => setCount(clamp(initialValueRef.current)),
[clamp]
);
return {
count,
increment,
incrementByValue,
decrement,
decrementByValue,
set,
reset
};
}
// src/hooks/state-management/useFormState.ts
var import_react5 = require("react");
function useFormState(defaultValue, predicates, { emptyInputValidation = true } = {}) {
const resolvedDefaultValueRef = (0, import_react5.useRef)(
typeof defaultValue === "function" ? defaultValue() : defaultValue
);
const [state, setStateRaw] = (0, import_react5.useState)(resolvedDefaultValueRef.current);
const [errors, setErrors] = (0, import_react5.useState)(
() => predicates.map((predicate) => predicate(resolvedDefaultValueRef.current))
);
const stateRef = (0, import_react5.useRef)(state);
stateRef.current = state;
const predicatesRef = (0, import_react5.useRef)(predicates);
predicatesRef.current = predicates;
const emptyValidationRef = (0, import_react5.useRef)(emptyInputValidation);
emptyValidationRef.current = emptyInputValidation;
const setValue = (0, import_react5.useCallback)((value) => {
const newValue = typeof value === "function" ? value(stateRef.current) : value;
setStateRaw(newValue);
if (typeof newValue === "string" && newValue.length === 0 && !emptyValidationRef.current) {
setErrors([]);
return;
}
const newErrors = predicatesRef.current.map((p) => p(newValue));
setErrors(
(prevErrors) => prevErrors.length === newErrors.length && prevErrors.every((e, i) => e === newErrors[i]) ? prevErrors : newErrors
);
}, []);
const filteredErrors = (0, import_react5.useMemo)(
() => errors.filter((error) => Boolean(error)),
[errors]
);
const isValid = filteredErrors.length === 0;
const status = (0, import_react5.useMemo)(() => {
if (resolvedDefaultValueRef.current === state && isValid) return "idle";
return isValid ? "valid" : "error";
}, [state, isValid]);
return [
state,
setValue,
{ errors: filteredErrors, isValid, status }
];
}
// src/hooks/state-management/useHistory.ts
var import_react6 = require("react");
function useHistory(defaultValue, { capacity = 10 } = {}) {
const resolvedDefaultValue = typeof defaultValue === "function" ? defaultValue() : defaultValue;
const [state, setState] = (0, import_react6.useState)(resolvedDefaultValue);
const historyRef = (0, import_react6.useRef)([resolvedDefaultValue]);
const pointerRef = (0, import_react6.useRef)(0);
const set = (0, import_react6.useCallback)(
(value) => {
setState((prev) => {
const resolvedValue = typeof value === "function" ? value(prev) : value;
if (historyRef.current[pointerRef.current] !== resolvedValue) {
if (pointerRef.current < historyRef.current.length - 1) {
historyRef.current = historyRef.current.slice(
0,
pointerRef.current + 1
);
}
historyRef.current.push(resolvedValue);
if (historyRef.current.length > capacity) {
historyRef.current.shift();
}
pointerRef.current = historyRef.current.length - 1;
}
return resolvedValue;
});
},
[capacity]
);
const back = (0, import_react6.useCallback)(() => {
if (pointerRef.current > 0) {
pointerRef.current--;
setState(historyRef.current[pointerRef.current]);
}
}, []);
const forward = (0, import_react6.useCallback)(() => {
if (pointerRef.current < historyRef.current.length - 1) {
pointerRef.current++;
setState(historyRef.current[pointerRef.current]);
}
}, []);
const go = (0, import_react6.useCallback)((index) => {
if (index >= 0 && index < historyRef.current.length) {
pointerRef.current = index;
setState(historyRef.current[pointerRef.current]);
}
}, []);
return [
state,
set,
{
history: historyRef.current,
pointer: pointerRef.current,
back,
forward,
go
}
];
}
// src/hooks/state-management/usePrevious.ts
var import_react7 = require("react");
function usePrevious(value) {
const ref = (0, import_react7.useRef)(null);
(0, import_react7.useEffect)(() => {
ref.current = value;
}, [value]);
return ref.current;
}
// src/hooks/state-management/useToggle.ts
var import_react8 = require("react");
function useToggle(initialValue = false) {
const [state, setState] = (0, import_react8.useState)(initialValue);
const toggle = (0, import_react8.useCallback)((value) => {
setState((prev) => typeof value === "boolean" ? value : !prev);
}, []);
return [state, toggle];
}
// src/hooks/async-management/useDebounce.ts
var import_react10 = require("react");
// src/hooks/utils/index.ts
var import_react9 = require("react");
var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
var useIsomorphicLayoutEffect = isBrowser ? import_react9.useLayoutEffect : import_react9.useEffect;
function useLatest(value) {
const ref = (0, import_react9.useRef)(value);
useIsomorphicLayoutEffect(() => {
ref.current = value;
}, [value]);
return ref;
}
// src/hooks/async-management/useDebounce.ts
function useDebounce(callback, delay, deps) {
const callbackRef = useLatest(callback);
(0, import_react10.useEffect)(() => {
const timer = setTimeout(() => callbackRef.current(), delay);
return () => clearTimeout(timer);
}, [...deps, delay]);
}
// src/hooks/async-management/useTimeout.ts
var import_react11 = require("react");
function useTimeout(callback, delay) {
const callbackRef = useLatest(callback);
const timeoutRef = (0, import_react11.useRef)(null);
const clear = (0, import_react11.useCallback)(() => {
if (timeoutRef.current !== null) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
}, []);
const set = (0, import_react11.useCallback)(() => {
clear();
timeoutRef.current = setTimeout(() => {
timeoutRef.current = null;
callbackRef.current();
}, delay);
}, [delay, clear, callbackRef]);
const reset = (0, import_react11.useCallback)(() => {
set();
}, [set]);
(0, import_react11.useEffect)(() => {
set();
return clear;
}, [set, clear]);
return { set, clear, reset };
}
// src/hooks/async-management/useInterval.ts
var import_react12 = require("react");
function useInterval(callback, interval = 1e3) {
const callbackRef = useLatest(callback);
const intervalRef = (0, import_react12.useRef)(null);
const clear = (0, import_react12.useCallback)(() => {
if (intervalRef.current !== null) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
}, []);
(0, import_react12.useEffect)(() => {
if (interval === null) return;
intervalRef.current = setInterval(() => callbackRef.current(), interval);
return () => {
if (intervalRef.current !== null) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
};
}, [interval, callbackRef]);
return { clear };
}
// src/hooks/storage/useStorage.ts
var import_react13 = require("react");
function getStorage(type) {
if (!isBrowser) return null;
try {
return type === "local" ? window.localStorage : window.sessionStorage;
} catch {
return null;
}
}
function useStorage(key, defaultValue, type) {
const readDefault = (0, import_react13.useCallback)(
() => typeof defaultValue === "function" ? defaultValue() : defaultValue,
[defaultValue]
);
const [value, setValue] = (0, import_react13.useState)(() => {
const storage = getStorage(type);
if (storage) {
try {
const stored = storage.getItem(key);
if (stored !== null) return JSON.parse(stored);
} catch (error) {
console.error(`useStorage: failed to read key "${key}"`, error);
}
}
return readDefault();
});
const valueRef = (0, import_react13.useRef)(value);
valueRef.current = value;
(0, import_react13.useEffect)(() => {
const storage = getStorage(type);
if (!storage) return;
try {
if (value === void 0) {
storage.removeItem(key);
} else {
storage.setItem(key, JSON.stringify(value));
}
} catch (error) {
console.error(`useStorage: failed to write key "${key}"`, error);
}
}, [key, value, type]);
(0, import_react13.useEffect)(() => {
if (!isBrowser || type !== "local") return;
const handleStorage = (event) => {
if (event.storageArea !== window.localStorage || event.key !== key) {
return;
}
try {
const next = event.newValue === null ? readDefault() : JSON.parse(event.newValue);
setValue(next);
} catch (error) {
console.error(`useStorage: failed to sync key "${key}"`, error);
}
};
window.addEventListener("storage", handleStorage);
return () => window.removeEventListener("storage", handleStorage);
}, [key, type, readDefault]);
return [value, setValue];
}
function useLocalStorage(key, defaultValue) {
return useStorage(key, defaultValue, "local");
}
function useSessionStorage(key, defaultValue) {
return useStorage(key, defaultValue, "session");
}
// src/hooks/dom/useCopyToClipboard.ts
var import_react14 = require("react");
function useCopyToClipboard(resetDelay = 2e3) {
const [isCopied, setIsCopied] = (0, import_react14.useState)(false);
const [error, setError] = (0, import_react14.useState)(null);
const resetTimerRef = (0, import_react14.useRef)(null);
(0, import_react14.useEffect)(() => {
return () => {
if (resetTimerRef.current !== null) {
clearTimeout(resetTimerRef.current);
}
};
}, []);
const copy = (0, import_react14.useCallback)(
async (text) => {
try {
if (navigator?.clipboard?.writeText) {
await navigator.clipboard.writeText(text);
} else if (typeof document !== "undefined" && typeof document.execCommand === "function") {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed";
textarea.style.opacity = "0";
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
const succeeded = document.execCommand("copy");
document.body.removeChild(textarea);
if (!succeeded) throw new Error("Copy command was unsuccessful");
} else {
throw new Error("Clipboard API not available");
}
setIsCopied(true);
setError(null);
if (resetDelay > 0) {
if (resetTimerRef.current !== null) {
clearTimeout(resetTimerRef.current);
}
resetTimerRef.current = setTimeout(
() => setIsCopied(false),
resetDelay
);
}
return true;
} catch (err) {
setError(err instanceof Error ? err : new Error(String(err)));
setIsCopied(false);
return false;
}
},
[resetDelay]
);
return { copy, isCopied, error };
}
// src/hooks/dom/useEventListener.ts
var import_react15 = require("react");
function useEventListener(eventType, callback, elementRef, options) {
const callbackRef = useLatest(callback);
const optionsRef = (0, import_react15.useRef)(options);
optionsRef.current = options;
(0, import_react15.useEffect)(() => {
const target = elementRef?.current ?? (typeof window !== "undefined" ? window : null);
if (!target?.addEventListener) return;
const currentOptions = optionsRef.current;
const handleEvent = (event) => callbackRef.current(event);
target.addEventListener(eventType, handleEvent, currentOptions);
return () => {
target.removeEventListener(eventType, handleEvent, currentOptions);
};
}, [eventType, elementRef, callbackRef]);
}
// src/hooks/dom/useHover.ts
var import_react16 = require("react");
function useHover() {
const [isHovered, setIsHovered] = (0, import_react16.useState)(false);
const ref = (0, import_react16.useRef)(null);
const handleHover = (0, import_react16.useCallback)(
(event) => setIsHovered(event.type === "mouseenter"),
[]
);
useEventListener("mouseenter", handleHover, ref);
useEventListener("mouseleave", handleHover, ref);
return { ref, isHovered };
}
// src/hooks/dom/useOnClickOutside.ts
var import_react17 = require("react");
function useClickOutside(callback) {
const ref = (0, import_react17.useRef)(null);
const documentRef = (0, import_react17.useRef)(isBrowser ? document : null);
const handleClick = (0, import_react17.useCallback)(
(event) => {
const element = ref.current;
if (!element || element.contains(event.target)) return;
callback(event);
},
[callback]
);
useEventListener("mousedown", handleClick, documentRef);
useEventListener("touchstart", handleClick, documentRef);
return { ref };
}
// src/hooks/dom/useOnlineStatus.ts
var import_react18 = require("react");
function useOnlineStatus() {
const [isOnline, setIsOnline] = (0, import_react18.useState)(
() => isBrowser ? navigator.onLine : true
);
useEventListener("online", () => setIsOnline(true));
useEventListener("offline", () => setIsOnline(false));
return { isOnline, onlineStatus: isOnline ? "online" : "offline" };
}
// src/hooks/dom/useOnScreen.ts
var import_react19 = require("react");
function useOnScreen(options = "0px") {
const {
rootMargin = "0px",
threshold = 0,
once = false
} = typeof options === "string" ? { rootMargin: options } : options;
const [isVisible, setIsVisible] = (0, import_react19.useState)(false);
const ref = (0, import_react19.useRef)(null);
(0, import_react19.useEffect)(() => {
const target = ref.current;
if (!target || typeof IntersectionObserver === "undefined") return;
const observer = new IntersectionObserver(
([entry]) => {
if (!entry) return;
setIsVisible(entry.isIntersecting);
if (entry.isIntersecting && once) observer.disconnect();
},
{ rootMargin, threshold }
);
observer.observe(target);
return () => observer.disconnect();
}, [rootMargin, threshold, once]);
return { ref, isVisible };
}
// src/hooks/dom/usePress.ts
var import_react20 = require("react");
function usePress() {
const [isPressed, setIsPressed] = (0, import_react20.useState)(false);
const ref = (0, import_react20.useRef)(null);
const press = () => setIsPressed(true);
const release = () => setIsPressed(false);
useEventListener("mousedown", press, ref);
useEventListener("touchstart", press, ref);
useEventListener("mouseleave", release, ref);
useEventListener("mouseup", release);
useEventListener("touchend", release);
return { isPressed, ref };
}
// src/hooks/dom/useScrollPosition.ts
var import_react21 = require("react");
function useScrollInfo() {
const ref = (0, import_react21.useRef)(null);
const [scrollData, setScrollData] = (0, import_react21.useState)({
scrollX: 0,
scrollY: 0,
scrollDirection: "none",
isScrolling: false,
scrollProgress: 0
});
const lastScrollY = (0, import_react21.useRef)(0);
const lastScrollX = (0, import_react21.useRef)(0);
const scrollTimeout = (0, import_react21.useRef)(null);
const handleScroll = (0, import_react21.useCallback)(() => {
const element = ref.current;
const metricsSource = element ?? document.documentElement;
const newScrollX = element ? element.scrollLeft : window.scrollX;
const newScrollY = element ? element.scrollTop : window.scrollY;
const maxScrollHeight = metricsSource.scrollHeight - metricsSource.clientHeight;
const scrollPercentage = maxScrollHeight > 0 ? newScrollY / maxScrollHeight * 100 : 0;
const directionX = newScrollX > lastScrollX.current ? "right" : newScrollX < lastScrollX.current ? "left" : "none";
const directionY = newScrollY > lastScrollY.current ? "down" : newScrollY < lastScrollY.current ? "up" : "none";
setScrollData({
scrollX: newScrollX,
scrollY: newScrollY,
scrollDirection: directionY !== "none" ? directionY : directionX,
isScrolling: true,
scrollProgress: scrollPercentage
});
lastScrollX.current = newScrollX;
lastScrollY.current = newScrollY;
if (scrollTimeout.current) clearTimeout(scrollTimeout.current);
scrollTimeout.current = setTimeout(() => {
setScrollData((prev) => ({ ...prev, isScrolling: false }));
}, 150);
}, []);
(0, import_react21.useEffect)(() => {
const target = ref.current ?? window;
target.addEventListener("scroll", handleScroll, { passive: true });
return () => {
target.removeEventListener("scroll", handleScroll);
if (scrollTimeout.current) {
clearTimeout(scrollTimeout.current);
scrollTimeout.current = null;
}
};
}, [handleScroll]);
return { ref, ...scrollData };
}
// src/hooks/dom/useSize.ts
var import_react22 = require("react");
function useSize() {
const ref = (0, import_react22.useRef)(null);
const [size, setSize] = (0, import_react22.useState)(null);
const updateSize = (0, import_react22.useCallback)((entries) => {
const entry = entries[0];
if (!entry) return;
const { width, height, top, left, bottom, right } = entry.contentRect;
setSize({ width, height, top, left, bottom, right });
}, []);
(0, import_react22.useEffect)(() => {
const element = ref.current;
if (!element || typeof ResizeObserver === "undefined") return;
const rect = element.getBoundingClientRect();
setSize({
width: rect.width,
height: rect.height,
top: rect.top,
left: rect.left,
bottom: rect.bottom,
right: rect.right
});
const observer = new ResizeObserver(updateSize);
observer.observe(element);
return () => observer.disconnect();
}, [updateSize]);
return { ref, size };
}
// src/hooks/dom/useWindowSize.ts
var import_react23 = require("react");
function useWindowSize() {
const isSSR = typeof window === "undefined";
const [size, setSize] = (0, import_react23.useState)({
width: isSSR ? 0 : window.innerWidth,
height: isSSR ? 0 : window.innerHeight
});
const updateSize = (0, import_react23.useCallback)(() => {
setSize({ width: window.innerWidth, height: window.innerHeight });
}, []);
(0, import_react23.useLayoutEffect)(() => {
if (isSSR) return;
updateSize();
window.addEventListener("resize", updateSize);
return () => {
window.removeEventListener("resize", updateSize);
};
}, [isSSR, updateSize]);
return size;
}
// src/hooks/location/useGeoLocation.ts
var import_react24 = require("react");
function useGeoLocation(options = {}) {
const {
enableHighAccuracy = false,
maximumAge = 0,
timeout = 1e4,
retryLimit = 3,
retryDelay = 2e3
} = options;
const [loading, setLoading] = (0, import_react24.useState)(true);
const [error, setError] = (0, import_react24.useState)(null);
const [coords, setCoords] = (0, import_react24.useState)(null);
const retriesRef = (0, import_react24.useRef)(0);
const watchIdRef = (0, import_react24.useRef)(null);
const retryTimerRef = (0, import_react24.useRef)(null);
(0, import_react24.useEffect)(() => {
if (typeof navigator === "undefined" || !navigator.geolocation) {
setError({
code: 0,
message: "Geolocation is not supported by this browser."
});
setLoading(false);
return;
}
let cancelled = false;
retriesRef.current = 0;
const fetchLocation = () => {
if (cancelled) return;
setLoading(true);
const successCallback = (position) => {
if (cancelled) return;
setCoords(position.coords);
setError(null);
setLoading(false);
retriesRef.current = 0;
};
const errorCallback = (positionError) => {
if (cancelled) return;
setError({ code: positionError.code, message: positionError.message });
if (retriesRef.current < retryLimit) {
retriesRef.current += 1;
retryTimerRef.current = setTimeout(fetchLocation, retryDelay);
} else {
setLoading(false);
}
};
watchIdRef.current = navigator.geolocation.watchPosition(
successCallback,
errorCallback,
{ enableHighAccuracy, maximumAge, timeout }
);
};
fetchLocation();
return () => {
cancelled = true;
if (watchIdRef.current !== null) {
navigator.geolocation.clearWatch(watchIdRef.current);
watchIdRef.current = null;
}
if (retryTimerRef.current !== null) {
clearTimeout(retryTimerRef.current);
retryTimerRef.current = null;
}
};
}, [enableHighAccuracy, maximumAge, timeout, retryLimit, retryDelay]);
return { loading, error, coords };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
useAdvancedEffect,
useArray,
useClickOutside,
useCopyToClipboard,
useCounter,
useDebounce,
useEventListener,
useFormState,
useGeoLocation,
useHistory,
useHover,
useInterval,
useLocalStorage,
useOnScreen,
useOnlineStatus,
usePress,
usePrevious,
useScrollInfo,
useSessionStorage,
useSize,
useStorage,
useTimeout,
useToggle,
useUpdatedEffect,
useWindowSize
});