@thibault.sh/hooks
Version: 
A comprehensive collection of React hooks for browser storage, UI interactions, and more
939 lines (915 loc) • 32 kB
text/typescript
import { RefObject } from 'react';
interface AsyncState<T> {
    isLoading: boolean;
    error: Error | null;
    value: T | null;
}
/**
 * Hook that manages async operations with loading, error, and success states.
 *
 * Provides a clean interface for handling asynchronous functions with automatic
 * state management for loading indicators and error handling.
 *
 * @template T - The type of data returned by the async function
 * @param asyncFunction - The async function to execute
 *
 * @returns An object containing:
 *   - `execute`: Function to trigger the async operation
 *   - `status`: Current state with `isLoading`, `error`, and `value` properties
 *
 * @example
 * ```tsx
 * const fetchUser = async (id: string) => {
 *   const response = await fetch(`/api/users/${id}`);
 *   return response.json();
 * };
 *
 * const { execute, status } = useAsync(fetchUser);
 *
 * // In your component
 * if (status.isLoading) return <div>Loading...</div>;
 * if (status.error) return <div>Error: {status.error.message}</div>;
 * if (status.value) return <div>User: {status.value.name}</div>;
 *
 * // Trigger the async operation
 * <button onClick={() => execute('user-123')}>Load User</button>
 * ```
 *
 * @see https://thibault.sh/hooks/use-async
 */
declare function useAsync<T>(asyncFunction: (...args: any[]) => Promise<T>): {
    execute: (...args: any[]) => Promise<void>;
    status: AsyncState<T>;
};
type Handler = (event: MouseEvent | TouchEvent) => void;
/**
 * Hook that detects clicks outside a referenced element and executes a callback.
 *
 * Useful for implementing dropdown menus, modals, or any component that should
 * close when the user clicks outside of it. Handles both mouse and touch events.
 *
 * @template T - The type of HTML element being referenced
 * @param ref - React ref object pointing to the element to monitor
 * @param handler - Callback function executed when a click occurs outside the element
 *
 * @example
 * ```tsx
 * function Dropdown() {
 *   const [isOpen, setIsOpen] = useState(false);
 *   const dropdownRef = useRef<HTMLDivElement>(null);
 *
 *   useClickOutside(dropdownRef, () => {
 *     setIsOpen(false);
 *   });
 *
 *   return (
 *     <div ref={dropdownRef}>
 *       <button onClick={() => setIsOpen(!isOpen)}>
 *         Toggle Dropdown
 *       </button>
 *       {isOpen && (
 *         <div className="dropdown-menu">
 *           <p>Dropdown content</p>
 *         </div>
 *       )}
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-click-outside
 */
declare const useClickOutside: <T extends HTMLElement = HTMLElement>(ref: RefObject<T | null> | null, handler: Handler) => void;
interface ContainerScroll {
    scrollTop: number;
    scrollLeft: number;
    scrollWidth: number;
    scrollHeight: number;
    clientWidth: number;
    clientHeight: number;
    isScrolling: boolean;
}
/**
 * Hook that tracks scroll position, dimensions, and scrolling state of a container element.
 *
 * Provides real-time scroll information including position, dimensions, and a debounced
 * scrolling indicator that's useful for optimizing scroll-based animations or effects.
 *
 * @param containerRef - React ref object pointing to the scrollable container element
 * @param delay - Delay in milliseconds before setting `isScrolling` to false (default: 150)
 *
 * @returns An object containing:
 *   - `scrollTop`: Vertical scroll position in pixels
 *   - `scrollLeft`: Horizontal scroll position in pixels
 *   - `scrollWidth`: Total scrollable width of the content
 *   - `scrollHeight`: Total scrollable height of the content
 *   - `clientWidth`: Visible width of the container
 *   - `clientHeight`: Visible height of the container
 *   - `isScrolling`: Boolean indicating if the user is currently scrolling (debounced)
 *
 * @example
 * ```tsx
 * const containerRef = useRef<HTMLDivElement>(null);
 * const scroll = useContainerScroll(containerRef, 200);
 *
 * return (
 *   <div ref={containerRef} className="scrollable-container">
 *     <div>Scroll position: {scroll.scrollTop}px</div>
 *     <div>Container size: {scroll.clientWidth}x{scroll.clientHeight}</div>
 *     <div>Content size: {scroll.scrollWidth}x{scroll.scrollHeight}</div>
 *     {scroll.isScrolling && <div>Currently scrolling...</div>}
 *
 *     <div style={{ height: '2000px' }}>Long content...</div>
 *   </div>
 * );
 * ```
 * @see https://thibault.sh/hooks/use-container-scroll
 */
