{"_id":"@bonhomie/useful-hooks","_rev":"5-cdae5fa3877bf4d9a749485defe60164","name":"@bonhomie/useful-hooks","dist-tags":{"latest":"2.1.0"},"versions":{"1.0.0":{"name":"@bonhomie/useful-hooks","version":"1.0.0","keywords":["react","hooks","react-hooks","usehooks","frontend","javascript","bonhomie"],"author":{"name":"Bonhomie"},"license":"MIT","_id":"@bonhomie/useful-hooks@1.0.0","maintainers":[{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"}],"dist":{"shasum":"a2b0b7ad0b37f890288354230d5fbda592403b80","tarball":"https://registry.npmjs.org/@bonhomie/useful-hooks/-/useful-hooks-1.0.0.tgz","fileCount":5,"integrity":"sha512-vbBq7XDhG49Jlf9n4fIIcr3LgySM0DQcvKt5oc27BE6Je0lYlhsW3J6bUBtRUlyr3uFgNcs4+u/ZQkc23DCRfg==","signatures":[{"sig":"MEUCIF/JqzzI5afiXj9WicH/9qcnkaZ/my3Cc/Mf3w4Rd1euAiEA9qlCKUSBY692iOrDKeMqghYklAjrybynq9p1h72FB4Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16820},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","gitHead":"5c8fe9589cc2711243454d80e4a147e85471f39e","scripts":{"dev":"tsup src/index.js --watch --dts","build":"tsup src/index.js --dts","clean":"rm -rf dist"},"_npmUser":{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"},"_npmVersion":"10.8.0","description":"A collection of clean, production-ready React hooks for everyday development.","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^7.2.0","typescript":"^5.6.0"},"peerDependencies":{"react":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/useful-hooks_1.0.0_1764094859162_0.37187773986837547","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@bonhomie/useful-hooks","version":"1.0.1","keywords":["react","hooks","react-hooks","usehooks","frontend","javascript","bonhomie"],"author":{"name":"Bonhomie"},"license":"MIT","_id":"@bonhomie/useful-hooks@1.0.1","maintainers":[{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"}],"dist":{"shasum":"deb8a27093d8014359e622a9c72bd33e3976bf1c","tarball":"https://registry.npmjs.org/@bonhomie/useful-hooks/-/useful-hooks-1.0.1.tgz","fileCount":7,"integrity":"sha512-olZoj595GnXOOTJPGedYXprWZ5Qcf4CgfumZ8O5tyEb7nhlHcJhETyDTD+FBXa3Wel/k0mriodpC50GcMsivbA==","signatures":[{"sig":"MEYCIQDCsb1Us4vgDz/QVzGPAeTSb+IZvurgCAh3tWCY3wtrQQIhALMwQg0+4mqznEgWKXFSregqpRM6mNkew+Y/Hlv4bZv7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":27131},"main":"dist/index.cjs","types":"dist/index.d.ts","module":"dist/index.js","gitHead":"5c8fe9589cc2711243454d80e4a147e85471f39e","scripts":{"dev":"tsup src/index.js --watch --dts","build":"tsup src/index.js --format esm,cjs --dts","clean":"rm -rf dist"},"_npmUser":{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"},"_npmVersion":"10.8.0","description":"A collection of clean, production-ready React hooks for everyday development.","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^7.2.0","typescript":"^5.6.0"},"peerDependencies":{"react":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/useful-hooks_1.0.1_1764314372564_0.6358352123201181","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@bonhomie/useful-hooks","version":"1.0.2","keywords":["react-hooks","usehook","react-use","custom-hooks","useful-hooks","hooks-library","react-utilities","react-tools","react-helper","react-utils","frontend-tools","browser-hooks","use-secure","use-screenshot","use-devtools","use-clipboard","use-route-guard"],"author":{"name":"Bonhomie"},"license":"MIT","_id":"@bonhomie/useful-hooks@1.0.2","maintainers":[{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"}],"dist":{"shasum":"53c644eb2883e68dce5497e7c98ac9b6f5dc927c","tarball":"https://registry.npmjs.org/@bonhomie/useful-hooks/-/useful-hooks-1.0.2.tgz","fileCount":7,"integrity":"sha512-rrZ9XFoUIAEQDHG2CYhL0kpyGKgWDOwE2RdvVANtQZkuMjdj7PzxVCAZjLSKydP+FhuCQsAn9CNr0AqzFol/Pg==","signatures":[{"sig":"MEUCICSh/7l1cQ7wb1VgGpIwZZHmXlTzMrKoTgJYSIVKYh6cAiEAhHow7Bko/xc1ZTMQLz5ONBUZoZXrc5qhH2kiuD8dL4M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":27374},"main":"dist/index.cjs","types":"dist/index.d.ts","module":"dist/index.js","gitHead":"c7b44607c7da102d8b6181f8af6168ce0edbd457","scripts":{"dev":"tsup src/index.js --watch --dts","build":"tsup src/index.js --format esm,cjs --dts","clean":"rm -rf dist"},"_npmUser":{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"},"_npmVersion":"10.8.0","description":"A collection of clean, production-ready React hooks for everyday development.","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^7.2.0","typescript":"^5.6.0"},"peerDependencies":{"react":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/useful-hooks_1.0.2_1764321042019_0.939231583316299","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@bonhomie/useful-hooks","version":"1.1.0","keywords":["react-hooks","usehook","react-use","custom-hooks","useful-hooks","hooks-library","react-utilities","react-tools","react-helper","react-utils","frontend-tools","browser-hooks","use-secure","use-screenshot","use-devtools","use-clipboard","use-route-guard"],"author":{"name":"Bonhomie"},"license":"MIT","_id":"@bonhomie/useful-hooks@1.1.0","maintainers":[{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"}],"dist":{"shasum":"7beb4f95d4b1bd92653963fe88ceca877cb26687","tarball":"https://registry.npmjs.org/@bonhomie/useful-hooks/-/useful-hooks-1.1.0.tgz","fileCount":7,"integrity":"sha512-yXGn5WGBjkulFf7W/Cb+mVZUeC+oJ8HF5Qmlhmuy0oBWRbQhg2b0CUx165jXxU3rmhIfqT2oAass01ibBXSVfA==","signatures":[{"sig":"MEUCIAqDHReD/HCPm+CqUMGzYhqh1OPwAPst4dAw9mYxMU4bAiEA5aKr8MiUUGEIuqxLbOklYYHtqzEA3ORiwNcuVIyDV3Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":29166},"main":"dist/index.cjs","types":"dist/index.d.ts","module":"dist/index.js","gitHead":"3b424d0dfa39e0d0431e447ac8d65cb85494056f","scripts":{"dev":"tsup src/index.js --watch --dts","build":"tsup src/index.js --format esm,cjs --dts","clean":"rm -rf dist"},"_npmUser":{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"},"_npmVersion":"10.8.0","description":"A collection of clean, production-ready React hooks for everyday development.","directories":{},"_nodeVersion":"22.22.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^7.2.0","typescript":"^5.6.0"},"peerDependencies":{"react":">=17.0.0"},"_npmOperationalInternal":{"tmp":"tmp/useful-hooks_1.1.0_1773822874119_0.535326276962192","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@bonhomie/useful-hooks","version":"2.1.0","description":"A collection of clean, production-ready React hooks for everyday development.","main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","keywords":["react-hooks","usehook","react-use","custom-hooks","useful-hooks","hooks-library","react-utilities","react-tools","react-helper","react-utils","frontend-tools","browser-hooks","use-secure","use-clipboard","use-route-guard","bonhomie"],"author":{"name":"Bonhomie"},"license":"MIT","scripts":{"dev":"tsup src/index.js --watch --dts","build":"tsup src/index.js --format esm,cjs --dts","clean":"rm -rf dist"},"peerDependencies":{"react":">=17.0.0"},"devDependencies":{"tsup":"^7.2.0","typescript":"^5.6.0"},"_id":"@bonhomie/useful-hooks@2.1.0","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-MD1WIXMt2XfADy8Q6WCJzI0W3K7UGJb6Rtr9X93FJWlcHKpqkUft/h7QvxaMWH+ta1phxIF6KaXS0A8iANhazw==","shasum":"22f21387631c6d9b225872b3d9f6eece6b63afbd","tarball":"https://registry.npmjs.org/@bonhomie/useful-hooks/-/useful-hooks-2.1.0.tgz","fileCount":7,"unpackedSize":30969,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDnhbiVSahhyF/rDJQAc8gi4eSY9bfByFKYZtazrEQP/AiBtpEzyydiwYr4ZDbywVMxd7q2ctf4sOBeEMZGX5RLi7g=="}]},"_npmUser":{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"},"directories":{},"maintainers":[{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/useful-hooks_2.1.0_1777495473751_0.6397036778690086"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-25T18:20:59.017Z","modified":"2026-04-29T20:44:34.024Z","1.0.0":"2025-11-25T18:20:59.363Z","1.0.1":"2025-11-28T07:19:32.760Z","1.0.2":"2025-11-28T09:10:42.219Z","1.1.0":"2026-03-18T08:34:34.282Z","2.1.0":"2026-04-29T20:44:33.885Z"},"author":{"name":"Bonhomie"},"license":"MIT","keywords":["react-hooks","usehook","react-use","custom-hooks","useful-hooks","hooks-library","react-utilities","react-tools","react-helper","react-utils","frontend-tools","browser-hooks","use-secure","use-clipboard","use-route-guard","bonhomie"],"description":"A collection of clean, production-ready React hooks for everyday development.","maintainers":[{"name":"bonhomie95","email":"adeyemibabatundejoseph@gmail.com"}],"readme":"# @bonhomie/useful-hooks\n\nA clean, production-ready collection of **React hooks** for everyday development.\nMinimal, fast, dependency-free, and fully SSR-safe.\n\n![npm](https://img.shields.io/npm/v/@bonhomie/useful-hooks)\n![downloads](https://img.shields.io/npm/dm/@bonhomie/useful-hooks)\n![license](https://img.shields.io/npm/l/@bonhomie/useful-hooks)\n![react](https://img.shields.io/badge/react-17%2B-blue?logo=react)\n\n---\n\n## 📦 Installation\n\n```bash\nnpm install @bonhomie/useful-hooks\n# or\nyarn add @bonhomie/useful-hooks\n```\n\n---\n\n## 🪝 Hooks\n\n### `useLocalStorage`\n\nPersist state in `localStorage` with cross-tab sync. Fully SSR-safe.\n\n```jsx\nimport { useLocalStorage } from \"@bonhomie/useful-hooks\";\n\nfunction App() {\n  const [name, setName] = useLocalStorage(\"name\", \"Bonhomie\");\n\n  return (\n    <input value={name} onChange={e => setName(e.target.value)} />\n  );\n}\n```\n\n---\n\n### `useDarkMode`\n\nToggle and persist dark mode with system preference sync.\n\n```jsx\nimport { useDarkMode } from \"@bonhomie/useful-hooks\";\n\nfunction ThemeToggle() {\n  const { dark, setDark } = useDarkMode();\n\n  return (\n    <button onClick={() => setDark(!dark)}>\n      {dark ? \"Switch to Light\" : \"Switch to Dark\"}\n    </button>\n  );\n}\n```\n\nAdds/removes a `dark` class on `document.documentElement` — compatible with Tailwind CSS dark mode.\n\n---\n\n### `useDebounce`\n\nDelay a value update until the user stops typing.\n\n```jsx\nimport { useDebounce } from \"@bonhomie/useful-hooks\";\n\nfunction SearchBox() {\n  const [query, setQuery] = useState(\"\");\n  const debounced = useDebounce(query, 400);\n\n  useEffect(() => {\n    if (!debounced) return;\n    // Call API here\n  }, [debounced]);\n\n  return (\n    <input\n      value={query}\n      onChange={(e) => setQuery(e.target.value)}\n      placeholder=\"Search...\"\n    />\n  );\n}\n```\n\n---\n\n### `useThrottle`\n\nLimit how often a value updates during rapid changes (e.g. scroll, resize).\n\n```jsx\nimport { useThrottle } from \"@bonhomie/useful-hooks\";\n\nfunction ScrollTracker() {\n  const [pos, setPos] = useState(0);\n  const throttledPos = useThrottle(pos, 200);\n\n  useEffect(() => {\n    const handler = () => setPos(window.scrollY);\n    window.addEventListener(\"scroll\", handler);\n    return () => window.removeEventListener(\"scroll\", handler);\n  }, []);\n\n  return <div>Scroll Y: {throttledPos}</div>;\n}\n```\n\n---\n\n### `useToggle`\n\nBoolean toggle with explicit setters.\n\n```jsx\nimport { useToggle } from \"@bonhomie/useful-hooks\";\n\nfunction Example() {\n  const { value, toggle, setTrue, setFalse } = useToggle();\n\n  return (\n    <div>\n      <p>{value ? \"ON\" : \"OFF\"}</p>\n      <button onClick={toggle}>Toggle</button>\n      <button onClick={setTrue}>Set ON</button>\n      <button onClick={setFalse}>Set OFF</button>\n    </div>\n  );\n}\n```\n\n---\n\n### `useClickOutside`\n\nFire a callback when the user clicks outside a ref'd element.\n\n```jsx\nimport { useRef } from \"react\";\nimport { useClickOutside, useToggle } from \"@bonhomie/useful-hooks\";\n\nfunction Dropdown() {\n  const ref = useRef(null);\n  const { value, toggle, setFalse } = useToggle();\n\n  useClickOutside(ref, () => setFalse());\n\n  return (\n    <div>\n      <button onClick={toggle}>Menu</button>\n      {value && (\n        <div ref={ref} className=\"dropdown\">\n          <p>Item 1</p>\n          <p>Item 2</p>\n        </div>\n      )}\n    </div>\n  );\n}\n```\n\n---\n\n### `useWindowSize`\n\nReactive window width and height.\n\n```jsx\nimport { useWindowSize } from \"@bonhomie/useful-hooks\";\n\nfunction Component() {\n  const { width, height } = useWindowSize();\n  return <p>Screen: {width} × {height}</p>;\n}\n```\n\n---\n\n### `useCopyToClipboard`\n\nCopy text to clipboard with a timed \"Copied!\" feedback state.\n\n> Requires HTTPS or `localhost` — `navigator.clipboard` is unavailable on plain HTTP.\n\n```jsx\nimport { useCopyToClipboard } from \"@bonhomie/useful-hooks\";\n\nfunction Referral() {\n  const { copied, copy } = useCopyToClipboard();\n\n  return (\n    <button onClick={() => copy(\"BONHOMIE-123\")}>\n      {copied ? \"Copied!\" : \"Copy Code\"}\n    </button>\n  );\n}\n```\n\n---\n\n### `useAsync`\n\nRun any async function with loading / error / value state.\n\n```jsx\nimport { useAsync } from \"@bonhomie/useful-hooks\";\n\nfunction ProfileLoader() {\n  const fetchUser = () => fetch(\"/api/user\").then(res => res.json());\n  const { execute, loading, error, value } = useAsync(fetchUser, []);\n\n  useEffect(() => { execute(); }, [execute]);\n\n  if (loading) return <p>Loading...</p>;\n  if (error) return <p>Error loading profile</p>;\n  return <pre>{JSON.stringify(value, null, 2)}</pre>;\n}\n```\n\n---\n\n### `useFetch`\n\nDeclarative data fetching with abort on unmount and a `refetch` function.\n\n```jsx\nimport { useFetch } from \"@bonhomie/useful-hooks\";\n\nfunction Users() {\n  const { data, loading, error, refetch } = useFetch(\"/api/users\");\n\n  if (loading) return <p>Loading...</p>;\n  if (error) return <p>Error fetching users</p>;\n\n  return (\n    <div>\n      <button onClick={refetch}>Refresh</button>\n      <pre>{JSON.stringify(data, null, 2)}</pre>\n    </div>\n  );\n}\n```\n\nPOST example:\n\n```jsx\nuseFetch(\"/api/auth/login\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ email, password }),\n});\n```\n\n> If your `options` object is created inline (new object on every render), memoize it with `useMemo` — otherwise a refetch fires on every render.\n\n---\n\n## 📄 License\n\nMIT — Free for personal and commercial use.\n\n## 👨‍💻 Author\n\n**Bonhomie** · Full-stack Web & Mobile Developer · Creator of @bonhomie toolkits.\n","readmeFilename":"README.md"}