UNPKG

rooks

Version:

Essential React custom hooks ⚓ to super charge your components!

1,645 lines (1,585 loc) 119 kB
"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,