UNPKG

rooks

Version:

Essential React custom hooks ⚓ to super charge your components!

1,618 lines (1,562 loc) 143 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, useIdleDetectionApi: () => useIdleDetectionApi, 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, usePictureInPictureApi: () => usePictureInPictureApi, usePreviousDifferent: () => usePreviousDifferent, usePreviousImmediate: () => usePreviousImmediate, usePromise: () => usePromise, useQueueState: () => useQueueState, useRaf: () => useRaf, useRefElement: () => useRefElement, useRenderCount: () => useRenderCount, useResizeObserverRef: () => useResizeObserverRef, useSafeSetState: () => useSafeSetState, useScreenDetailsApi: () => useScreenDetailsApi, 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, useWebLocksApi: () => useWebLocksApi, 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, volume: initialVolume = 1, playbackRate: initialPlaybackRate = 1, loop: initialLoop = false, preload = "metadata" } = options; const [audioNode, setAudioNode] = (0, import_react11.useState)(null); const [state, setState] = (0, import_react11.useState)({ isPlaying: false, isMuted: initialIsMuted, volume: initialVolume, currentTime: 0, duration: 0, playbackRate: initialPlaybackRate, isLoading: false, isBuffering: false, loop: initialLoop, hasError: false }); const onPlay = useFreshCallback(callbacks.onPlay ?? noop2); const onPause = useFreshCallback(callbacks.onPause ?? noop2); const onEnded = useFreshCallback(callbacks.onEnded ?? noop2); const onMute = useFreshCallback(callbacks.onMute ?? noop2); const onUnmute = useFreshCallback(callbacks.onUnmute ?? noop2); const onLoadedMetadata = useFreshCallback(callbacks.onLoadedMetadata ?? noop2); const onTimeUpdate = useFreshCallback(callbacks.onTimeUpdate ?? noop2); const onDurationChange = useFreshCallback(callbacks.onDurationChange ?? noop2); const onVolumeChange = useFreshCallback(callbacks.onVolumeChange ?? noop2); const onRateChange = useFreshCallback(callbacks.onRateChange ?? noop2); const onError = useFreshCallback(callbacks.onError ?? noop2); const onLoadStart = useFreshCallback(callbacks.onLoadStart ?? noop2); const onCanPlay = useFreshCallback(callbacks.onCanPlay ?? noop2); const onWaiting = useFreshCallback(callbacks.onWaiting ?? noop2); const audioCallbackRef = (node) => { if (node !== null) { setAudioNode(node); } }; (0, import_react11.useEffect)(() => { if (!audioNode) return; audioNode.muted = state.isMuted; audioNode.volume = state.volume; audioNode.playbackRate = state.playbackRate; audioNode.loop = state.loop; audioNode.preload = preload; if (autoPlay) { audioNode.autoplay = true; } }, [audioNode, autoPlay, preload]); (0, import_react11.useEffect)(() => { if (!audioNode) return; const handleLoadStart = () => { setState((prev) => ({ ...prev, isLoading: true, hasError: false })); onLoadStart(); }; const handleLoadedMetadata = () => { setState((prev) => ({ ...prev, duration: audioNode.duration, isLoading: false, hasError: false })); onLoadedMetadata(); onDurationChange(audioNode.duration); }; const handleCanPlay = () => { setState((prev) => ({ ...prev, isBuffering: false, hasError: false })); onCanPlay(); }; const handleWaiting = () => { setState((prev) => ({ ...prev, isBuffering: true })); onWaiting(); }; const handlePlay = () => { setState((prev) => ({ ...prev, isPlaying: true, hasError: false })); onPlay(); }; const handlePause = () => { setState((prev) => ({ ...prev, isPlaying: false })); onPause(); }; const handleEnded = () => { setState((prev) => ({ ...prev, isPlaying: false })); onEnded(); }; const handleTimeUpdate = () => { const currentTime = audioNode.currentTime; setState((prev) => ({ ...prev, currentTime })); onTimeUpdate(currentTime); }; const handleDurationChange = () => { const duration = audioNode.duration; setState((prev) => ({ ...prev, duration })); onDurationChange(duration); }; const handleVolumeChange = () => { const volume = audioNode.volume; const isMuted = audioNode.muted; setState((prev) => { const newState = { ...prev, volume, isMuted }; if (isMuted !== prev.isMuted) { if (isMuted) { onMute(); } else { onUnmute(); } } return newState; }); onVolumeChange(volume); }; const handleRateChange = () => { const playbackRate = audioNode.playbackRate; setState((prev) => ({ ...prev, playbackRate })); onRateChange(playbackRate); }; const handleError = () => { const error = audioNode.error; const errorMessage = error ? `Audio error (${error.code}): ${error.message}` : "Unknown audio error occurred"; setState((prev) => ({ ...prev, hasError: true, error: errorMessage, isLoading: false, isBuffering: false, isPlaying: false })); onError(errorMessage); }; audioNode.addEventListener("loadstart", handleLoadStart); audioNode.addEventListener("loadedmetadata", handleLoadedMetadata); audioNode.addEventListener("canplay", handleCanPlay); audioNode.addEventListener("waiting", handleWaiting); audioNode.addEventListener("play", handlePlay); audioNode.addEventListener("pause", handlePause); audioNode.addEventListener("ended", handleEnded); audioNode.addEventListener("timeupdate", handleTimeUpdate); audioNode.addEventListener("durationchange", handleDurationChange); audioNode.addEventListener("volumechange", handleVolumeChange); audioNode.addEventListener("ratechange", handleRateChange); audioNode.addEventListener("error", handleError); return () => { audioNode.removeEventListener("loadstart", handleLoadStart); audioNode.removeEventListener("loadedmetadata", handleLoadedMetadata); audioNode.removeEventListener("canplay", handleCanPlay); audioNode.removeEventListener("waiting", handleWaiting); audioNode.removeEventListener("play", handlePlay); audioNode.removeEventListener("pause", handlePause); audioNode.removeEventListener("ended", handleEnded); audioNode.removeEventListener("timeupdate", handleTimeUpdate); audioNode.removeEventListener("durationchange", handleDurationChange); audioNode.removeEventListener("volumechange", handleVolumeChange); audioNode.removeEventListener("ratechange", handleRateChange); audioNode.removeEventListener("error", handleError); }; }, [ audioNode, onLoadStart, onLoadedMetadata, onCanPlay, onWaiting, onPlay, onPause, onEnded, onTimeUpdate, onDurationChange, onVolumeChange, onRateChange, onError, onMute, onUnmute ]); const play = () => { if (!audioNode) return; audioNode.play().catch((error) => { const errorMessage = error instanceof Error ? error.message : "Failed to play audio"; setState((prev) => ({ ...prev, hasError: true, error: errorMessage, isPlaying: false })); onError(errorMessage); }); }; const pause = () => { if (!audioNode) return; audioNode.pause(); }; const togglePlay = () => { if (state.isPlaying) { pause(); } else { play(); } }; const mute = () => { if (!audioNode) return; audioNode.muted = true; }; const unmute = () => { if (!audioNode) return; audioNode.muted = false; }; const toggleMute = () => { if (state.isMuted) { unmute(); } else { mute(); } }; const setVolume = (volume) => { if (!audioNode) return; const clampedVolume = Math.max(0, Math.min(1, volume)); audioNode.volume = clampedVolume; }; const setCurrentTime = (time) => { if (!audioNode) return; const clampedTime = Math.max(0, Math.min(state.duration || 0, time)); audioNode.currentTime = clampedTime; }; const setPlaybackRate = (rate) => { if (!audioNode) return; const clampedRate = Math.max(0.25, Math.min(4, rate)); audioNode.playbackRate = clampedRate; }; const seek = (seconds) => { setCurrentTime(state.currentTime + seconds); }; const fastForward = (seconds = 10) => { seek(seconds); }; const rewind = (seconds = 10) => { seek(-seconds); }; const setLoop = (loop) => { if (!audioNode) return; audioNode.loop = loop; setState((prev) => ({ ...prev, loop })); }; const controls = { play, pause, togglePlay, mute, unmute, toggleMute, setVolume, setCurrentTime, setPlaybackRate, seek, fastForward, rewind, setLoop }; 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 getVisibilityStateSnapshot() { if (typeof document !== "undefined") { return document.visibilityState; } else { return null; } } function getVisibilityStateSubscription(callback) { if (typeof document !== "undefined") { document.addEventListener("visibilitychange", callback); return () => { document.removeEventListener("visibilitychange", callback); }; } return () => { }; } function getVisibilityStateServerSnapshot() { return null; } function useDocumentVisibilityState() { return (0, import_react30.useSyncExternalStore)(getVisibilityStateSubscription, getVisibilityStateSnapshot, getVisibilityStateServerSnapshot); } // 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 }