rooks
Version:
Essential React custom hooks ⚓ to super charge your components!
1,645 lines (1,585 loc) • 119 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
useArrayState: () => useArrayState,
useAsyncEffect: () => useAsyncEffect,
useAudio: () => useAudio,
useBoundingclientrect: () => useBoundingclientrect,
useBoundingclientrectRef: () => useBoundingclientrectRef,
useCountdown: () => useCountdown,
useCounter: () => useCounter,
useDebounce: () => useDebounce,
useDebounceFn: () => useDebounceFn,
useDebouncedValue: () => useDebouncedValue,
useDeepCompareEffect: () => useDeepCompareEffect,
useDidMount: () => useDidMount,
useDidUpdate: () => useDidUpdate,
useDimensionsRef: () => useDimensionsRef,
useDocumentEventListener: () => useDocumentEventListener,
useDocumentTitle: () => useDocumentTitle,
useDocumentVisibilityState: () => useDocumentVisibilityState,
useEffectOnceWhen: () => useEffectOnceWhen,
useEventListenerRef: () => useEventListenerRef,
useFileDropRef: () => useFileDropRef,
useFocus: () => useFocus,
useFocusWithin: () => useFocusWithin,
useForkRef: () => useForkRef,
useFreshCallback: () => useFreshCallback,
useFreshRef: () => useFreshRef,
useFreshTick: () => useFreshTick,
useFullscreen: () => useFullscreen,
useGeolocation: () => useGeolocation,
useGetIsMounted: () => useGetIsMounted,
useInViewRef: () => useInViewRef,
useInput: () => useInput,
useIntersectionObserverRef: () => useIntersectionObserverRef,
useIntervalWhen: () => useIntervalWhen,
useIsDroppingFiles: () => useIsDroppingFiles,
useIsomorphicEffect: () => useIsomorphicEffect,
useKey: () => useKey,
useKeyBindings: () => useKeyBindings,
useKeyRef: () => useKeyRef,
useKeys: () => useKeys,
useLifecycleLogger: () => useLifecycleLogger,
useLocalstorageState: () => useLocalstorageState,
useLockBodyScroll: () => useLockBodyScroll,
useMapState: () => useMapState,
useMediaMatch: () => useMediaMatch,
useMergeRefs: () => useMergeRefs,
useMouse: () => useMouse,
useMouseMoveDelta: () => useMouseMoveDelta,
useMouseWheelDelta: () => useMouseWheelDelta,
useMultiSelectableList: () => useMultiSelectableList,
useMutationObserver: () => useMutationObserver,
useMutationObserverRef: () => useMutationObserverRef,
useNativeMapState: () => useNativeMapState,
useNavigatorLanguage: () => useNavigatorLanguage,
useObjectState: () => useMapState,
useOnClickRef: () => useOnClickRef,
useOnHoverRef: () => useOnHoverRef,
useOnLongHover: () => useOnLongHover,
useOnLongHoverRef: () => useOnLongHover,
useOnLongPress: () => useOnLongPress,
useOnLongPressRef: () => useOnLongPress,
useOnWindowResize: () => useOnWindowResize,
useOnWindowScroll: () => useOnWindowScroll,
useOnline: () => useOnline,
useOrientation: () => useOrientation,
useOutsideClick: () => useOutsideClick,
useOutsideClickRef: () => useOutsideClickRef,
usePreviousDifferent: () => usePreviousDifferent,
usePreviousImmediate: () => usePreviousImmediate,
usePromise: () => usePromise,
useQueueState: () => useQueueState,
useRaf: () => useRaf,
useRefElement: () => useRefElement,
useRenderCount: () => useRenderCount,
useResizeObserverRef: () => useResizeObserverRef,
useSafeSetState: () => useSafeSetState,
useSelect: () => useSelect,
useSelectableList: () => useSelectableList,
useSessionstorageState: () => useSessionstorageState,
useSetState: () => useSetState,
useSpeech: () => useSpeech,
useStackState: () => useStackState,
useThrottle: () => useThrottle,
useTimeTravelState: () => useTimeTravelState,
useTimeoutWhen: () => useTimeoutWhen,
useToggle: () => useToggle,
useUndoRedoState: () => useUndoRedoState,
useUndoState: () => useUndoState,
useVibrate: () => useVibrate,
useVideo: () => useVideo,
useWhyDidYouUpdate: () => useWhyDidYouUpdate,
useWillUnmount: () => useWillUnmount,
useWindowEventListener: () => useWindowEventListener,
useWindowScrollPosition: () => useWindowScrollPosition,
useWindowSize: () => useWindowSize
});
module.exports = __toCommonJS(index_exports);
// src/hooks/useOnLongHover.ts
var import_react5 = require("react");
// src/hooks/useFreshCallback.ts
var import_react3 = require("react");
// src/hooks/useFreshRef.ts
var import_react2 = require("react");
// src/hooks/useIsomorphicEffect.ts
var import_react = require("react");
var useIsomorphicEffect = typeof window === "undefined" ? import_react.useEffect : import_react.useLayoutEffect;
// src/hooks/useFreshRef.ts
function useFreshRef(value, preferLayoutEffect = false) {
const useEffectToUse = preferLayoutEffect ? useIsomorphicEffect : import_react2.useEffect;
const ref = (0, import_react2.useRef)(value);
useEffectToUse(() => {
ref.current = value;
});
return ref;
}
// src/hooks/useFreshCallback.ts
function useFreshCallback(callback) {
const freshRef = useFreshRef(callback);
const tick = (0, import_react3.useCallback)(
(...args) => {
return freshRef.current(...args);
},
[freshRef]
);
return tick;
}
// src/hooks/useTimeoutWhen.ts
var import_react4 = require("react");
// src/utils/noop.ts
var noop = () => {
};
// src/hooks/useTimeoutWhen.ts
function useTimeoutWhen(callback, timeoutDelayMs = 0, when = true, key = 0) {
const freshCallback = useFreshCallback(callback);
(0, import_react4.useEffect)(() => {
if (when) {
let internalCallback2 = function() {
freshCallback();
};
var internalCallback = internalCallback2;
if (typeof window !== "undefined") {
const timeout = window.setTimeout(internalCallback2, timeoutDelayMs);
return () => {
window.clearTimeout(timeout);
};
} else {
console.warn("useTimeoutWhen: window is undefined.");
}
}
return noop;
}, [timeoutDelayMs, when, key, freshCallback]);
}
// src/hooks/useOnLongHover.ts
var useOnLongHover = (callback, { duration = 300 } = {}) => {
const [targetNode, setTargetNode] = (0, import_react5.useState)(null);
const ref = (0, import_react5.useCallback)((node) => {
setTargetNode(node);
}, []);
const [isHovering, setIsHovering] = (0, import_react5.useState)(false);
const freshCallback = useFreshCallback(callback);
useTimeoutWhen(
() => {
freshCallback();
},
duration,
isHovering
);
const start = (0, import_react5.useCallback)(() => {
setIsHovering(true);
}, []);
const handleOnMouseLeave = (0, import_react5.useCallback)((_) => {
setIsHovering(false);
}, []);
(0, import_react5.useEffect)(() => {
if (targetNode) {
targetNode.addEventListener("mouseenter", start);
targetNode.addEventListener("mouseleave", handleOnMouseLeave);
}
return () => {
if (targetNode) {
targetNode.removeEventListener("mouseenter", start);
targetNode.removeEventListener("mouseleave", handleOnMouseLeave);
}
};
}, [start, handleOnMouseLeave, targetNode]);
return ref;
};
// src/hooks/useOnLongPress.ts
var import_react6 = require("react");
var defaultOnClick = () => {
};
var useOnLongPress = (callback, { onClick, duration = 300 } = {}) => {
const [targetNode, setTargetNode] = (0, import_react6.useState)(null);
const ref = (0, import_react6.useCallback)((node) => {
setTargetNode(node);
}, []);
const [isPressing, setIsPressing] = (0, import_react6.useState)(false);
const freshCallback = useFreshCallback(callback);
const freshClick = useFreshCallback(onClick ?? defaultOnClick);
useTimeoutWhen(freshCallback, duration, isPressing);
const start = (0, import_react6.useCallback)((_) => {
setIsPressing(true);
}, []);
const handleOnClick = (0, import_react6.useCallback)(
(event) => {
setIsPressing(false);
freshClick(event);
},
[freshClick]
);
(0, import_react6.useEffect)(() => {
if (targetNode) {
targetNode.addEventListener("mousedown", start);
targetNode.addEventListener("mouseup", handleOnClick);
targetNode.addEventListener("mouseleave", handleOnClick);
targetNode.addEventListener("touchstart", start);
targetNode.addEventListener("touchend", handleOnClick);
targetNode.addEventListener("touchcancel", handleOnClick);
}
return () => {
if (targetNode) {
targetNode.removeEventListener("mousedown", start);
targetNode.removeEventListener("mouseup", handleOnClick);
targetNode.removeEventListener("mouseleave", handleOnClick);
targetNode.removeEventListener("touchstart", start);
targetNode.removeEventListener("touchend", handleOnClick);
targetNode.removeEventListener("touchcancel", handleOnClick);
}
};
}, [start, handleOnClick, targetNode]);
return ref;
};
// src/hooks/useMapState.ts
var import_react7 = require("react");
function useMapState(initialValue) {
const [map, setMap] = (0, import_react7.useState)(initialValue);
const set = (0, import_react7.useCallback)((key, value) => {
setMap((currentMap) => ({
...currentMap,
[key]: value
}));
}, []);
const has = (0, import_react7.useCallback)(
(key) => {
return typeof map[key] !== "undefined";
},
[map]
);
const setMultiple = (0, import_react7.useCallback)((nextMap) => {
setMap((currentMap) => ({
...currentMap,
...nextMap
}));
}, []);
const removeMultiple = (0, import_react7.useCallback)(
(...keys) => {
setMap((currentMap) => {
const nextMap = { ...currentMap };
for (const key of keys) {
delete nextMap[key];
}
return nextMap;
});
},
[setMap]
);
const remove = (0, import_react7.useCallback)(
(key) => {
setMap((currentMap) => {
const nextMap = { ...currentMap };
delete nextMap[key];
return nextMap;
});
},
[setMap]
);
const removeAll = (0, import_react7.useCallback)(() => {
setMap((currentMap) => {
const nextMap = { ...currentMap };
for (const key in nextMap) {
if (nextMap.hasOwnProperty(key)) {
delete nextMap[key];
}
}
return nextMap;
});
}, [setMap]);
return [
map,
{
has,
remove,
removeAll,
removeMultiple,
set,
setMultiple
}
];
}
// src/hooks/useArrayState.ts
var import_react8 = require("react");
function useArrayState(initial) {
const [array, setArray] = (0, import_react8.useState)(initial ?? []);
const push = (0, import_react8.useCallback)(
(value) => {
setArray([...array, value]);
},
[array]
);
const pop = (0, import_react8.useCallback)(() => {
setArray(array.slice(0, array.length - 1));
}, [array]);
const clear = (0, import_react8.useCallback)(() => {
setArray([]);
}, []);
const unshift = (0, import_react8.useCallback)(
(value) => {
setArray([value, ...array]);
},
[array]
);
const shift = (0, import_react8.useCallback)(() => {
setArray(array.slice(1));
}, [array]);
const reverse = (0, import_react8.useCallback)(() => {
setArray([...array].reverse());
}, [array]);
const concat = (0, import_react8.useCallback)(
(value) => {
setArray([...array, ...value]);
},
[array]
);
const fill = (0, import_react8.useCallback)(
(value, start, end) => {
setArray([...array].fill(value, start, end));
},
[array]
);
const updateItemAtIndex = (0, import_react8.useCallback)(
(index, value) => {
setArray((prevArray) => {
const newArray = [...prevArray];
newArray[index] = value;
return newArray;
});
},
[setArray]
);
const splice = (0, import_react8.useCallback)(
(...args) => {
setArray((prevArray) => {
const newArray = [...prevArray];
newArray.splice(...args);
return newArray;
});
},
[setArray]
);
const removeItemAtIndex = (0, import_react8.useCallback)(
(index) => {
setArray((prevArray) => {
const newArray = [...prevArray];
newArray.splice(index, 1);
return newArray;
});
},
[setArray]
);
const replaceItemAtIndex = (0, import_react8.useCallback)(
(index, value) => {
setArray((prevArray) => {
const newArray = [...prevArray];
newArray.splice(index, 1, value);
return newArray;
});
},
[setArray]
);
const insertItemAtIndex = (0, import_react8.useCallback)(
(index, value) => {
setArray((prevArray) => {
const newArray = [...prevArray];
newArray.splice(index, 0, value);
return newArray;
});
},
[setArray]
);
const sort = (0, import_react8.useCallback)(
(compareFn) => {
setArray([...array].sort(compareFn));
},
[array]
);
const controls = (0, import_react8.useMemo)(() => {
return {
push,
pop,
clear,
unshift,
shift,
reverse,
concat,
fill,
updateItemAtIndex,
setArray,
splice,
removeItemAtIndex,
replaceItemAtIndex,
insertItemAtIndex,
sort
};
}, [
push,
pop,
clear,
unshift,
shift,
reverse,
concat,
fill,
updateItemAtIndex,
setArray,
splice,
removeItemAtIndex,
replaceItemAtIndex,
insertItemAtIndex,
sort
]);
const returnValue = (0, import_react8.useMemo)(() => {
return [array, controls];
}, [array, controls]);
return returnValue;
}
// src/hooks/useAsyncEffect.ts
var import_react10 = require("react");
// src/hooks/useGetIsMounted.ts
var import_react9 = require("react");
var useGetIsMounted = () => {
const isMountedRef = (0, import_react9.useRef)(false);
const get = (0, import_react9.useCallback)(() => isMountedRef.current, []);
(0, import_react9.useEffect)(() => {
isMountedRef.current = true;
return () => {
isMountedRef.current = false;
};
}, []);
return get;
};
// src/hooks/useAsyncEffect.ts
function useAsyncEffect(effect, deps, cleanup) {
const lastCallId = (0, import_react10.useRef)(0);
const getIsMounted = useGetIsMounted();
const effectRef = useFreshRef(effect);
const callback = (0, import_react10.useCallback)(async () => {
const callId = ++lastCallId.current;
const shouldContinueEffect = () => {
return getIsMounted() && callId === lastCallId.current;
};
try {
return await effectRef.current(shouldContinueEffect);
} catch (error) {
throw error;
}
}, [getIsMounted, ...deps]);
(0, import_react10.useEffect)(() => {
let result;
callback().then((value) => {
result = value;
});
return () => {
cleanup?.(result);
};
}, [callback, cleanup]);
}
// src/hooks/useAudio.ts
var import_react11 = require("react");
var noop2 = () => {
};
function useAudio(options = {}, callbacks = {}) {
const { autoPlay = false, isMuted: initialIsMuted = false } = options;
const [isPlaying, setIsPlaying] = (0, import_react11.useState)(autoPlay);
const [isMuted, setIsMuted] = (0, import_react11.useState)(initialIsMuted);
const [audioNode, setAudioNode] = (0, import_react11.useState)(null);
const onPlay = useFreshCallback(callbacks.onPlay ?? noop2);
const onPause = useFreshCallback(callbacks.onPause ?? noop2);
const onMute = useFreshCallback(callbacks.onMute ?? noop2);
const onUnmute = useFreshCallback(callbacks.onUnmute ?? noop2);
const onLoadedMetadata = useFreshCallback(callbacks.onLoadedMetadata ?? noop2);
const audioCallbackRef = (node) => {
if (node !== null) {
setAudioNode(node);
}
};
(0, import_react11.useEffect)(() => {
if (!audioNode) return;
if (isPlaying) {
audioNode.play();
} else {
audioNode.pause();
}
}, [audioNode, isPlaying]);
(0, import_react11.useEffect)(() => {
if (!audioNode) return;
audioNode.muted = isMuted;
}, [audioNode, isMuted]);
(0, import_react11.useEffect)(() => {
if (!audioNode) return;
const handleLoadedMetadata = () => {
if (autoPlay) {
audioNode?.play();
}
onLoadedMetadata();
};
const handlePlay = () => {
onPlay();
};
const handlePause = () => {
onPause();
};
const handleEnded = () => {
setIsPlaying(false);
};
audioNode?.addEventListener("loadedmetadata", handleLoadedMetadata);
audioNode?.addEventListener("play", handlePlay);
audioNode?.addEventListener("pause", handlePause);
audioNode?.addEventListener("ended", handleEnded);
return () => {
audioNode?.removeEventListener("loadedmetadata", handleLoadedMetadata);
audioNode?.removeEventListener("play", handlePlay);
audioNode?.removeEventListener("pause", handlePause);
audioNode?.removeEventListener("ended", handleEnded);
};
}, [autoPlay, onLoadedMetadata, onPlay, onPause, audioNode]);
const play = () => {
setIsPlaying(true);
};
const pause = () => {
setIsPlaying(false);
};
const togglePlay = () => {
setIsPlaying(!isPlaying);
};
const mute = () => {
setIsMuted(true);
onMute();
};
const unmute = () => {
setIsMuted(false);
onUnmute();
};
const toggleMute = () => {
if (isMuted) {
unmute();
} else {
mute();
}
};
const controls = {
play,
pause,
togglePlay,
mute,
unmute,
toggleMute
};
const state = {
isPlaying,
isMuted
};
return [audioCallbackRef, state, controls];
}
// src/hooks/useBoundingclientrect.ts
var import_react14 = require("react");
// src/hooks/useDidMount.ts
var import_react12 = require("react");
function useDidMount(callback) {
(0, import_react12.useEffect)(() => {
if (typeof callback === "function") {
callback();
}
}, []);
}
// src/hooks/useMutationObserver.ts
var import_react13 = require("react");
var config = {
attributes: true,
characterData: true,
childList: true,
subtree: true
};
function useMutationObserver(ref, callback, options = config) {
(0, import_react13.useEffect)(() => {
if (ref.current) {
const observer = new MutationObserver(callback);
observer.observe(ref.current, options);
return () => {
observer.disconnect();
};
}
return noop;
}, [callback, options, ref]);
}
// src/hooks/useBoundingclientrect.ts
function getBoundingClientRect(element) {
return element.getBoundingClientRect();
}
function useBoundingclientrect(ref) {
const [domRect, setDomRect] = (0, import_react14.useState)(null);
const update = (0, import_react14.useCallback)(() => {
setDomRect(ref.current ? getBoundingClientRect(ref.current) : null);
}, [ref]);
useDidMount(() => {
update();
});
useMutationObserver(ref, update);
return domRect;
}
// src/hooks/useBoundingclientrectRef.ts
var import_react17 = require("react");
// src/hooks/useForkRef.ts
var import_react15 = require("react");
function setRef(ref, value) {
if (typeof ref === "function") {
ref(value);
} else if (ref !== null && ref !== void 0) {
ref.current = value;
}
}
function useForkRef(refA, refB) {
return (0, import_react15.useMemo)(() => {
if (refA === null && refB === null) {
return null;
}
return (refValue) => {
setRef(refA, refValue);
setRef(refB, refValue);
};
}, [refA, refB]);
}
// src/hooks/useMutationObserverRef.ts
var import_react16 = require("react");
var config2 = {
attributes: true,
characterData: true,
childList: true,
subtree: true
};
function useMutationObserverRef(callback, options = config2) {
const [node, setNode] = (0, import_react16.useState)(null);
(0, import_react16.useEffect)(() => {
if (node) {
const observer = new MutationObserver(callback);
observer.observe(node, options);
return () => {
observer.disconnect();
};
}
return noop;
}, [node, callback, options]);
const ref = (0, import_react16.useCallback)((nodeElement) => {
setNode(nodeElement);
}, []);
return [ref];
}
// src/hooks/useBoundingclientrectRef.ts
function getBoundingClientRect2(element) {
return element.getBoundingClientRect();
}
function useBoundingclientrectRef() {
const [domRect, setDomRect] = (0, import_react17.useState)(null);
const [node, setNode] = (0, import_react17.useState)(null);
const update = (0, import_react17.useCallback)(() => {
setDomRect(node ? getBoundingClientRect2(node) : null);
}, [node]);
(0, import_react17.useEffect)(() => {
update();
}, [update]);
const ref = (0, import_react17.useCallback)((nodeElement) => {
setNode(nodeElement);
}, []);
const [mutationObserverRef] = useMutationObserverRef(update);
const forkedRef = useForkRef(ref, mutationObserverRef);
return [forkedRef, domRect, update];
}
// src/hooks/useCountdown.ts
var import_react19 = require("react");
// src/hooks/useIntervalWhen.ts
var import_react18 = require("react");
function useIntervalWhen(callback, intervalDurationMs = 0, when = true, startImmediate = false) {
const savedRefCallback = (0, import_react18.useRef)(void 0);
(0, import_react18.useEffect)(() => {
savedRefCallback.current = callback;
});
(0, import_react18.useEffect)(() => {
if (when) {
let internalCallback2 = function() {
savedRefCallback.current?.();
};
var internalCallback = internalCallback2;
if (startImmediate) {
internalCallback2();
}
const interval = window.setInterval(internalCallback2, intervalDurationMs);
return () => {
window.clearInterval(interval);
};
}
return noop;
}, [when, intervalDurationMs, startImmediate]);
}
// src/hooks/useCountdown.ts
function useCountdown(endTime, options = {}) {
const { interval = 1e3, onDown, onEnd } = options;
const [time, setTime] = (0, import_react19.useState)(() => /* @__PURE__ */ new Date());
const restTime = endTime.getTime() - time.getTime();
const count = restTime > 0 ? Math.ceil(restTime / interval) : 0;
useIntervalWhen(onTick, count ? interval : void 0, true, true);
return count;
function onTick() {
const newTime = /* @__PURE__ */ new Date();
if (newTime > endTime) {
if (onEnd) {
onEnd(newTime);
}
setTime(endTime);
return;
}
if (onDown) {
onDown(restTime, newTime);
}
setTime(newTime);
}
}
// src/hooks/useCounter.ts
var import_react20 = require("react");
function useCounter(initialValue) {
const [counter, setCounter] = (0, import_react20.useState)(initialValue);
const incrementBy = (0, import_react20.useCallback)((incrAmount) => {
setCounter((currentCounter) => currentCounter + incrAmount);
}, []);
const decrementBy = (0, import_react20.useCallback)(
(decrAmount) => {
incrementBy(-decrAmount);
},
[incrementBy]
);
const increment = (0, import_react20.useCallback)(() => {
incrementBy(1);
}, [incrementBy]);
const decrement = (0, import_react20.useCallback)(() => {
incrementBy(-1);
}, [incrementBy]);
const reset = (0, import_react20.useCallback)(() => {
setCounter(initialValue);
}, [initialValue]);
return {
decrement,
decrementBy,
increment,
incrementBy,
reset,
value: counter
};
}
// src/hooks/useDebounce.ts
var import_lodash = __toESM(require("lodash.debounce"));
var import_react22 = require("react");
// src/hooks/useWillUnmount.ts
var import_react21 = require("react");
function useWillUnmount(callback) {
(0, import_react21.useEffect)(() => {
return callback;
}, []);
}
// src/hooks/useDebounce.ts
function useDebounce(callback, wait, options) {
const createDebouncedCallback = (0, import_react22.useCallback)(
(function_) => {
return (0, import_lodash.default)(function_, wait, options);
},
[wait, options]
);
const freshCallback = useFreshRef(callback);
function tick(...args) {
freshCallback.current?.(...args);
}
const debouncedCallbackRef = (0, import_react22.useRef)(
createDebouncedCallback(tick)
);
useWillUnmount(() => {
debouncedCallbackRef.current?.cancel();
});
return debouncedCallbackRef.current;
}
// src/hooks/useDebounceFn.ts
var import_react23 = require("react");
function useDebounceFn(func, delay, options = { leading: false, trailing: true }) {
const { leading, trailing, maxWait } = options;
if (!leading && !trailing) {
throw new Error("leading and trailing cannot both be false");
} else if (typeof maxWait !== "undefined" && maxWait < delay) {
throw new Error("maxWait cannot be less than delay");
}
const funcRef = useFreshCallback(func);
const [isTimeoutEnabled, setIsTimeoutEnabled] = (0, import_react23.useState)(false);
const [key, setKey] = (0, import_react23.useState)(0);
const lastExecutionTimeRef = (0, import_react23.useRef)(0);
const argsRef = (0, import_react23.useRef)(void 0);
const debouncedFn = (0, import_react23.useCallback)(
(...args) => {
argsRef.current = args;
const overrideTimeout = typeof maxWait !== "undefined" && lastExecutionTimeRef.current && Date.now() - lastExecutionTimeRef.current > maxWait;
if (leading) {
if (isTimeoutEnabled && overrideTimeout) {
setKey((prevKey) => prevKey + 1);
lastExecutionTimeRef.current = Date.now();
try {
funcRef(...args);
} catch (error) {
console.warn(error);
}
} else if (overrideTimeout && !isTimeoutEnabled) {
setIsTimeoutEnabled(true);
lastExecutionTimeRef.current = Date.now();
try {
funcRef(...args);
} catch (error) {
console.warn(error);
}
} else if (isTimeoutEnabled && !overrideTimeout) {
} else {
setIsTimeoutEnabled(true);
lastExecutionTimeRef.current = Date.now();
try {
funcRef(...args);
} catch (error) {
console.warn(error);
}
}
}
if (trailing) {
if (isTimeoutEnabled) {
setKey((prevKey) => prevKey + 1);
} else {
setIsTimeoutEnabled(true);
}
}
},
[maxWait, isTimeoutEnabled, leading, trailing, funcRef]
);
useTimeoutWhen(
() => {
if (typeof maxWait !== "undefined" && trailing) {
if (!argsRef.current) return;
lastExecutionTimeRef.current = Date.now();
try {
funcRef(...argsRef.current);
} catch (error) {
console.warn(error);
}
}
},
maxWait ?? Infinity,
isTimeoutEnabled && typeof maxWait !== "undefined" && trailing,
key
);
useTimeoutWhen(
() => {
if (trailing) {
if (!argsRef.current) return;
lastExecutionTimeRef.current = Date.now();
try {
funcRef(...argsRef.current);
} catch (error) {
console.warn(error);
}
}
setIsTimeoutEnabled(false);
},
delay,
isTimeoutEnabled && trailing,
key
);
const freshDebouncedFn = useFreshCallback(debouncedFn);
return [freshDebouncedFn, isTimeoutEnabled];
}
// src/hooks/useDebouncedValue.ts
var import_react25 = require("react");
// src/hooks/useDidUpdate.ts
var import_react24 = require("react");
function useDidUpdate(callback, conditions) {
const hasMountedRef = (0, import_react24.useRef)(false);
const internalConditions = (0, import_react24.useMemo)(() => {
if (typeof conditions !== "undefined" && !Array.isArray(conditions)) {
return [conditions];
} else if (Array.isArray(conditions) && conditions.length === 0) {
console.warn(
"Using [] as the second argument makes useDidUpdate a noop. The second argument should either be `undefined` or an array of length greater than 0."
);
}
return conditions;
}, [conditions]);
(0, import_react24.useEffect)(() => {
if (hasMountedRef.current) {
callback();
}
}, internalConditions);
useDidMount(() => {
hasMountedRef.current = true;
});
useWillUnmount(() => {
hasMountedRef.current = false;
});
}
// src/hooks/useDebouncedValue.ts
var defaultUseDebounceValueOptions = {
initializeWithNull: false
};
var useDebouncedValue = (value, timeout, options = {}) => {
const { initializeWithNull } = Object.assign(
{},
defaultUseDebounceValueOptions,
options
);
const [updatedValue, setUpdatedValue] = (0, import_react25.useState)(
initializeWithNull ? null : value
);
const debouncedSetUpdatedValue = useDebounce(setUpdatedValue, timeout);
useDidMount(() => {
if (initializeWithNull) {
debouncedSetUpdatedValue(value);
}
});
useDidUpdate(() => {
debouncedSetUpdatedValue(value);
}, [value]);
return [updatedValue, setUpdatedValue];
};
// src/hooks/useDeepCompareEffect.ts
var import_react26 = require("react");
var import_fast_deep_equal = __toESM(require("fast-deep-equal"));
// src/hooks/warning.ts
var isDevelopmentEnvironment = process.env.NODE_ENV !== "production";
var warning = () => {
};
if (isDevelopmentEnvironment) {
const printWarning = (actualMessage) => {
const message = `Warning: ${actualMessage}`;
if (typeof console !== "undefined") {
console.error(message);
}
try {
throw new Error(message);
} catch {
}
};
warning = function(condition, actualMessage) {
if (!condition) {
printWarning(actualMessage);
}
};
}
// src/hooks/useDeepCompareEffect.ts
function isPrimitive(value) {
const valueType = typeof value;
return valueType === "string" || valueType === "number" || valueType === "bigint" || valueType === "boolean" || valueType === "undefined" || valueType === "symbol";
}
function useDeepCompareEffect(callback, dependencies) {
const previousDeps = (0, import_react26.useRef)(dependencies);
if (!Array.isArray(dependencies)) {
throw new Error(
"useDeepCompareEffect should be used with an array of dependencies"
);
}
const hasPrimitives = dependencies.every(isPrimitive);
warning(
!hasPrimitives,
"useDeepCompareEffect should not be used with primitive values as dependencies"
);
if (!(0, import_fast_deep_equal.default)(previousDeps.current, dependencies)) {
previousDeps.current = dependencies;
}
(0, import_react26.useEffect)(callback, previousDeps.current);
}
// src/hooks/useDimensionsRef.ts
var import_react28 = require("react");
// src/hooks/useGlobalObjectEventListener.ts
var import_react27 = require("react");
// src/hooks/useFreshTick.ts
function useFreshTick(callback) {
const freshRef = useFreshRef(callback);
function tick(...args) {
if (typeof freshRef.current === "function") {
freshRef.current(...args);
}
}
return tick;
}
// src/hooks/useGlobalObjectEventListener.ts
function useGlobalObjectEventListener(globalObject, eventName, callback, listenerOptions = {}, when = true, isLayoutEffect = false) {
const freshCallback = useFreshTick(callback);
const useEffectToRun = isLayoutEffect ? useIsomorphicEffect : import_react27.useEffect;
useEffectToRun(() => {
warning(
typeof globalObject !== "undefined",
"[useGlobalObjectEventListener]: Cannot attach event handlers to undefined."
);
if (typeof globalObject !== "undefined" && when) {
globalObject.addEventListener(eventName, freshCallback, listenerOptions);
return () => {
globalObject.removeEventListener(
eventName,
freshCallback,
listenerOptions
);
};
}
return () => {
};
}, [eventName, listenerOptions]);
}
// src/hooks/useOnWindowResize.ts
function useOnWindowResize(callback, when = true, isLayoutEffect = false) {
useGlobalObjectEventListener(
global.window,
"resize",
callback,
{ passive: true },
when,
isLayoutEffect
);
}
// src/hooks/useOnWindowScroll.ts
function useOnWindowScroll(callback, when = true, isLayoutEffect = false) {
useGlobalObjectEventListener(
global.window,
"scroll",
callback,
{ passive: true },
when,
isLayoutEffect
);
}
// src/hooks/useDimensionsRef.ts
var getDimensionObject = (node) => {
const rect = node.getBoundingClientRect();
return {
bottom: rect.bottom,
height: rect.height,
left: rect.left,
right: rect.right,
top: rect.top,
width: rect.width,
x: rect.left,
y: rect.top
};
};
var noWindowReturnValue = [void 0, null, null];
var useDimensionsRef = ({
updateOnScroll = true,
updateOnResize = true
} = {}) => {
const [dimensions, setDimensions] = (0, import_react28.useState)(null);
const [node, setNode] = (0, import_react28.useState)(null);
const ref = (0, import_react28.useCallback)((nodeFromCallback) => {
setNode(nodeFromCallback);
}, []);
const measure = (0, import_react28.useCallback)(() => {
window.requestAnimationFrame(() => {
if (node) {
setDimensions(getDimensionObject(node));
}
});
}, [node]);
(0, import_react28.useLayoutEffect)(() => {
measure();
}, [measure]);
useOnWindowResize(
() => {
measure();
},
updateOnResize,
true
);
useOnWindowScroll(
() => {
measure();
},
updateOnScroll,
true
);
if (typeof window === "undefined") {
console.warn("useDimensionsRef: window is undefined.");
return noWindowReturnValue;
}
return [ref, dimensions, node];
};
// src/hooks/useDocumentEventListener.ts
function useDocumentEventListener(eventName, callback, listenerOptions = {}, isLayoutEffect = false) {
useGlobalObjectEventListener(
global.document,
eventName,
callback,
listenerOptions,
true,
isLayoutEffect
);
}
// src/hooks/useDocumentTitle.ts
var import_react29 = require("react");
function useDocumentTitle(title, options = {}) {
const isBrowser = typeof window !== "undefined";
const prevTitleRef = (0, import_react29.useRef)(isBrowser ? document.title : "");
const { resetOnUnmount = false } = options;
(0, import_react29.useEffect)(() => {
if (isBrowser) {
document.title = title;
const lastTitle = prevTitleRef.current;
if (resetOnUnmount) {
return () => {
document.title = lastTitle;
};
}
}
return noop;
}, [title, isBrowser, resetOnUnmount]);
}
// src/hooks/useDocumentVisibilityState.ts
var import_react30 = require("react");
function useDocumentVisibilityState() {
const [visibilityState, setVisibilityState] = (0, import_react30.useState)(
document ? document.visibilityState : null
);
const handleVisibilityChange = (0, import_react30.useCallback)(() => {
setVisibilityState(document ? document.visibilityState : null);
}, []);
useGlobalObjectEventListener(
global.document,
"visibilitychange",
handleVisibilityChange,
{},
true,
true
);
return visibilityState;
}
// src/hooks/useEffectOnceWhen.ts
var import_react31 = require("react");
function useEffectOnceWhen(callback, when = true) {
const hasRunOnceRef = (0, import_react31.useRef)(false);
const callbackRef = (0, import_react31.useRef)(callback);
(0, import_react31.useEffect)(() => {
callbackRef.current = callback;
});
(0, import_react31.useEffect)(() => {
if (when && !hasRunOnceRef.current) {
callbackRef.current();
hasRunOnceRef.current = true;
}
}, [when]);
}
// src/hooks/useEventListenerRef.ts
var import_react33 = require("react");
// src/hooks/useRefElement.ts
var import_react32 = require("react");
function useRefElement() {
const [refElement, setRefElement] = (0, import_react32.useState)(null);
const ref = (0, import_react32.useCallback)(
(element) => {
setRefElement(element);
},
[]
);
return [ref, refElement];
}
// src/hooks/useEventListenerRef.ts
function useEventListenerRef(eventName, callback, listenerOptions = {}, isLayoutEffect = false) {
const [ref, element] = useRefElement();
const freshCallback = useFreshTick(callback);
const useEffectToRun = isLayoutEffect ? useIsomorphicEffect : import_react33.useEffect;
useEffectToRun(() => {
if (!element?.addEventListener) {
return noop;
}
element.addEventListener(eventName, freshCallback, listenerOptions);
return () => {
element.removeEventListener(eventName, freshCallback, listenerOptions);
};
}, [element, eventName, listenerOptions]);
return ref;
}
// src/hooks/useFileDropRef.ts
var import_react34 = require("react");
function useFileDropRef(options = {}, callbacks = {}) {
const { accept, maxFileSize, maxFiles } = options;
const {
onDrop = noop,
onFileAccepted = noop,
onFileRejected = noop,
onDragEnter = noop,
onDragLeave = noop
} = callbacks;
const [targetNode, setTargetNode] = (0, import_react34.useState)(null);
const freshOnDrop = useFreshCallback(onDrop);
const freshOnFileAccepted = useFreshCallback(onFileAccepted);
const freshOnFileRejected = useFreshCallback(onFileRejected);
const freshOnDragEnter = useFreshCallback(onDragEnter);
const freshOnDragLeave = useFreshCallback(onDragLeave);
(0, import_react34.useCallback)((node) => {
setTargetNode(node);
}, []);
const fileIsValid = (0, import_react34.useCallback)(
(file) => {
if (accept && !accept.includes(file.type)) {
return { valid: false, reason: "File type not allowed" };
}
if (maxFileSize && file.size > maxFileSize) {
return { valid: false, reason: "File size exceeds the limit" };
}
return { valid: true };
},
[accept, maxFileSize]
);
const handleDrop = (0, import_react34.useCallback)(
(event) => {
event.preventDefault();
const files = Array.from(event.dataTransfer?.files || []);
const acceptedFiles = [];
const rejectedFiles = [];
if (maxFiles && files.length > maxFiles) {
for (const file of files) {
freshOnFileRejected(file, "Exceeded maximum number of files");
}
} else {
files.forEach((file) => {
const validationResult = fileIsValid(file);
if (validationResult.valid) {
acceptedFiles.push(file);
freshOnFileAccepted(file);
} else {
rejectedFiles.push(file);
freshOnFileRejected(
file,
validationResult.reason || "Unknown reason"
);
}
});
}
freshOnDrop(acceptedFiles, rejectedFiles);
},
[
fileIsValid,
freshOnFileAccepted,
freshOnFileRejected,
maxFiles,
freshOnDrop
]
);
const handleDragOver = (0, import_react34.useCallback)((event) => {
event.preventDefault();
}, []);
(0, import_react34.useEffect)(() => {
if (targetNode) {
targetNode.addEventListener("drop", handleDrop);
targetNode.addEventListener("dragover", handleDragOver);
targetNode.addEventListener("dragenter", freshOnDragEnter);
targetNode.addEventListener("dragleave", freshOnDragLeave);
return () => {
targetNode.removeEventListener("drop", handleDrop);
targetNode.removeEventListener("dragover", handleDragOver);
targetNode.removeEventListener("dragenter", freshOnDragEnter);
targetNode.removeEventListener("dragleave", freshOnDragLeave);
};
} else {
return () => {
};
}
}, [
targetNode,
handleDrop,
handleDragOver,
freshOnDragEnter,
freshOnDragLeave
]);
return (0, import_react34.useCallback)((node) => {
setTargetNode(node);
}, []);
}
// src/hooks/useFullscreen.ts
var import_react35 = require("react");
var FullscreenApi = {
DOM_UNAVAILABLE_ERROR: "DOM is unavailable server-side. Please use this method client-side only.",
FULLSCREEN_UNSUPPORTED_ERROR: "Your browser does not support Fullscreen API.",
getEventsNames() {
if (typeof document === "undefined") return null;
const _document = document;
if ("exitFullscreen" in _document)
return ["fullscreenchange", "fullscreenerror"];
if ("webkitExitFullscreen" in _document)
return ["webkitfullscreenchange", "webkitfullscreenerror"];
if ("webkitCancelFullScreen" in _document)
return ["webkitfullscreenchange", "webkitfullscreenerror"];
if ("mozCancelFullScreen" in _document)
return ["mozfullscreenchange", "mozfullscreenerror"];
if ("msExitFullscreen" in _document)
return ["MSFullscreenChange", "MSFullscreenError"];
return null;
},
getEventName(eventType) {
const eventsNames = this.getEventsNames();
if (!eventsNames) return null;
if (eventType === "change") return eventsNames[0];
return eventsNames[1];
},
get fullscreenEnabled() {
if (typeof document === "undefined") return false;
const _document = document;
return _document.fullscreenEnabled || _document.webkitFullscreenEnabled || !!_document.webkitCancelFullScreen || _document.mozFullScreenEnabled || _document.msFullscreenEnabled || false;
},
get fullscreenElement() {
if (typeof document === "undefined") return null;
const _document = document;
return _document.fullscreenElement || _document.webkitFullscreenElement || _document.webkitCurrentFullScreenElement || _document.mozFullScreenElement || _document.msFullscreenElement || null;
},
requestFullscreen(element, options) {
if (typeof document === "undefined")
throw new Error(this.DOM_UNAVAILABLE_ERROR);
const target = element ?? document.documentElement;
const method = target.requestFullscreen || target.webkitRequestFullscreen || target.webkitRequestFullScreen || target.mozRequestFullScreen || target.msRequestFullscreen;
if (!method) throw new Error(this.FULLSCREEN_UNSUPPORTED_ERROR);
return method.call(target, options);
},
exitFullscreen() {
if (typeof document === "undefined")
throw new Error(this.DOM_UNAVAILABLE_ERROR);
const _document = document;
const method = _document.exitFullscreen || _document.webkitExitFullscreen || _document.webkitCancelFullScreen || _document.mozCancelFullScreen || _document.msExitFullscreen;
if (!method) throw new Error(this.FULLSCREEN_UNSUPPORTED_ERROR);
return method.call(_document);
},
on(eventType, callback) {
const eventName = this.getEventName(eventType);
if (!eventName) return;
document.addEventListener(eventName, callback);
},
off(eventType, callback) {
const eventName = this.getEventName(eventType);
if (!eventName) return;
document.removeEventListener(eventName, callback);
}
};
function useFullscreen(props = {}) {
const { target, onChange, onError, requestFullScreenOptions } = props;
const [isFullscreenAvailable, setIsFullscreenAvailable] = (0, import_react35.useState)(false);
const [fullscreenElement, setFullscreenElement] = (0, import_react35.useState)(
null
);
const [isFullscreenEnabled, setIsFullscreenEnabled] = (0, import_react35.useState)(false);
const enableFullscreen = (0, import_react35.useCallback)(() => {
return FullscreenApi.requestFullscreen(
target?.current || null,
requestFullScreenOptions
);
}, [target, requestFullScreenOptions]);
const disableFullscreen = (0, import_react35.useCallback)(() => {
return FullscreenApi.exitFullscreen();
}, []);
const toggleFullscreen = (0, import_react35.useCallback)(() => {
if (!!FullscreenApi.fullscreenElement) return disableFullscreen();
return enableFullscreen();
}, [enableFullscreen, disableFullscreen]);
const onChangeHandler = (0, import_react35.useCallback)(
(event) => {
const fullscreenElement2 = FullscreenApi.fullscreenElement;
setFullscreenElement(fullscreenElement2);
setIsFullscreenEnabled(!!fullscreenElement2);
onChange?.(event);
},
[onChange]
);
const onErrorHandler = (0, import_react35.useCallback)(
(event) => {
const fullscreenElement2 = FullscreenApi.fullscreenElement;
setFullscreenElement(fullscreenElement2);
setIsFullscreenEnabled(!!fullscreenElement2);
onError?.(event);
},
[onError]
);
(0, import_react35.useEffect)(() => {
setIsFullscreenAvailable(FullscreenApi.fullscreenEnabled);
}, []);
(0, import_react35.useEffect)(() => {
FullscreenApi.on("change", onChangeHandler);
FullscreenApi.on("error", onErrorHandler);
return () => {
FullscreenApi.off("change", onChangeHandler);
FullscreenApi.off("error", onErrorHandler);
};
}, [onChangeHandler, onErrorHandler]);
return {
isFullscreenAvailable,
fullscreenElement,
isFullscreenEnabled,
enableFullscreen,
disableFullscreen,
toggleFullscreen
};
}
// src/hooks/useFocus.ts
var import_react36 = require("react");
var useFocus = (props) => {
const {
onBlur: propsOnBlur,
onFocus: propsOnFocus,
onFocusChange: propsOnFocusChange
} = props;
const onBlur = (0, import_react36.useCallback)(
(e) => {
if (e.target === e.currentTarget) {
if (propsOnBlur) propsOnBlur(e);
if (propsOnFocusChange) propsOnFocusChange(false);
}
},
[propsOnBlur, propsOnFocusChange]
);
const onFocus = (0, import_react36.useCallback)(
(e) => {
if (e.target === e.currentTarget) {
if (propsOnFocus) propsOnFocus(e);
if (propsOnFocusChange) propsOnFocusChange(true);
}
},
[propsOnFocusChange, propsOnFocus]
);
return {
focusProps: {
onFocus,
onBlur
}
};
};
// src/hooks/useFocusWithin.ts
var import_react37 = require("react");
var useFocusWithin = (props) => {
const { onBlurWithin, onFocusWithin, onFocusWithinChange } = props;
const state = (0, import_react37.useRef)({
isFocusWithin: false
});
const onBlur = (0, import_react37.useCallback)(
(e) => {
if (state.current.isFocusWithin && !e.currentTarget.contains(e.relatedTarget)) {
state.current.isFocusWithin = false;
if (onBlurWithin) onBlurWithin(e);
if (onFocusWithinChange) onFocusWithinChange(false);
}
},
[onBlurWithin, onFocusWithinChange]
);
const onFocus = (0, import_react37.useCallback)(
(e) => {
if (!state.current.isFocusWithin) {
if (onFocusWithin) onFocusWithin(e);
if (onFocusWithinChange) onFocusWithinChange(true);
state.current.isFocusWithin = true;
}
},
[onFocusWithin, onFocusWithinChange]
);
return {
focusWithinProps: {
onFocus,
onBlur
}
};
};
// src/hooks/useGeolocation.ts
var import_react38 = require("react");
function getGeoLocation(options) {
return new Promise((resolve, reject) => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const { coords } = position;
const { latitude, longitude } = coords;
resolve({
isError: false,
lat: latitude,
lng: longitude,
message: ""
});
},
(error) => {
resolve({
isError: true,
message: error && typeof error === "object" && "message" in error ? error.message : "Geolocation error"
});
},
options
);
} else {
resolve({
isError: true,
message: "Geolocation is not supported for this Browser/OS."
});
}
});
}
var defaultGeoLocationOptions = {
enableHighAccuracy: false,
maximumAge: 0,
timeout: Number.POSITIVE_INFINITY,
when: true
};
var useGeolocation = (geoLocationOptions = defaultGeoLocationOptions) => {
const [geoObject, setGeoObject] = (0, import_react38.useState)(
null
);
const { when, enableHighAccuracy, timeout, maximumAge } = geoLocationOptions;
const getIsMounted = useGetIsMounted();
(0, import_react38.useEffect)(() => {
async function getGeoCode() {
try {
const value = await getGeoLocation({
enableHighAccuracy,
maximumAge,
timeout,
when
});
if (getIsMounted()) {
setGeoObject(value);
}
} catch (error) {
if (getIsMounted()) {
setGeoObject({
isError: true,
message: error instanceof Error ? error.message : String(error)
});
}
}
}
if (when) {
void getGeoCode();
}
}, [when, enableHighAccuracy, timeout, maximumAge, getIsMounted]);
return geoObject;
};
// src/hooks/useInput.ts
var import_react39 = require("react");
var defaultOptions = {};
function useInput(initialValue = "", options = defaultOptions) {
const [value, setValue] = (0, import_react39.useState)(initialValue);
const onChange = (0,