declare function useContainerScroll(containerRef: RefObject<HTMLElement | null>, delay?: number): ContainerScroll;
/**
 * Options for configuring cookie behavior
 */
interface CookieOptions {
    /** Number of days until the cookie expires (default: 7) */
    days?: number;
    /** Cookie path (default: "/") */
    path?: string;
    /** Cookie domain */
    domain?: string;
    /** Whether the cookie requires HTTPS (default: false) */
    secure?: boolean;
    /** SameSite cookie attribute (default: "Lax") */
    sameSite?: "Strict" | "Lax" | "None";
}
/**
 * Hook for managing state that persists in browser cookies with SSR support.
 *
 * Provides a React state-like interface for reading, writing, and deleting cookies.
 * Automatically handles encoding/decoding, error handling, and server-side rendering compatibility.
 *
 * @param name - The name of the cookie to manage
 * @param initialValue - The default value to use when no cookie exists or on server-side
 *
 * @returns A tuple containing:
 *   - `value`: Current cookie value as string, or null if not set
 *   - `setCookie`: Function to update the cookie with optional configuration
 *   - `deleteCookie`: Function to remove the cookie from the browser
 *
 * @example
 * ```tsx
 * const [theme, setTheme, deleteTheme] = useCookieState('theme', 'light');
 *
 * // Read current value
 * console.log(theme); // 'light' or saved value
 *
 * // Update cookie with default options (7 days expiry)
 * setTheme('dark');
 *
 * // Update with custom options
 * setTheme('dark', {
 *   days: 30,
 *   secure: true,
 *   sameSite: 'Strict'
 * });
 *
 * // Remove the cookie
 * deleteTheme();
 * ```
 *
 * @example
 * ```tsx
 * // User preferences with longer expiry
 * const [userPrefs, setUserPrefs] = useCookieState('preferences', '{}');
 *
 * const updatePreference = (key: string, value: any) => {
 *   const prefs = JSON.parse(userPrefs || '{}');
 *   prefs[key] = value;
 *   setUserPrefs(JSON.stringify(prefs), { days: 365 });
 * };
 * ```
 * @see https://thibault.sh/hooks/use-cookie-state
 */
declare function useCookieState(name: string, initialValue: string): [string | null, (newValue: string, options?: CookieOptions) => void, () => void];
/**
 * Hook that creates a countdown timer to a target date with automatic updates.
 *
 * Provides real-time countdown values that update at a specified interval.
 * Returns zero values when the target date has passed.
 *
 * @param countDownDate - Target date as a timestamp in milliseconds (e.g., `new Date('2024-12-31').getTime()`)
 * @param refreshRate - Update interval in milliseconds (defaults to 1000ms for 1-second updates)
 *
 * @returns A readonly tuple `[days, hours, minutes, seconds]` representing time remaining
 *
 * @example
 * ```tsx
 * const targetDate = new Date('2024-12-31 23:59:59').getTime();
 * const [days, hours, minutes, seconds] = useCountdown(targetDate);
 *
 * return (
 *   <div>
 *     {days}d {hours}h {minutes}m {seconds}s remaining
 *   </div>
 * );
 * ```
 *
 * @example
 * // Custom refresh rate (every 100ms for smoother animation)
 * const [days, hours, minutes, seconds] = useCountdown(targetDate, 100);
 * @see https://thibault.sh/hooks/use-countdown
 */
