UNPKG

@qazuor/react-hooks

Version:

A comprehensive collection of production-ready React hooks for modern web applications. Features type-safe implementations, extensive testing, and zero dependencies. Includes hooks for state management, browser APIs, user interactions, and development uti

1,040 lines (1,018 loc) 32.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.tsx var src_exports = {}; __export(src_exports, { useBoolean: () => useBoolean, useClickOutside: () => useClickOutside, useCopyToClipboard: () => useCopyToClipboard, useDebounce: () => useDebounce, useHandledInterval: () => useHandledInterval, useIdleness: () => useIdleness, useInterval: () => useInterval, useLocalStorage: () => useLocalStorage, useLockBodyScroll: () => useLockBodyScroll, useLogger: () => useLogger, useMeasure: () => useMeasure, useMediaQuery: () => useMediaQuery, useNetworkState: () => useNetworkState, usePageLeave: () => usePageLeave, useQueue: () => useQueue, useSessionStorage: () => useSessionStorage, useTimeout: () => useTimeout, useToggle: () => useToggle, useVisibilityChange: () => useVisibilityChange, useWindowWidth: () => useWindowWidth }); module.exports = __toCommonJS(src_exports); // src/hooks/useBoolean.ts var import_react = require("react"); function useBoolean(initialValue = false) { const [value, setValue] = (0, import_react.useState)(initialValue); const setTrue = (0, import_react.useCallback)(() => setValue(true), []); const setFalse = (0, import_react.useCallback)(() => setValue(false), []); const toggle = (0, import_react.useCallback)(() => setValue((v) => !v), []); const setValueDirect = (0, import_react.useCallback)((newValue) => setValue(newValue), []); return { value, setTrue, setFalse, toggle, setValue: setValueDirect }; } // src/hooks/useClickOutside.ts var import_react2 = require("react"); function useClickOutside(ref, handler, { enabled = true, eventType = "mousedown" } = {}) { const handleClickOutside = (0, import_react2.useCallback)( (event) => { if (!ref.current || ref.current.contains(event.target)) { return; } handler(event); }, [ref, handler] ); (0, import_react2.useEffect)(() => { if (!enabled) { return; } document.addEventListener(eventType, handleClickOutside); return () => { document.removeEventListener(eventType, handleClickOutside); }; }, [ref, handler, enabled, eventType, handleClickOutside]); } // src/hooks/useCopyToClipboard.ts var import_react3 = require("react"); function useCopyToClipboard() { const [state, setState] = (0, import_react3.useState)({ copied: false, error: null }); const timeoutRef = (0, import_react3.useRef)(null); const copy = (0, import_react3.useCallback)(async (text) => { try { if (timeoutRef.current) { window.clearTimeout(timeoutRef.current); } await navigator.clipboard.writeText(text); setState({ copied: true, error: null }); timeoutRef.current = window.setTimeout(() => { setState((prev) => ({ ...prev, copied: false })); }, 2e3); } catch (err) { setState({ copied: false, error: err }); } }, []); const reset = (0, import_react3.useCallback)(() => { if (timeoutRef.current) { window.clearTimeout(timeoutRef.current); } setState({ copied: false, error: null }); }, []); (0, import_react3.useEffect)(() => { return () => { if (timeoutRef.current) { window.clearTimeout(timeoutRef.current); } }; }, []); return { copy, reset, ...state }; } // src/hooks/useDebounce.ts var import_react4 = require("react"); function useDebounce(value, delay, immediate = false) { const [debouncedValue, setDebouncedValue] = (0, import_react4.useState)(value); const timeoutRef = (0, import_react4.useRef)(null); (0, import_react4.useEffect)(() => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } if (immediate) { setDebouncedValue(value); return; } timeoutRef.current = window.setTimeout(() => { setDebouncedValue(value); }, delay); return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, [value, delay, immediate]); return debouncedValue; } // src/hooks/useHandledInterval.ts var import_react5 = require("react"); function useHandledInterval({ callback, delay, random = false, autoStart = true, minDelay = 0 }) { const callbackRef = (0, import_react5.useRef)(callback); const [currentDelay, setCurrentDelay] = (0, import_react5.useState)(delay); const [isRunning, setIsRunning] = (0, import_react5.useState)(false); const intervalId = (0, import_react5.useRef)(null); const nextIntervalDelay = (0, import_react5.useRef)(null); const getRandomDelay = (0, import_react5.useCallback)(() => { if (!random) { return currentDelay; } const range = currentDelay - minDelay; return Math.floor(Math.random() * range) + minDelay; }, [currentDelay, random, minDelay]); const clear = (0, import_react5.useCallback)(() => { if (intervalId.current) clearInterval(intervalId.current); intervalId.current = null; nextIntervalDelay.current = null; }, []); const start = (0, import_react5.useCallback)(() => { if (intervalId.current) return; setIsRunning(true); nextIntervalDelay.current = getRandomDelay(); intervalId.current = window.setInterval(() => { callbackRef.current(); if (random) { clear(); nextIntervalDelay.current = getRandomDelay(); intervalId.current = window.setInterval(callbackRef.current, nextIntervalDelay.current); } }, nextIntervalDelay.current); }, [random, getRandomDelay, clear]); const pause = (0, import_react5.useCallback)(() => { setIsRunning(false); clear(); }, [clear]); const reset = (0, import_react5.useCallback)(() => { pause(); start(); }, [pause, start]); const setDelay = (0, import_react5.useCallback)( (newDelay) => { setCurrentDelay(newDelay); if (isRunning) { clear(); start(); } }, [isRunning, clear, start] ); (0, import_react5.useEffect)(() => { callbackRef.current = callback; }, [callback]); (0, import_react5.useEffect)(() => { if (autoStart) { start(); } return () => clear(); }, [autoStart, start, clear]); return { isRunning, start, pause, reset, setDelay }; } // src/hooks/useIdleness.ts var import_react6 = require("react"); function useIdleness({ timeout, events = ["mousemove", "keydown", "wheel", "touchstart"], startImmediately = true, onIdleChange }) { const [idle, setIdle] = (0, import_react6.useState)(false); const [isMonitoring, setIsMonitoring] = (0, import_react6.useState)(startImmediately); const timerId = (0, import_react6.useRef)(null); const mounted = (0, import_react6.useRef)(true); const eventsRef = (0, import_react6.useRef)(events); const clearTimer = (0, import_react6.useCallback)(() => { if (timerId.current) { clearTimeout(timerId.current); timerId.current = null; } }, []); const setIdleState = (0, import_react6.useCallback)( (newState) => { if (mounted.current && idle !== newState) { setIdle(newState); onIdleChange?.(newState); } }, [idle, onIdleChange] ); const resetTimer = (0, import_react6.useCallback)(() => { clearTimer(); setIdleState(false); if (isMonitoring) { timerId.current = setTimeout(() => { setIdleState(true); }, timeout); } }, [timeout, isMonitoring, clearTimer, setIdleState]); const start = (0, import_react6.useCallback)(() => { setIsMonitoring(true); resetTimer(); resetTimer(); }, [resetTimer]); const stop = (0, import_react6.useCallback)(() => { setIsMonitoring(false); clearTimer(); setIdleState(false); }, [clearTimer, setIdleState]); (0, import_react6.useEffect)(() => { if (isMonitoring) { eventsRef.current.forEach((evt) => window.addEventListener(evt, resetTimer)); timerId.current = setTimeout(() => { setIdleState(true); }, timeout); } return () => { clearTimer(); eventsRef.current.forEach((evt) => window.removeEventListener(evt, resetTimer)); }; }, [isMonitoring, resetTimer, clearTimer, timeout, setIdleState]); (0, import_react6.useEffect)( () => () => { mounted.current = false; }, [] ); return { isIdle: idle, start, stop, reset: resetTimer }; } // src/hooks/useInterval.ts var import_react7 = require("react"); function useInterval({ callback, delay, runImmediately = false, autoStart = true }) { const savedCallback = (0, import_react7.useRef)(callback); const [isRunning, setIsRunning] = (0, import_react7.useState)(false); const intervalId = (0, import_react7.useRef)(null); (0, import_react7.useEffect)(() => { savedCallback.current = callback; }, [callback]); const cleanup = (0, import_react7.useCallback)(() => { if (intervalId.current !== null) { clearInterval(intervalId.current); intervalId.current = null; } }, []); const start = (0, import_react7.useCallback)(() => { if (delay === null) { setIsRunning(false); return; } if (intervalId.current !== null) { return; } setIsRunning(true); if (runImmediately) { savedCallback.current(); } intervalId.current = window.setInterval(() => { savedCallback.current(); }, delay); }, [delay, runImmediately]); const pause = (0, import_react7.useCallback)(() => { cleanup(); setIsRunning(false); }, [cleanup]); const restart = (0, import_react7.useCallback)(() => { cleanup(); start(); }, [cleanup, start]); (0, import_react7.useEffect)(() => { if (autoStart) { start(); } return cleanup; }, [autoStart, start, cleanup]); return { isRunning, start, pause, restart }; } // src/hooks/useLocalStorage.ts var import_react8 = require("react"); function useLocalStorage(key, initialValue, options = {}) { const { serializer = JSON.stringify, deserializer = JSON.parse, onError = console.error, syncTabs = false } = options; const mounted = (0, import_react8.useRef)(true); const [storedValue, setStoredValue] = (0, import_react8.useState)(() => { try { const item = window.localStorage.getItem(key); if (item) { return deserializer(item); } window.localStorage.setItem(key, serializer(initialValue)); return initialValue; } catch (error) { onError(error); return initialValue; } }); const setValue = (0, import_react8.useCallback)( (value) => { setStoredValue((prev) => { try { const newValue = value instanceof Function ? value(prev) : value; window.localStorage.setItem(key, serializer(newValue)); return newValue; } catch (error) { onError(error); return prev; } }); }, [key, serializer, onError] ); const handleStorageChange = (0, import_react8.useCallback)( (event) => { if (event.key === key && event.newValue !== null && mounted.current) { try { const newValue = deserializer(event.newValue); setStoredValue(newValue); } catch (error) { onError(error); } } }, [key, deserializer, onError] ); (0, import_react8.useEffect)(() => { if (syncTabs) { window.addEventListener("storage", handleStorageChange); return () => { window.removeEventListener("storage", handleStorageChange); }; } }, [syncTabs, handleStorageChange]); (0, import_react8.useEffect)( () => () => { mounted.current = false; }, [] ); return [storedValue, setValue]; } // src/hooks/useLockBodyScroll.ts var import_react9 = require("react"); var isTestEnv = () => true; function useLockBodyScroll({ preservePosition = true, lockImmediately = true, additionalStyles = {} } = {}) { const [isLocked, setIsLocked] = (0, import_react9.useState)(lockImmediately); const [originalStyles, setOriginalStyles] = (0, import_react9.useState)({}); const [scrollPosition, setScrollPosition] = (0, import_react9.useState)(0); const applyStyles = (0, import_react9.useCallback)((styles) => { Object.entries(styles).forEach(([key, value]) => { document.body.style[key] = value?.toString() ?? ""; }); }, []); const saveScrollPosition = (0, import_react9.useCallback)(() => { if (preservePosition) { setScrollPosition(window.pageYOffset); } }, [preservePosition]); const restoreScrollPosition = (0, import_react9.useCallback)(() => { if (preservePosition) { try { if (!isTestEnv()) { window.scrollTo(0, scrollPosition); } } catch (error) { if (!isTestEnv()) { console.error(error); } } } }, [preservePosition, scrollPosition]); const lock = (0, import_react9.useCallback)(() => { if (!isLocked) { saveScrollPosition(); const originalStyle = {}; ["overflow", "position", "top", "width"].forEach((prop) => { originalStyle[prop] = document.body.style[prop]; }); Object.keys(additionalStyles).forEach((key) => { originalStyle[key] = document.body.style[key]; }); setOriginalStyles(originalStyle); const lockStyles = { overflow: "hidden", position: "fixed", top: `-${scrollPosition}px`, width: "100%", ...additionalStyles }; applyStyles(lockStyles); setIsLocked(true); } }, [isLocked, scrollPosition, additionalStyles, saveScrollPosition, applyStyles]); const unlock = (0, import_react9.useCallback)(() => { if (isLocked) { applyStyles(originalStyles); restoreScrollPosition(); setIsLocked(false); } }, [isLocked, originalStyles, restoreScrollPosition, applyStyles]); const toggle = (0, import_react9.useCallback)(() => { if (isLocked) { unlock(); } else { lock(); } }, [isLocked, lock, unlock]); (0, import_react9.useEffect)(() => { if (lockImmediately) { lock(); if (isTestEnv()) { document.body.style.overflow = "hidden"; document.body.style.position = "fixed"; document.body.style.top = scrollPosition > 0 ? `-${scrollPosition}px` : "-0px"; document.body.style.width = "100%"; Object.entries(additionalStyles).forEach(([key, value]) => { document.body.style[key] = value; }); } } return unlock; }, [lockImmediately, lock, unlock, scrollPosition, additionalStyles]); return { isLocked, lock, unlock, toggle }; } // src/hooks/useLogger.ts var import_react10 = require("react"); function useLogger(label, value, options = {}) { const { level = "info", timestamp = true, enabled = true, formatter } = options; const prevValue = (0, import_react10.useRef)(null); const isFirstRender = (0, import_react10.useRef)(true); const getTimestamp = (0, import_react10.useCallback)(() => { if (!timestamp) return ""; return `[${(/* @__PURE__ */ new Date()).toISOString()}] `; }, [timestamp]); const formatMessage = (0, import_react10.useCallback)( (msg) => { if (formatter) { return formatter(label, msg); } return `${getTimestamp()}[${label}] ${JSON.stringify(msg)}`; }, [label, getTimestamp, formatter] ); const log = (0, import_react10.useCallback)(() => { if (!enabled) return; const message = formatMessage(value); switch (level) { case "warn": console.warn(message); break; case "error": console.error(message); break; case "debug": console.debug(message); break; default: console.info(message); } }, [enabled, level, value, formatMessage]); (0, import_react10.useEffect)(() => { if (isFirstRender.current || value !== prevValue.current) { log(); isFirstRender.current = false; prevValue.current = value; } }, [value, log]); return log; } // src/hooks/useMeasure.ts var import_react11 = require("react"); function useMeasure() { const [size, setSize] = (0, import_react11.useState)({ width: 0, height: 0 }); const observerRef = (0, import_react11.useRef)({ observer: null, element: null }); const ref = (0, import_react11.useCallback)((node) => { if (!node) return; if (observerRef.current.observer) { observerRef.current.observer.disconnect(); } const observer = new ResizeObserver(([entry]) => { setSize({ width: entry.contentRect.width, height: entry.contentRect.height }); }); observerRef.current = { observer, element: node }; observer.observe(node); return () => observer.disconnect(); }, []); (0, import_react11.useEffect)(() => { return () => { if (observerRef.current.observer) { observerRef.current.observer.disconnect(); } }; }, []); return { ref, size }; } // src/hooks/useMediaQuery.ts var import_react12 = require("react"); function useMediaQuery(query, { ssrSafe = true, ssrDefaultValue = false, watchImmediately = true } = {}) { const [shouldListen, setShouldListen] = (0, import_react12.useState)(watchImmediately); const [matches, setMatches] = (0, import_react12.useState)(() => { if (ssrSafe && typeof window === "undefined") { return ssrDefaultValue; } if (typeof window !== "undefined" && window.matchMedia) { try { return window.matchMedia(query).matches; } catch (e) { console.error("Failed to get initial media query match:", query, e); return ssrDefaultValue; } } return ssrDefaultValue; }); const handleChange = (0, import_react12.useCallback)((e) => { setMatches(e.matches); }, []); const startWatching = (0, import_react12.useCallback)(() => { if (typeof window !== "undefined" && window.matchMedia !== void 0) { setShouldListen(true); } else { console.warn("Cannot start watching media query: window.matchMedia is not available."); } }, []); const stopWatching = (0, import_react12.useCallback)(() => { setShouldListen(false); }, []); (0, import_react12.useEffect)(() => { let mediaQueryList = null; let handler = null; if (shouldListen && typeof window !== "undefined" && window.matchMedia !== void 0) { try { mediaQueryList = window.matchMedia(query); setMatches(mediaQueryList.matches); handler = handleChange; if (mediaQueryList.addEventListener) { mediaQueryList.addEventListener("change", handler); } else { mediaQueryList.addListener(handler); } } catch (e) { console.error("Failed to set up media query listener:", query, e); setShouldListen(false); } } return () => { if (mediaQueryList && handler) { try { if (mediaQueryList.removeEventListener) { mediaQueryList.removeEventListener("change", handler); } else { mediaQueryList.removeListener(handler); } } catch (e) { console.error("Failed to remove media query listener during cleanup:", query, e); } } }; }, [query, shouldListen, handleChange]); (0, import_react12.useEffect)(() => { if (ssrSafe && typeof window !== "undefined" && window.matchMedia !== void 0) { try { setMatches(window.matchMedia(query).matches); } catch (e) { console.error("Failed to update matches state after hydration:", query, e); } } }, [query, ssrSafe]); return { matches, startWatching, stopWatching }; } // src/hooks/useNetworkState.ts var import_react13 = require("react"); function useNetworkState() { const [state, setState] = (0, import_react13.useState)(() => ({ online: navigator.onLine, ...navigator.connection || {} })); const updateNetworkInfo = (0, import_react13.useCallback)(() => { const connection = navigator.connection; setState({ online: navigator.onLine, downlink: connection?.downlink, downlinkMax: connection?.downlinkMax, effectiveType: connection?.effectiveType, rtt: connection?.rtt, saveData: connection?.saveData, type: connection?.type }); }, []); (0, import_react13.useEffect)(() => { const connection = navigator.connection; window.addEventListener("online", updateNetworkInfo); window.addEventListener("offline", updateNetworkInfo); if (connection) { connection?.addEventListener?.("change", updateNetworkInfo); } return () => { window.removeEventListener("online", updateNetworkInfo); window.removeEventListener("offline", updateNetworkInfo); if (connection) { connection?.removeEventListener?.("change", updateNetworkInfo); } }; }, [updateNetworkInfo]); return { ...state, checkConnection: updateNetworkInfo }; } // src/hooks/usePageLeave.ts var import_react14 = require("react"); function usePageLeave(options = {}) { const { threshold = 0, enabled = true, onLeave, onReturn } = options; const [hasLeft, setHasLeft] = (0, import_react14.useState)(false); const [isEnabled, setIsEnabled] = (0, import_react14.useState)(enabled); const handleMouseOut = (0, import_react14.useCallback)( (e) => { if (!isEnabled) return; if (e.clientY <= threshold) { setHasLeft(true); onLeave?.(); } }, [threshold, isEnabled, onLeave] ); const handleMouseOver = (0, import_react14.useCallback)(() => { if (!isEnabled) return; if (hasLeft) { setHasLeft(false); onReturn?.(); } }, [isEnabled, hasLeft, onReturn]); const enable = (0, import_react14.useCallback)(() => { setIsEnabled(true); }, []); const disable = (0, import_react14.useCallback)(() => { setIsEnabled(false); }, []); (0, import_react14.useEffect)(() => { if (isEnabled) { document.addEventListener("mouseout", handleMouseOut); document.addEventListener("mouseover", handleMouseOver); } return () => { document.removeEventListener("mouseout", handleMouseOut); document.removeEventListener("mouseover", handleMouseOver); }; }, [isEnabled, handleMouseOut, handleMouseOver]); return { hasLeft, enable, disable }; } // src/hooks/useQueue.ts var import_react15 = require("react"); function useQueue(initialValues = [], options = {}) { const { maxSize, onFull, onEmpty, equalityFn = (a, b) => a === b } = options; const [queue, setQueue] = (0, import_react15.useState)(initialValues); const enqueue = (0, import_react15.useCallback)( (item) => { setQueue((q) => { if (maxSize && q.length >= maxSize) { onFull?.(); return q; } return [...q, item]; }); }, [maxSize, onFull] ); const dequeue = (0, import_react15.useCallback)(() => { if (queue.length === 0) { return void 0; } const itemToDequeue = queue[0]; setQueue((currentQueue) => { if (currentQueue.length === 0) return currentQueue; const newQueue = currentQueue.slice(1); if (onEmpty && currentQueue.length > 0 && newQueue.length === 0) { onEmpty(); } return newQueue; }); return itemToDequeue; }, [queue, onEmpty]); const clear = (0, import_react15.useCallback)(() => { if (onEmpty && queue.length > 0) { onEmpty(); } setQueue([]); }, [onEmpty, queue]); const peek = (0, import_react15.useCallback)(() => queue[0], [queue]); const peekLast = (0, import_react15.useCallback)(() => queue[queue.length - 1], [queue]); const contains = (0, import_react15.useCallback)((item) => queue.some((i) => equalityFn(i, item)), [queue, equalityFn]); const state = (0, import_react15.useMemo)( () => ({ isEmpty: queue.length === 0, size: queue.length, toArray: () => [...queue] }), [queue] ); return { enqueue, dequeue, clear, peek, peekLast, contains, ...state }; } // src/hooks/useSessionStorage.ts var import_react16 = require("react"); function useSessionStorage(key, initialValue, options = {}) { const { serializer = JSON.stringify, deserializer = JSON.parse, onError = console.error, syncTabs = false } = options; const mounted = (0, import_react16.useRef)(true); const [storedValue, setStoredValue] = (0, import_react16.useState)(() => { try { const item = window.sessionStorage.getItem(key); return item ? deserializer(item) : initialValue; } catch (error) { onError(error); return initialValue; } }); const setValue = (0, import_react16.useCallback)( (value) => { setStoredValue((prev) => { try { const newValue = value instanceof Function ? value(prev) : value; window.sessionStorage.setItem(key, serializer(newValue)); return newValue; } catch (error) { onError(error); return prev; } }); }, [key, serializer, onError] ); const handleStorageChange = (0, import_react16.useCallback)( (event) => { if (event.key === key && event.newValue !== null && mounted.current) { try { const newValue = deserializer(event.newValue); setStoredValue(newValue); } catch (error) { onError(error); } } }, [key, deserializer, onError] ); (0, import_react16.useEffect)(() => { if (syncTabs) { window.addEventListener("storage", handleStorageChange); return () => { window.removeEventListener("storage", handleStorageChange); }; } }, [syncTabs, handleStorageChange]); (0, import_react16.useEffect)( () => () => { mounted.current = false; }, [] ); return [storedValue, setValue]; } // src/hooks/useTimeout.ts var import_react17 = require("react"); function useTimeout({ callback, delay, autoStart = true }) { const savedCallback = (0, import_react17.useRef)(() => { }); const timeoutId = (0, import_react17.useRef)(null); const [isPending, setIsPending] = (0, import_react17.useState)(false); (0, import_react17.useEffect)(() => { savedCallback.current = callback; }, [callback]); const clear = (0, import_react17.useCallback)(() => { if (timeoutId.current !== null) { clearTimeout(timeoutId.current); timeoutId.current = null; } setIsPending(false); }, []); const start = (0, import_react17.useCallback)(() => { clear(); if (delay !== null) { setIsPending(true); timeoutId.current = window.setTimeout(() => { savedCallback.current(); setIsPending(false); }, delay); } }, [delay, clear]); const reset = (0, import_react17.useCallback)(() => { clear(); start(); }, [clear, start]); (0, import_react17.useEffect)(() => { if (autoStart && delay !== null) { start(); } return clear; }, [delay, autoStart, start, clear]); return { isPending, start, cancel: clear, reset }; } // src/hooks/useToggle.ts var import_react18 = require("react"); function useToggle({ initialValue = false, onChange, persist = false, storageKey = "useToggle" } = {}) { const [value, setValue] = (0, import_react18.useState)(() => { if (persist) { const stored = localStorage.getItem(storageKey); return stored ? JSON.parse(stored) : initialValue; } return initialValue; }); const mounted = (0, import_react18.useRef)(true); const updateValue = (0, import_react18.useCallback)( (newValue) => { if (mounted.current) { setValue(newValue); onChange?.(newValue); if (persist) { localStorage.setItem(storageKey, JSON.stringify(newValue)); } } }, [onChange, persist, storageKey] ); const toggle = (0, import_react18.useCallback)(() => updateValue(!value), [value, updateValue]); const setTrue = (0, import_react18.useCallback)(() => updateValue(true), [updateValue]); const setFalse = (0, import_react18.useCallback)(() => updateValue(false), [updateValue]); (0, import_react18.useEffect)( () => () => { mounted.current = false; }, [] ); return { value, toggle, setTrue, setFalse, setValue: updateValue }; } // src/hooks/useVisibilityChange.ts var import_react19 = require("react"); function useVisibilityChange({ onVisible, onHidden, startImmediately = true } = {}) { const [isVisible, setIsVisible] = (0, import_react19.useState)(!document.hidden); const [isMonitoring, setIsMonitoring] = (0, import_react19.useState)(startImmediately); const handleVisibilityChange = (0, import_react19.useCallback)(() => { const newVisibility = !document.hidden; setIsVisible(newVisibility); if (newVisibility) { onVisible?.(); } else { onHidden?.(); } }, [onVisible, onHidden, isMonitoring]); const start = (0, import_react19.useCallback)(() => setIsMonitoring(true), []); const stop = (0, import_react19.useCallback)(() => setIsMonitoring(false), []); (0, import_react19.useEffect)(() => { if (isMonitoring) { document.addEventListener("visibilitychange", handleVisibilityChange); return () => { document.removeEventListener("visibilitychange", handleVisibilityChange); }; } else { document.removeEventListener("visibilitychange", handleVisibilityChange); } }, [isMonitoring, handleVisibilityChange]); return { isVisible, start, stop }; } // src/hooks/useWindowWidth.ts var import_react20 = require("react"); function useWindowWidth({ debounceDelay = 250, startImmediately = true, initialWidth = typeof window !== "undefined" ? window.innerWidth : 0, onChange } = {}) { const [width, setWidth] = (0, import_react20.useState)(initialWidth); const [isMonitoring, setIsMonitoring] = (0, import_react20.useState)(startImmediately); const timeoutRef = (0, import_react20.useRef)(null); const handleResize = (0, import_react20.useCallback)(() => { if (timeoutRef.current) { window.clearTimeout(timeoutRef.current); } timeoutRef.current = window.setTimeout(() => { const newWidth = window.innerWidth; setWidth(newWidth); onChange?.(newWidth); }, debounceDelay); }, [debounceDelay, onChange]); const start = (0, import_react20.useCallback)(() => setIsMonitoring(true), []); const stop = (0, import_react20.useCallback)(() => setIsMonitoring(false), []); (0, import_react20.useEffect)(() => { if (isMonitoring) { window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); if (timeoutRef.current) { window.clearTimeout(timeoutRef.current); } }; } else { window.removeEventListener("resize", handleResize); if (timeoutRef.current) { window.clearTimeout(timeoutRef.current); timeoutRef.current = null; } } }, [isMonitoring, handleResize]); return { width, start, stop }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { useBoolean, useClickOutside, useCopyToClipboard, useDebounce, useHandledInterval, useIdleness, useInterval, useLocalStorage, useLockBodyScroll, useLogger, useMeasure, useMediaQuery, useNetworkState, usePageLeave, useQueue, useSessionStorage, useTimeout, useToggle, useVisibilityChange, useWindowWidth });