UNPKG

@thibault.sh/hooks

Version:

A comprehensive collection of React hooks for browser storage, UI interactions, and more

307 lines (283 loc) 12.4 kB
import { RefObject } from 'react'; interface AsyncState<T> { isLoading: boolean; error: Error | null; value: T | null; } /** * Hook that handles async operations with loading and error states * @param asyncFunction - Async function to execute * @returns Object containing execute function, loading state, error, and value */ 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 handles click outside of the referenced element * @param ref - React ref object for the element to monitor * @param handler - Callback function to execute when click outside occurs */ declare const useClickOutside: <T extends HTMLElement = HTMLElement>(ref: RefObject<T | null> | null, handler: Handler) => void; /** * Hook that tracks state of a CSS media query * @param query - CSS media query string * @returns boolean indicating if the media query matches */ declare const useMediaQuery: (query: string) => boolean; /** * Hook that detects hover state on an element * @param ref - (optional) React ref object for the element to monitor * @returns Tuple containing ref to attach to element and boolean indicating hover state */ declare const useHover: <T extends HTMLElement>(_ref?: RefObject<T | null> | null) => [RefObject<T>, boolean]; /** * Hook that detects when a specific key is pressed * @param targetKey - The key to detect (e.g., "Enter", "Escape", "a") * @returns boolean indicating if the key is currently pressed */ declare function useKeyPress(targetKey: string): boolean; type KeyCombo = string[]; /** * Hook that detects when a specific combination of keys is pressed * @param targetCombo - Array of keys that make up the combination (e.g., ["Control", "Shift", "a"]) * @returns boolean indicating if the combination is currently active */ 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; } /** * A hook that handles both normal press and long press interactions * * @param options - Configuration options for the long press behavior * @param options.delay - Duration in milliseconds before a press is considered a long press (default: 400) * @param options.preventContext - When true, prevents the default context menu on long press (default: true) * @param options.onPress - Callback fired when a normal press (shorter than delay) is completed. * Triggers only if the press duration was less than the specified delay * @param options.onLongPress - Callback fired when a long press is successfully triggered. * Triggers exactly once when the press duration exceeds the delay * @param options.onLongPressCanceled - Callback fired when a long press is canceled before completion. * Triggers if the press is released or canceled before reaching the delay threshold * @returns Object containing event handlers and current press state * * @example * ```tsx * const MyComponent = () => { * const { handlers, state } = useLongPress({ * delay: 1000, * onPress: () => console.log('Normal press'), * onLongPress: () => console.log('Long press completed'), * onLongPressCanceled: () => console.log('Long press canceled'), * }); * * return ( * <button {...handlers}> * {state.isLongPressed * ? 'Long Press!' * : `Hold me (${Math.round(state.progress * 100)}%)`} * </button> * ); * }; * ``` */ 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 window dimensions * @returns Object containing current window width and height * @example * const { width, height } = useWindowSize(); * console.log(width, height); */ declare function useWindowSize(): WindowSize; interface ScrollPosition { x: number; y: number; } /** * Hook that tracks window scroll position * @returns Object containing current scroll x and y coordinates */ declare function useScrollPosition(): ScrollPosition; interface ContainerScroll { scrollTop: number; scrollLeft: number; scrollWidth: number; scrollHeight: number; clientWidth: number; clientHeight: number; isScrolling: boolean; } /** * Hook that tracks scroll position and dimensions of a container element * @param containerRef - React ref object pointing to the container element * @param delay - Delay in milliseconds before setting isScrolling to false * @returns Object containing scroll position and dimension information */ declare function useContainerScroll(containerRef: RefObject<HTMLElement | null>, delay?: number): ContainerScroll; interface ElementSize { width: number; height: number; } /** * Hook that tracks an element's dimensions using ResizeObserver * @param elementRef - React ref object pointing to the target element * @returns Object containing current element width and height */ declare function useElementSize(elementRef: RefObject<HTMLElement>): ElementSize; interface IntersectionOptions extends IntersectionObserverInit { freezeOnceVisible?: boolean; } /** * Hook that tracks element's intersection with viewport using IntersectionObserver * @param elementRef - React ref object pointing to the target element * @param options - IntersectionObserver options with additional freezeOnceVisible flag * @returns IntersectionObserverEntry if available, null otherwise */ declare function useIntersectionObserver(elementRef: RefObject<HTMLElement>, { threshold, root, rootMargin, freezeOnceVisible, }?: IntersectionOptions): IntersectionObserverEntry | null; interface ResizeObserverEntry { contentRect: DOMRectReadOnly; contentBoxSize: ReadonlyArray<ResizeObserverSize>; borderBoxSize: ReadonlyArray<ResizeObserverSize>; devicePixelContentBoxSize: ReadonlyArray<ResizeObserverSize>; target: Element; } /** * Hook that tracks element's size changes using ResizeObserver with full entry details * @param elementRef - React ref object pointing to the target element * @returns Latest ResizeObserverEntry if available, null otherwise */ declare function useResizeObserver(elementRef: RefObject<HTMLElement>): ResizeObserverEntry | null; /** * Hook that debounces a value * @param value - The value to debounce * @param delay - The delay in milliseconds * @returns The debounced value */ declare function useDebounce<T>(value: T, delay: number): T; /** * Hook that throttles a value * @param value - The value to throttle * @param interval - The minimum time interval between updates in milliseconds * @returns The throttled value */ declare function useThrottle<T>(value: T, interval: number): T; interface TimerControls { start: () => void; pause: () => void; reset: () => void; isRunning: boolean; } /** * Hook that provides a timer with controls * @param initialTime - Initial time in seconds * @param step - Time step in seconds (default: 1) * @param countDown - Whether to count down instead of up (default: false) * @returns [currentTime, controls] */ declare function useTimer(initialTime: number, step?: number, countDown?: boolean): [number, TimerControls]; /** * Hook that sets up an interval that is properly cleaned up when the component unmounts * @param callback - Function to call on each interval * @param delay - Delay in milliseconds (null to pause) */ declare function useInterval(callback: () => void, delay: number | null): void; type EventMap = WindowEventMap & HTMLElementEventMap & DocumentEventMap; /** * Hook that adds an event listener to a target element or window * @param eventName - Name of the event to listen for * @param handler - Event handler function * @param element - Target element (defaults to window) * @param options - AddEventListener options */ declare function useEventListener<K extends keyof EventMap>(eventName: K, handler: (event: EventMap[K]) => void, element?: RefObject<HTMLElement> | null, options?: boolean | AddEventListenerOptions): void; /** * 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 persisted in a browser cookie * @param name - The name of the cookie * @param initialValue - The initial value to use if no cookie exists * @returns A tuple containing: * - The current cookie value (or null if not set) * - A function to update the cookie value and its options * - A function to delete the cookie */ declare function useCookieState(name: string, initialValue: string): [string | null, (newValue: string, options?: CookieOptions) => void, () => void]; /** * Hook for managing state persisted in localStorage * @param key - The localStorage key * @param initialValue - The initial value to use if no value exists in storage * @returns A tuple containing the current value and a setter function * @example * const [value, setValue] = useLocalStorageState('my-key', 'initial value'); */ declare function useLocalStorageState<T>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void]; /** * Hook for managing state persisted in sessionStorage * @param key - The sessionStorage key * @param initialValue - The initial value to use if no value exists in storage * @returns A tuple containing the current value and a setter function * @example * const [value, setValue] = useSessionStorageState('my-key', 'initial value'); */ declare function useSessionStorageState<T>(key: string, initialValue: T): [T, (value: T | ((val: T) => T)) => void]; /** * Hook for managing state persisted in URL query parameters * @param key - The query parameter key * @param initialValue - The initial value to use if the parameter doesn't exist * @param options - Configuration options * @param options.serialize - Function to convert value to string (default: JSON.stringify) * @param options.deserialize - Function to parse string back to value (default: JSON.parse) * @returns A tuple containing the current value and a setter function */ 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, useDebounce, useElementSize, useEventListener, useHover, useIntersectionObserver, useInterval, useKeyCombo, useKeyPress, useLocalStorageState, useLongPress, useMediaQuery, useQueryParamsState, useResizeObserver, useScrollPosition, useSessionStorageState, useThrottle, useTimer, useWindowSize };