declare function useCountdown(countDownDate: number, refreshRate?: number): number[] | readonly [number, number, number, number];
/**
 * Hook that tracks the state of a CSS media query and updates when it changes.
 *
 * Provides a reactive way to respond to viewport changes, screen sizes, or any
 * CSS media query conditions in your React components.
 *
 * @param query - The CSS media query string to track (e.g., "(min-width: 768px)")
 *
 * @returns Boolean indicating whether the media query currently matches
 *
 * @example
 * ```tsx
 * function ResponsiveComponent() {
 *   const isMobile = useMediaQuery('(max-width: 768px)');
 *   const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
 *   const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
 *
 *   return (
 *     <div>
 *       {isMobile && <MobileLayout />}
 *       {isTablet && <TabletLayout />}
 *       {isDarkMode ? <DarkTheme /> : <LightTheme />}
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-media-query
 */
declare const useMediaQuery: (query: string) => boolean;
/**
 * Hook that detects when an element is being hovered over.
 *
 * Provides a simple way to track hover state for any HTML element, with support
 * for both internal ref management and external ref usage.
 *
 * @template T - The type of HTML element being monitored (extends HTMLElement)
 * @param _ref - Optional React ref object for the element to monitor. If not provided,
 *               the hook will create and return its own ref.
 *
 * @returns A tuple containing:
 *   - `ref`: React ref object to attach to the target element
 *   - `isHovered`: Boolean indicating whether the element is currently being hovered
 *
 * @example
 * ```tsx
 * // Using the hook's internal ref
 * function HoverButton() {
 *   const [ref, isHovered] = useHover<HTMLButtonElement>();
 *
 *   return (
 *     <button
 *       ref={ref}
 *       style={{ backgroundColor: isHovered ? 'lightblue' : 'white' }}
 *     >
 *       {isHovered ? 'Hovered!' : 'Hover me'}
 *     </button>
 *   );
 * }
 *
 * // Using an external ref
 * function HoverDiv() {
 *   const myRef = useRef<HTMLDivElement>(null);
 *   const [, isHovered] = useHover(myRef);
 *
 *   return (
 *     <div ref={myRef}>
 *       {isHovered && <span>You're hovering!</span>}
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-hover
 */
declare const useHover: <T extends HTMLElement>(_ref?: RefObject<T | null> | null) => [RefObject<T>, boolean];
/**
 * Hook that detects when a specific key is pressed and held down.
 *
 * Tracks the current pressed state of a keyboard key, returning true while
 * the key is held down and false when released.
 *
 * @param targetKey - The key to detect (e.g., "Enter", "Escape", "ArrowUp", "a")
 *
 * @returns Boolean indicating if the target key is currently pressed
 *
 * @example
 * ```tsx
 * function GameControls() {
 *   const isSpacePressed = useKeyPress(' ');
 *   const isEnterPressed = useKeyPress('Enter');
 *   const isArrowUpPressed = useKeyPress('ArrowUp');
 *
 *   return (
 *     <div>
 *       <p>Space: {isSpacePressed ? 'Pressed' : 'Released'}</p>
 *       <p>Enter: {isEnterPressed ? 'Pressed' : 'Released'}</p>
 *       <p>Arrow Up: {isArrowUpPressed ? 'Pressed' : 'Released'}</p>
 *
 *       {isSpacePressed && <div>🚀 Boost active!</div>}
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-key-press
 */
