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

622 lines (507 loc) 15.7 kB
# Qazuor React Custom Hooks <div align="center"> <img src="logo.webp" alt="React Custom Hooks Library Logo" width="150" /> <div style="margin-top: 25px; margin-bottom: 25px"> <a href="https://www.npmjs.com/package/@qazuor/react-hooks"><img src="https://img.shields.io/npm/v/@qazuor/react-hooks.svg" alt="npm version" /></a> <a href="https://www.npmjs.com/package/@qazuor/react-hooks"><img src="https://img.shields.io/npm/dm/@qazuor/react-hooks.svg" alt="npm downloads" /></a> <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a> <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-4.9+-blue.svg" alt="TypeScript" /></a> <a href="https://reactjs.org/"><img src="https://img.shields.io/badge/React-18.2+-blue.svg" alt="React" /></a> </div> </div> A collection of high-quality, fully tested React hooks for common use cases. Written in TypeScript with comprehensive documentation and examples. ## Table of Contents - [Qazuor React Custom Hooks](#qazuor-react-custom-hooks) - [Table of Contents](#table-of-contents) - [Features](#features) - [Installation](#installation) - [Available Hooks](#available-hooks) - [State Management](#state-management) - [useBoolean](#useboolean) - [useToggle](#usetoggle) - [useQueue](#usequeue) - [Side Effects](#side-effects) - [useTimeout](#usetimeout) - [useInterval](#useinterval) - [useHandledInterval](#usehandledinterval) - [useDebounce](#usedebounce) - [Browser APIs](#browser-apis) - [useLocalStorage](#uselocalstorage) - [useSessionStorage](#usesessionstorage) - [useCopyToClipboard](#usecopytoclipboard) - [useMediaQuery](#usemediaquery) - [useNetworkState](#usenetworkstate) - [useVisibilityChange](#usevisibilitychange) - [useWindowWidth](#usewindowwidth) - [User Interaction](#user-interaction) - [useClickOutside](#useclickoutside) - [useIdleness](#useidleness) - [usePageLeave](#usepageleave) - [useLockBodyScroll](#uselockbodyscroll) - [useMeasure](#usemeasure) - [Development](#development) - [useLogger](#uselogger) - [TypeScript Support](#typescript-support) - [Browser Support](#browser-support) - [Contributing](#contributing) - [License](#license) - [Author](#author) ## Features - 📦 20+ Custom Hooks - 🔒 Type-safe with TypeScript - 📚 Comprehensive documentation - ✅ Fully tested - 🎯 Zero dependencies - 🌳 Tree-shakeable - 💻 SSR compatible ## Installation ```bash # Using npm npm install @qazuor/react-hooks # Using yarn yarn add @qazuor/react-hooks # Using pnpm pnpm add @qazuor/react-hooks ``` ## Available Hooks ### State Management #### useBoolean Manages a boolean state with convenient methods. ```tsx import { useBoolean } from '@qazuor/react-hooks'; function Modal() { const { value: isOpen, setTrue: open, setFalse: close } = useBoolean(false); return ( <> <button onClick={open} type="button">Open Modal</button> {isOpen && ( <div className="modal"> <button onClick={close} type="button">Close</button> <h1>Modal Content</h1> </div> )} </> ); } ``` #### useToggle Manages a toggleable boolean state with persistence options. ```tsx import { useToggle } from '@qazuor/react-hooks'; function ThemeToggle() { const { value: isDark, toggle } = useToggle({ initialValue: false, persist: true, storageKey: 'theme-preference' }); return ( <button onClick={toggle} type="button"> Current theme: {isDark ? 'Dark' : 'Light'} </button> ); } ``` #### useQueue Implements a FIFO queue with state management. ```tsx import { useQueue } from '@qazuor/react-hooks'; function TaskQueue() { const { enqueue, dequeue, peek, size, isEmpty } = useQueue<string>(); return ( <div> <button onClick={() => enqueue(`Task ${size + 1}`)} type="button"> Add Task </button> <button onClick={dequeue} disabled={isEmpty} type="button"> Process Next </button> <p>Next task: {peek() || 'No tasks'}</p> <p>Queue size: {size}</p> </div> ); } ``` ### Side Effects #### useTimeout Execute a callback after a delay with control methods. ```tsx import { useTimeout } from '@qazuor/react-hooks'; function AutoDismiss() { const [visible, setVisible] = useState(true); const { isPending, reset } = useTimeout({ callback: () => setVisible(false), delay: 3000 }); return visible && ( <div> <p>I will disappear in 3 seconds!</p> <button onClick={reset} type="button">Reset Timer</button> </div> ); } ``` #### useInterval Execute a callback at regular intervals with pause/resume functionality. ```tsx import { useInterval } from '@qazuor/react-hooks'; function Counter() { const [count, setCount] = useState(0); const { isRunning, start, pause } = useInterval({ callback: () => setCount(c => c + 1), delay: 1000 }); return ( <div> <p>Count: {count}</p> <button onClick={isRunning ? pause : start} type="button"> {isRunning ? 'Pause' : 'Start'} </button> </div> ); } ``` #### useHandledInterval Enhanced interval with random delay options and more control. ```tsx import { useHandledInterval } from '@qazuor/react-hooks'; function RandomTimer() { const [count, setCount] = useState(0); const { isRunning, start, pause, reset } = useHandledInterval({ callback: () => setCount(c => c + 1), delay: 1000, random: true, minDelay: 500 }); return ( <div> <p>Random intervals count: {count}</p> <button onClick={isRunning ? pause : start} type="button"> {isRunning ? 'Pause' : 'Start'} </button> <button onClick={reset} type="button">Reset</button> </div> ); } ``` #### useDebounce Debounce a value with configurable delay. ```tsx import { useDebounce } from '@qazuor/react-hooks'; function SearchInput() { const [value, setValue] = useState(''); const debouncedValue = useDebounce(value, 500); useEffect(() => { // API call with debouncedValue console.log('Searching:', debouncedValue); }, [debouncedValue]); return ( <input value={value} onChange={(e) => setValue(e.target.value)} placeholder="Search..." /> ); } ``` ### Browser APIs #### useLocalStorage Persist state in localStorage with type safety. ```tsx import { useLocalStorage } from '@qazuor/react-hooks'; function UserPreferences() { const [preferences, setPreferences] = useLocalStorage('user-prefs', { theme: 'light', fontSize: 16 }); return ( <div> <button onClick={() => setPreferences(p => ({ ...p, theme: p.theme === 'light' ? 'dark' : 'light' }))} type="button" > Toggle Theme </button> <select value={preferences.fontSize} onChange={(e) => setPreferences(p => ({ ...p, fontSize: Number(e.target.value) }))} > <option value="14">Small</option> <option value="16">Medium</option> <option value="18">Large</option> </select> </div> ); } ``` #### useSessionStorage Persist state in sessionStorage. ```tsx import { useSessionStorage } from '@qazuor/react-hooks'; function FormWithAutosave() { const [formData, setFormData] = useSessionStorage('form-draft', { title: '', content: '' }); return ( <form> <input value={formData.title} onChange={(e) => setFormData(prev => ({ ...prev, title: e.target.value }))} placeholder="Title" /> <textarea value={formData.content} onChange={(e) => setFormData(prev => ({ ...prev, content: e.target.value }))} placeholder="Content" /> </form> ); } ``` #### useCopyToClipboard Copy text to clipboard with status feedback. ```tsx import { useCopyToClipboard } from '@qazuor/react-hooks'; function ShareButton() { const { copy, copied, error } = useCopyToClipboard(); const url = window.location.href; return ( <button onClick={() => copy(url)} type="button" className={copied ? 'success' : error ? 'error' : ''} > {copied ? 'Copied!' : error ? 'Failed to copy' : 'Copy URL'} </button> ); } ``` #### useMediaQuery React to media query changes. ```tsx import { useMediaQuery } from '@qazuor/react-hooks'; function ResponsiveLayout() { const isMobile = useMediaQuery('(max-width: 768px)'); const prefersDark = useMediaQuery('(prefers-color-scheme: dark)'); return ( <div className={`layout ${isMobile ? 'mobile' : 'desktop'} ${prefersDark ? 'dark' : 'light'}`}> <p>Current layout: {isMobile ? 'Mobile' : 'Desktop'}</p> <p>Theme preference: {prefersDark ? 'Dark' : 'Light'}</p> </div> ); } ``` #### useNetworkState Track network connectivity status. ```tsx import { useNetworkState } from '@qazuor/react-hooks'; function NetworkIndicator() { const { online, type, rtt } = useNetworkState(); return ( <div> <div className={`status-dot ${online ? 'online' : 'offline'}`} /> {online && ( <> <p>Connection: {type}</p> <p>Latency: {rtt}ms</p> </> )} </div> ); } ``` #### useVisibilityChange Track document visibility state. ```tsx import { useVisibilityChange } from '@qazuor/react-hooks'; function VideoPlayer() { const videoRef = useRef<HTMLVideoElement>(null); const { isVisible } = useVisibilityChange({ onHidden: () => videoRef.current?.pause(), onVisible: () => videoRef.current?.play() }); return ( <div> <video ref={videoRef} /> <p>Video is {isVisible ? 'visible' : 'hidden'}</p> </div> ); } ``` #### useWindowWidth Track window width with debouncing. ```tsx import { useWindowWidth } from '@qazuor/react-hooks'; function ResponsiveComponent() { const { width } = useWindowWidth({ debounceDelay: 250, onChange: (w) => console.log(`Window width changed to ${w}px`) }); return ( <div> <p>Window width: {width}px</p> {width > 1024 ? ( <h1>Desktop View</h1> ) : width > 768 ? ( <h2>Tablet View</h2> ) : ( <h3>Mobile View</h3> )} </div> ); } ``` ### User Interaction #### useClickOutside Detect clicks outside an element. ```tsx import { useClickOutside } from '@qazuor/react-hooks'; function Dropdown() { const [isOpen, setIsOpen] = useState(false); const ref = useRef(null); useClickOutside(ref, () => setIsOpen(false)); return ( <div ref={ref}> <button onClick={() => setIsOpen(true)} type="button"> Toggle Dropdown </button> {isOpen && ( <ul className="dropdown-menu"> <li>Option 1</li> <li>Option 2</li> </ul> )} </div> ); } ``` #### useIdleness Track user idle state. ```tsx import { useIdleness } from '@qazuor/react-hooks'; function IdleMonitor() { const { isIdle, reset } = useIdleness({ timeout: 5000, onIdleChange: (idle) => { if (idle) { console.log('User is idle'); } else { console.log('User is active'); } } }); return ( <div> <p>User is currently {isIdle ? 'idle' : 'active'}</p> <button onClick={reset} type="button">Reset Idle Timer</button> </div> ); } ``` #### usePageLeave Detect when user attempts to leave page. ```tsx import { usePageLeave } from '@qazuor/react-hooks'; function ExitIntent() { const { hasLeft } = usePageLeave({ onLeave: () => console.log('Mouse left the page'), threshold: 10 }); return hasLeft && ( <div className="exit-popup"> <h2>Wait! Don't leave yet...</h2> <p>Would you like to subscribe to our newsletter?</p> </div> ); } ``` #### useLockBodyScroll Prevent body scrolling. ```tsx import { useLockBodyScroll } from '@qazuor/react-hooks'; function Modal({ isOpen }: { isOpen: boolean }) { const { isLocked, lock, unlock } = useLockBodyScroll({ lockImmediately: isOpen, preservePosition: true }); useEffect(() => { if (isOpen) { lock(); } else { unlock(); } }, [isOpen, lock, unlock]); return isOpen && ( <div className="modal"> <h2>Modal Content</h2> <p>Body scroll is {isLocked ? 'locked' : 'unlocked'}</p> </div> ); } ``` #### useMeasure Measure DOM elements. ```tsx import { useMeasure } from '@qazuor/react-hooks'; function ResizableBox() { const { ref, size } = useMeasure(); return ( <div ref={ref} style={{ resize: 'both', overflow: 'auto', minWidth: '100px', minHeight: '100px', border: '1px solid black' }} > <p>Width: {size.width}px</p> <p>Height: {size.height}px</p> </div> ); } ``` ### Development #### useLogger Debug values with console logging. ```tsx import { useLogger } from '@qazuor/react-hooks'; function DebugComponent() { const [count, setCount] = useState(0); useLogger('Counter Value', count, { level: 'info', timestamp: true, formatter: (label, value) => `${label}: ${value} (${new Date().toISOString()})` }); return ( <button onClick={() => setCount(c => c + 1)} type="button"> Increment ({count}) </button> ); } ``` ## TypeScript Support All hooks are written in TypeScript and include comprehensive type definitions. Generic types are used where appropriate to ensure type safety. ```tsx interface UserPreferences { theme: 'light' | 'dark'; fontSize: number; } // Type-safe localStorage hook const [preferences, setPreferences] = useLocalStorage<UserPreferences>('prefs', { theme: 'light', fontSize: 16 }); // TypeScript knows the correct types preferences.theme; // 'light' | 'dark' preferences.fontSize; // number ``` ## Browser Support The library supports all modern browsers. Some hooks may require specific browser features - check individual hook documentation for details. ## Contributing Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests. ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Author Leandro Asrilevich ([@qazuor](https://github.com/qazuor))