declare function useKeyPress(targetKey: string): boolean;
type KeyCombo = string[];
/**
 * Hook that detects when a specific combination of keys is pressed simultaneously.
 *
 * Useful for implementing keyboard shortcuts, hotkeys, or complex key combinations
 * in your React components. The hook tracks all currently pressed keys and returns
 * true when all keys in the target combination are active.
 *
 * @param targetCombo - Array of key names that make up the combination
 *
 * @returns Boolean indicating if all keys in the combination are currently pressed
 *
 * @example
 * ```tsx
 * function App() {
 *   const isSaveCombo = useKeyCombo(['Control', 's']);
 *   const isUndoCombo = useKeyCombo(['Control', 'z']);
 *   const isComplexCombo = useKeyCombo(['Control', 'Shift', 'p']);
 *
 *   useEffect(() => {
 *     if (isSaveCombo) {
 *       console.log('Save shortcut pressed!');
 *       // Handle save action
 *     }
 *   }, [isSaveCombo]);
 *
 *   return (
 *     <div>
 *       <p>Press Ctrl+S to save</p>
 *       <p>Save combo active: {isSaveCombo ? 'Yes' : 'No'}</p>
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-key-combo
 */
declare function useKeyCombo(targetCombo: KeyCombo): boolean;
/**
 * Configuration options for the useLongPress hook
 */
interface LongPressOptions {
    /** Duration in milliseconds before long press is triggered (default: 400) */
    delay?: number;
    /** Whether to disable context menu on long press (default: true) */
    preventContext?: boolean;
    /** Callback fired when a normal press (shorter than delay) is completed */
    onPress?: () => void;
    /** Callback fired when a long press is successfully triggered */
    onLongPress?: () => void;
    /** Callback fired when a long press is canceled before completion */
    onLongPressCanceled?: () => void;
}
/**
 * Hook that handles both normal press and long press interactions with progress tracking.
 *
 * Provides event handlers for detecting short taps vs long presses, with smooth progress
 * animation and customizable timing. Works with both mouse and touch events.
 *
 * @param options - Configuration options for the long press behavior
 * @param options.delay - Duration in milliseconds before triggering long press (default: 400)
 * @param options.preventContext - Whether to prevent context menu on long press (default: true)
 * @param options.onPress - Callback for normal press (when released before delay)
 * @param options.onLongPress - Callback for successful long press (when delay is reached)
 * @param options.onLongPressCanceled - Callback when long press is interrupted
 *
 * @returns Object containing:
 *   - `handlers`: Event handlers to spread on your element
 *   - `state`: Current press state with `isPressed`, `isLongPressed`, and `progress` (0-1)
 *
 * @example
 * ```tsx
 * function DeleteButton({ onDelete }) {
 *   const { handlers, state } = useLongPress({
 *     delay: 1000,
 *     onPress: () => console.log('Quick tap - no action'),
 *     onLongPress: onDelete,
 *     onLongPressCanceled: () => console.log('Canceled deletion')
 *   });
 *
 *   return (
 *     <button {...handlers} className={state.isPressed ? 'pressing' : ''}>
 *       {state.isLongPressed
 *         ? 'Deleting...'
 *         : `Hold to delete (${Math.round(state.progress * 100)}%)`
 *       }
 *     </button>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-long-press
 */
declare function useLongPress(options?: LongPressOptions): {
    /** Event handlers to attach to the target element */
    handlers: {
        onMouseDown: (event: React.TouchEvent | React.MouseEvent) => void;
        onMouseUp: (event: React.TouchEvent | React.MouseEvent) => void;
        onMouseLeave: (event: React.TouchEvent | React.MouseEvent) => void;
        onTouchStart: (event: React.TouchEvent | React.MouseEvent) => void;
        onTouchEnd: (event: React.TouchEvent | React.MouseEvent) => void;
        onTouchCancel: (event: React.TouchEvent | React.MouseEvent) => void;
    };
    /** Current state of the press interaction */
    state: {
        isPressed: boolean;
        isLongPressed: boolean;
        progress: number;
    };
};
interface WindowSize {
    width: number;
    height: number;
}
/**
 * Hook that tracks the browser window dimensions and updates on resize.
 *
 * Automatically listens for window resize events and provides the current
 * width and height. Safe for SSR environments by checking for window availability.
 *
 * @returns An object containing:
 *   - `width`: Current window inner width in pixels
 *   - `height`: Current window inner height in pixels
 *
 * @example
 * ```tsx
 * function ResponsiveComponent() {
 *   const { width, height } = useWindowSize();
 *
 *   return (
 *     <div>
 *       <p>Window size: {width} x {height}</p>
 *       {width < 768 ? (
 *         <MobileLayout />
 *       ) : (
 *         <DesktopLayout />
 *       )}
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-window-size
 */
declare function useWindowSize(): WindowSize;
interface ScrollPosition {
    x: number;
    y: number;
}
/**
 * Hook that tracks the current window scroll position in real-time.
 *
 * Automatically updates when the user scrolls and handles SSR scenarios
 * by safely checking for window availability.
 *
 * @returns An object containing:
 *   - `x`: Horizontal scroll position in pixels
 *   - `y`: Vertical scroll position in pixels
 *
 * @example
 * ```tsx
 * function ScrollIndicator() {
 *   const { x, y } = useScrollPosition();
 *
 *   return (
 *     <div className="scroll-info">
 *       <p>Horizontal: {x}px</p>
 *       <p>Vertical: {y}px</p>
 *       {y > 100 && (
 *         <button onClick={() => window.scrollTo(0, 0)}>
 *           Back to Top
 *         </button>
 *       )}
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-scroll-position
 */
declare function useScrollPosition(): ScrollPosition;
interface ElementSize {
    width: number;
    height: number;
}
/**
 * Hook that tracks an element's dimensions and updates when the element is resized.
 *
 * Uses ResizeObserver to efficiently monitor size changes and provides real-time
 * width and height measurements. Automatically handles cleanup and provides
 * initial measurements immediately.
 *
 * @param elementRef - React ref object pointing to the target HTML element
 *
 * @returns An object containing:
 *   - `width`: Current width of the element in pixels
 *   - `height`: Current height of the element in pixels
 *
 * @example
 * ```tsx
 * function ResizableComponent() {
 *   const elementRef = useRef<HTMLDivElement>(null);
 *   const { width, height } = useElementSize(elementRef);
 *
 *   return (
 *     <div>
 *       <div ref={elementRef} style={{ resize: 'both', overflow: 'auto' }}>
 *         Resizable content
 *       </div>
 *       <p>Size: {width} x {height}px</p>
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-element-size
 */
declare function useElementSize<T extends HTMLElement>(elementRef: RefObject<T | null> | null): ElementSize;
interface IntersectionOptions extends IntersectionObserverInit {
    freezeOnceVisible?: boolean;
}
/**
 * Hook that tracks when an element enters or leaves the viewport using the Intersection Observer API.
 *
 * Useful for implementing lazy loading, infinite scrolling, animations on scroll,
 * or tracking visibility of elements for analytics purposes.
 *
 * @param elementRef - React ref object pointing to the target element to observe
 * @param options - Configuration options for the intersection observer:
 *   - `threshold`: Number or array defining at what percentage of visibility the callback should trigger (0-1)
 *   - `root`: Element used as viewport for checking visibility (defaults to browser viewport)
 *   - `rootMargin`: Margin around the root element (CSS-like syntax, e.g., "10px 20px")
 *   - `freezeOnceVisible`: If true, stops observing once element becomes visible (useful for one-time animations)
 *
 * @returns IntersectionObserverEntry object containing visibility information, or null if element not found
 *
 * @example
 * ```tsx
 * function LazyImage({ src, alt }: { src: string; alt: string }) {
 *   const imgRef = useRef<HTMLImageElement>(null);
 *   const entry = useIntersectionObserver(imgRef, {
 *     threshold: 0.1,
 *     freezeOnceVisible: true
 *   });
 *
 *   const isVisible = entry?.isIntersecting;
 *
 *   return (
 *     <img
 *       ref={imgRef}
 *       src={isVisible ? src : undefined}
 *       alt={alt}
 *       style={{ opacity: isVisible ? 1 : 0 }}
 *     />
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-intersection-observer
 */
declare function useIntersectionObserver<T extends HTMLElement>(elementRef: RefObject<T | null> | null, { threshold, root, rootMargin, freezeOnceVisible }?: IntersectionOptions): IntersectionObserverEntry | null;
interface ResizeObserverEntry {
    contentRect: DOMRectReadOnly;
    contentBoxSize: ReadonlyArray<ResizeObserverSize>;
    borderBoxSize: ReadonlyArray<ResizeObserverSize>;
    devicePixelContentBoxSize: ReadonlyArray<ResizeObserverSize>;
    target: Element;
}
/**
 * Hook that observes element size changes using the ResizeObserver API.
 *
 * Provides detailed resize information including content rect, box sizes, and device pixel ratios.
 * Automatically cleans up the observer when the component unmounts or the ref changes.
 *
 * @param elementRef - React ref object pointing to the target element to observe
 *
 * @returns ResizeObserverEntry with detailed size information, or null if no element or no resize has occurred
 *   - `contentRect`: The content rectangle of the element
 *   - `contentBoxSize`: Array of content box dimensions
 *   - `borderBoxSize`: Array of border box dimensions
 *   - `devicePixelContentBoxSize`: Array of device pixel content box dimensions
 *   - `target`: The observed element
 *
 * @example
 * ```tsx
 * function ResponsiveComponent() {
 *   const containerRef = useRef<HTMLDivElement>(null);
 *   const resizeEntry = useResizeObserver(containerRef);
 *
 *   const width = resizeEntry?.contentRect.width ?? 0;
 *   const height = resizeEntry?.contentRect.height ?? 0;
 *
 *   return (
 *     <div ref={containerRef}>
 *       <p>Size: {width} x {height}</p>
 *       <div>Content adapts based on container size</div>
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-resize-observer
 */
declare function useResizeObserver<T extends HTMLElement>(elementRef: RefObject<T | null> | null): ResizeObserverEntry | null;
/**
 * Hook that debounces a value, delaying updates until after the specified delay.
 *
 * Useful for optimizing performance in scenarios like search inputs, API calls,
 * or any situation where you want to limit how often a value changes.
 *
 * @template T - The type of the value being debounced
 * @param value - The value to debounce
 * @param delay - The delay in milliseconds before the value updates
 *
 * @returns The debounced value that only updates after the delay period
 *
 * @example
 * ```tsx
 * function SearchInput() {
 *   const [searchTerm, setSearchTerm] = useState('');
 *   const debouncedSearchTerm = useDebounce(searchTerm, 300);
 *
 *   useEffect(() => {
 *     if (debouncedSearchTerm) {
 *       // This will only run 300ms after the user stops typing
 *       searchAPI(debouncedSearchTerm);
 *     }
 *   }, [debouncedSearchTerm]);
 *
 *   return (
 *     <input
 *       value={searchTerm}
 *       onChange={(e) => setSearchTerm(e.target.value)}
 *       placeholder="Search..."
 *     />
 *   );
 * }
 * ```
 * @see https://thibault.sh/hooks/use-debounce
 */
declare function useDebounce<T>(value: T, delay: number): T;
/**
 * Hook that throttles a value, limiting how often it can update.
 *
 * Unlike debouncing which delays execution until after a quiet period, throttling
 * ensures the value updates at most once per specified interval, making it ideal
 * for scroll events, resize handlers, or any high-frequency updates.
 *
 * @template T - The type of the value being throttled
 * @param value - The value to throttle
 * @param interval - The minimum time interval between updates in milliseconds
 *
 * @returns The throttled value that updates at most once per interval
 *
 * @example
 * ```tsx
 * function ScrollTracker() {
 *   const [scrollY, setScrollY] = useState(0);
 *   const throttledScrollY = useThrottle(scrollY, 100);
 *
 *   useEffect(() => {
 *     const handleScroll = () => setScrollY(window.scrollY);
 *     window.addEventListener('scroll', handleScroll);
 *     return () => window.removeEventListener('scroll', handleScroll);
 *   }, []);
 *
 *   useEffect(() => {
 *     // This will only run at most once every 100ms
 *     console.log('Throttled scroll position:', throttledScrollY);
 *   }, [throttledScrollY]);
 *
 *   return <div>Scroll position: {throttledScrollY}px</div>;
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-throttle
 */
declare function useThrottle<T>(value: T, interval: number): T;
/**
 * Hook that creates a setInterval that automatically cleans up on unmount.
 *
 * Provides a declarative way to use intervals in React components with proper
 * cleanup and the ability to pause/resume by passing null as the delay.
 *
 * @param callback - The function to execute on each interval tick
 * @param delay - The delay in milliseconds between executions, or null to pause the interval
 *
 * @example
 * ```tsx
 * function Timer() {
 *   const [count, setCount] = useState(0);
 *   const [isRunning, setIsRunning] = useState(true);
 *
 *   // Increment count every second when running
 *   useInterval(() => {
 *     setCount(count => count + 1);
 *   }, isRunning ? 1000 : null);
 *
 *   return (
 *     <div>
 *       <p>Count: {count}</p>
 *       <button onClick={() => setIsRunning(!isRunning)}>
 *         {isRunning ? 'Pause' : 'Resume'}
 *       </button>
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-interval
 */
declare function useInterval(callback: () => void, delay: number | null): void;
type EventMap = WindowEventMap & HTMLElementEventMap & DocumentEventMap;
/**
 * Hook that adds an event listener to a target element with automatic cleanup.
 *
 * Automatically handles adding and removing event listeners, ensuring proper cleanup
 * when the component unmounts or dependencies change. Supports all standard DOM events
 * on window, document, or specific HTML elements.
 *
 * @template K - The event type key from the event map
 * @param eventName - The name of the event to listen for (e.g., 'click', 'keydown', 'resize')
 * @param handler - The event handler function that will be called when the event fires
 * @param element - Optional ref to the target element. Defaults to window if not provided
 * @param options - Optional event listener options (capture, once, passive, etc.)
 *
 * @example
 * ```tsx
 * function Component() {
 *   const buttonRef = useRef<HTMLButtonElement>(null);
 *
 *   // Listen for clicks on a specific element
 *   useEventListener('click', (e) => {
 *     console.log('Button clicked!', e);
 *   }, buttonRef);r
 *
 *   // Listen for window resize events
 *   useEventListener('resize', () => {
 *     console.log('Window resized');
 *   });
 *
 *   // Listen for escape key presses
 *   useEventListener('keydown', (e) => {
 *     if (e.key === 'Escape') {
 *       console.log('Escape pressed');
 *     }
 *   });
 *
 *   return <button ref={buttonRef}>Click me</button>;
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-event-listener
 */
declare function useEventListener<K extends keyof EventMap, T extends HTMLElement>(eventName: K, handler: (event: EventMap[K]) => void, element?: RefObject<T | null> | null, options?: boolean | AddEventListenerOptions): void;
/**
 * Hook that manages state synchronized with localStorage.
 *
 * Provides a useState-like interface that automatically persists state changes
 * to localStorage and initializes from stored values on mount. Handles SSR
 * compatibility and JSON serialization/deserialization automatically.
 *
 * @template T - The type of the value being stored
 * @param key - The localStorage key to use for persistence
 * @param initialValue - The default value to use if no stored value exists
 *
 * @returns A tuple containing:
 *   - Current stored value (T)
 *   - Setter function that updates both state and localStorage
 *
 * @example
 * ```tsx
 * function UserPreferences() {
 *   const [theme, setTheme] = useLocalStorageState('theme', 'light');
 *   const [settings, setSettings] = useLocalStorageState('settings', {
 *     notifications: true,
 *     language: 'en'
 *   });
 *
 *   return (
 *     <div>
 *       <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
 *         Current theme: {theme}
 *       </button>
 *
 *       <button onClick={() => setSettings(prev => ({
 *         ...prev,
 *         notifications: !prev.notifications
 *       }))}>
 *         Notifications: {settings.notifications ? 'On' : 'Off'}
 *       </button>
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-local-storage-state
 */
declare function useLocalStorageState<T>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void];
/**
 * Hook that manages state synchronized with sessionStorage.
 *
 * Provides persistent state that survives page refreshes but is cleared when
 * the browser tab is closed. Automatically handles JSON serialization/deserialization
 * and provides SSR-safe initialization.
 *
 * @template T - The type of the stored value
 * @param key - The sessionStorage key to store the value under
 * @param initialValue - The default value used when no stored value exists
 *
 * @returns A tuple containing:
 *   - The current stored value (or initial value if none exists)
 *   - A setter function that updates both state and sessionStorage
 *
 * @example
 * ```tsx
 * function UserPreferences() {
 *   const [theme, setTheme] = useSessionStorageState('theme', 'light');
 *   const [sidebarOpen, setSidebarOpen] = useSessionStorageState('sidebar', true);
 *
 *   return (
 *     <div>
 *       <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
 *         Current theme: {theme}
 *       </button>
 *       <button onClick={() => setSidebarOpen(!sidebarOpen)}>
 *         Sidebar: {sidebarOpen ? 'Open' : 'Closed'}
 *       </button>
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-session-storage-state
 */
declare function useSessionStorageState<T>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void];
/**
 * Hook that manages state synchronized with URL query parameters.
 *
 * Automatically persists state to the URL and keeps it in sync with browser
 * navigation (back/forward buttons). Perfect for shareable URLs and maintaining
 * state across page refreshes.
 *
 * @template T - The type of the state value
 * @param key - The query parameter key to use in the URL
 * @param initialValue - Default value when the parameter doesn't exist
 * @param options - Configuration options for serialization
 * @param options.serialize - Custom function to convert value to string (defaults to JSON.stringify)
 * @param options.deserialize - Custom function to parse string back to value (defaults to JSON.parse)
 *
 * @returns A tuple containing:
 *   - Current state value (synced with URL)
 *   - Setter function (updates both state and URL)
 *
 * @example
 * ```tsx
 * function SearchPage() {
 *   const [query, setQuery] = useQueryParamsState('q', '');
 *   const [filters, setFilters] = useQueryParamsState('filters', { category: 'all' });
 *
 *   return (
 *     <div>
 *       <input
 *         value={query}
 *         onChange={(e) => setQuery(e.target.value)}
 *         placeholder="Search..."
 *       />
 *       <select
 *         value={filters.category}
 *         onChange={(e) => setFilters({ ...filters, category: e.target.value })}
 *       >
 *         <option value="all">All</option>
 *         <option value="books">Books</option>
 *       </select>
 *     </div>
 *   );
 * }
 * ```
 *
 * @see https://thibault.sh/hooks/use-query-params-state
 */
declare function useQueryParamsState<T>(key: string, initialValue: T, options?: {
    serialize?: (value: T) => string;
    deserialize?: (value: string) => T;
}): [T, (value: T | ((val: T) => T)) => void];
export { useAsync, useClickOutside, useContainerScroll, useCookieState, useCountdown, useDebounce, useElementSize, useEventListener, useHover, useIntersectionObserver, useInterval, useKeyCombo, useKeyPress, useLocalStorageState, useLongPress, useMediaQuery, useQueryParamsState, useResizeObserver, useScrollPosition, useSessionStorageState, useThrottle, useWindowSize };