npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

hook-kits

v1.2.3

Published

A lightweight, reusable React hooks library for modern apps using Next.js and React 18+.

Readme

🪝 Hook Kits

Hook Kits is a lightweight, modern React hooks library that helps you build UI and manage logic faster and cleaner.
Each hook solves a common problem in everyday React development — from toggles and hover detection to storage and resize tracking.

🚀 Build smarter UIs. Reuse smarter logic.


📦 Installation

Install Hook Kits with your preferred package manager:

npm install hook-kits
yarn add hook-kits
pnpm add hook-kits

📦 Usage

Detects the browser's wheel event and returns whether the user is currently scrolling with the mouse wheel.

import { useWheel } from 'hook-kits';

export default function WheelControlExample() {
  const { isWheel, handleWheelTrue, handleWheelFalse } = useWheel();

  return (
    <div>
      <p>Wheel Detected: {isWheel ? 'YES' : 'NO'}</p>
      <button onClick={handleWheelTrue}>Set True</button>
      <button onClick={handleWheelFalse}>Set False</button>
    </div>
  );
}

Simple boolean toggle hook.
Provides methods to flip, set, and control a boolean state easily.

import { useToggle } from 'hook-kits';

export default function ToggleExample() {
  const {
    isToggle,
    handleToggle,
    handleSetTrue,
    handleSetFalse,
    handleSetBoolean,
  } = useToggle();

  return (
    <div>
      <p>Toggle State: {isToggle ? 'TRUE' : 'FALSE'}</p>

      <button onClick={handleToggle}>Toggle</button>
      <button onClick={handleSetTrue}>Set True</button>
      <button onClick={handleSetFalse}>Set False</button>
      <button onClick={() => handleSetBoolean(false)}>Set Boolean</button>
    </div>
  );
}

A typed sessionStorage hook that reads, writes, and removes values with automatic JSON parsing.
Works safely with SSR environments.

import { useSessionStorage } from 'hook-kits';

export default function SessionStorageExample() {
  const { value, setItem, removeItem } = useSessionStorage('user', {
    name: 'Guest',
  });

  return (
    <div>
      <p>Name: {value.name}</p>

      <button onClick={() => setItem({ name: 'Alice' })}>
        Set Name to Alice
      </button>

      <button onClick={removeItem}>Reset</button>
    </div>
  );
}

A hook that observes the size of a DOM element and returns its current DOMRect.
Useful for responsive components, dynamic layouts, and size-based UI calculations.

import { useResize } from 'hook-kits';

export default function ResizeExample() {
  const { ref, rect } = useResize<HTMLDivElement>();

  return (
    <div>
      <div
        ref={ref}
        style={{
          width: '50%',
          resize: 'both',
          overflow: 'auto',
          border: '1px solid #aaa',
          padding: '1rem',
        }}
      >
        Resize me!
      </div>

      <p>
        Width: {rect?.width ?? 0}px — Height: {rect?.height ?? 0}px
      </p>
    </div>
  );
}

A state hook that updates inside a requestAnimationFrame loop.
Useful for high-frequency UI updates such as scroll, resize, or animation-driven state changes.

import { useRafState } from 'hook-kits';

export default function RafStateExample() {
  const { state, setRafState } = useRafState(0);

  return (
    <div>
      <p>Value: {state}</p>

      <button onClick={() => setRafState(state + 1)}>Increment (RAF)</button>
    </div>
  );
}

Returns the previous value of a state or prop.
Useful for comparison, animations, and detecting value changes.

import { usePrevious } from 'hook-kits';
import { useState } from 'react';

export default function PreviousExample() {
  const [count, setCount] = useState(0);
  const prev = usePrevious(count);

  return (
    <div>
      <p>Current: {count}</p>
      <p>Previous: {prev ?? 'N/A'}</p>

      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  );
}

A hook built on top of the IntersectionObserver API.
It detects when an element enters the viewport and optionally triggers a callback.

import { useObserver } from 'hook-kits';

export default function ObserverExample() {
  const { ref, isIntersecting } = useObserver({
    root: null,
    rootMargin: '0px',
    threshold: 0.5,
    onIntersect: () => {
      console.log('Element is visible!');
    },
  });

  return (
    <div style={{ height: '200vh', padding: '200px 0' }}>
      <div
        ref={ref}
        style={{
          height: '150px',
          background: isIntersecting ? '#4caf50' : '#ddd',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        {isIntersecting ? 'Visible' : 'Scroll Down'}
      </div>
    </div>
  );
}

Returns true after the component is mounted.
Useful for delaying logic until the first client render.

import { useMount } from 'hook-kits';

export default function MountExample() {
  const isMount = useMount();

  return (
    <div>
      <p>Mounted: {isMount ? 'YES' : 'NO'}</p>
    </div>
  );
}

A typed localStorage hook that reads, writes, and removes values with automatic JSON parsing.
Safely handles SSR environments.

import { useLocalStorage } from 'hook-kits';

export default function LocalStorageExample() {
  const { value, setItem, removeItem } = useLocalStorage('theme', 'light');

  return (
    <div>
      <p>Theme: {value}</p>

      <button onClick={() => setItem('dark')}>Set Dark</button>
      <button onClick={() => setItem('light')}>Set Light</button>
      <button onClick={removeItem}>Reset</button>
    </div>
  );
}

A lazy-loading hook for images using IntersectionObserver.
It waits until the image enters the viewport, then triggers a load event and updates the loaded state.

import { useLazyImageLoad } from 'hook-kits';

export default function LazyImageExample() {
  const { ref, loaded } = useLazyImageLoad({
    isLazy: true,
    root: null,
    threshold: 0.1,
    rootMargin: '0px',
  });

  return (
    <div>
      {!loaded && <p>Loading image...</p>}

      <img
        ref={ref}
        data-src='https://picsum.photos/500'
        src={loaded ? 'https://picsum.photos/500' : undefined}
        alt='Lazy Example'
        style={{
          width: 300,
          height: 200,
          background: '#eee',
          objectFit: 'cover',
        }}
      />
    </div>
  );
}

Returns true only on the client-side after the component has mounted.
Useful for avoiding SSR mismatches or running client-only logic.

import { useIsClient } from 'hook-kits';

export default function IsClientExample() {
  const isClient = useIsClient();

  return (
    <div>
      <p>Client Render: {isClient ? 'YES' : 'NO'}</p>
    </div>
  );
}

A flexible input handler hook for both single-value inputs and object-based form fields.
Supports simple input changes, named-field updates, and value reset.

import { useInput } from 'hook-kits';

export default function InputExample() {
  // Single value input
  const {
    value: text,
    handleInputChange,
    resetValue: resetText,
  } = useInput('');

  // Object value input (e.g., form fields)
  const {
    value: form,
    handleFieldChange,
    resetValue: resetForm,
  } = useInput({ email: '', username: '' });

  return (
    <div>
      <h3>Single Input</h3>
      <input
        value={text}
        onChange={handleInputChange}
      />
      <button onClick={resetText}>Reset</button>

      <h3>Form Fields</h3>
      <input
        name='email'
        value={form.email}
        onChange={handleFieldChange}
      />
      <input
        name='username'
        value={form.username}
        onChange={handleFieldChange}
      />
      <button onClick={resetForm}>Reset Form</button>
    </div>
  );
}

A hook that detects whether an element is being hovered.
Returns a ref to attach to the target element and a boolean isHover.

import { useHover } from 'hook-kits';

export default function HoverExample() {
  const { ref, isHover } = useHover<HTMLDivElement>();

  return (
    <div>
      <div
        ref={ref}
        style={{
          width: 200,
          height: 100,
          background: isHover ? '#4caf50' : '#ccc',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          transition: '0.2s ease',
        }}
      >
        {isHover ? 'Hovering!' : 'Hover me'}
      </div>
    </div>
  );
}

A hook for handling Server-Sent Events (SSE).
It manages connection lifecycle, listens for streamed chunks, handles errors, and allows manual cancellation.

import { useEventSource } from 'hook-kits';

export default function EventSourceExample() {
  const { state, isError, cancelEventSource, eventSource } = useEventSource({
    url: '/api/stream',
    event: 'message',
    initialState: [],
    onOpen: () => console.log('SSE Connected'),
    onResponse: (chunk) => console.log('Chunk:', chunk),
    onError: (err) => console.error('Error:', err),
    onCancel: () => console.log('SSE Cancelled'),
  });

  return (
    <div>
      <button onClick={cancelEventSource}>Cancel Stream</button>

      <p>SSE Error: {isError ? 'YES' : 'NO'}</p>

      <ul>
        {state.map((item, i) => (
          <li key={i}>{JSON.stringify(item)}</li>
        ))}
      </ul>
    </div>
  );
}

A stable callback hook that always references the latest function without causing re-renders.
Useful when passing callbacks into useEffect, observers, or event listeners without adding them to dependency arrays.

import { useEventCallback } from 'hook-kits';
import { useEffect, useState } from 'react';

export default function EventCallbackExample() {
  const [count, setCount] = useState(0);

  // Always up-to-date, but stable reference
  const handleLog = useEventCallback(() => {
    console.log('Current count:', count);
  });

  useEffect(() => {
    const id = setInterval(() => {
      // This callback will always log the latest count,
      // without adding `count` to the dependency array.
      handleLog();
    }, 1000);

    return () => clearInterval(id);
  }, [handleLog]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  );
}

A counter hook with optional limits and change callbacks.
Supports increment, decrement, direct updates, and prevents invalid values.

import { useCount } from 'hook-kits';

export default function CountExample() {
  const { count, increase, decrease, handleChangeCount } = useCount({
    initialState: 1,
    limit: 5,
    onChange: (v) => console.log('Changed:', v),
  });

  return (
    <div>
      <p>Count: {count}</p>

      <button onClick={decrease}>-</button>
      <button onClick={increase}>+</button>

      <button onClick={() => handleChangeCount(3)}>Set to 3</button>
      <button onClick={() => handleChangeCount(10)}>Set to 10 (blocked)</button>
    </div>
  );
}

A hook for copying text to the clipboard using the modern Clipboard API.
Returns the last copied text and a copy function.

import { useCopyClipBoard } from 'hook-kits';

export default function CopyExample() {
  const { copiedText, copy } = useCopyClipBoard();

  return (
    <div>
      <button onClick={() => copy('Hello World!')}>Copy Text</button>

      <p>Copied: {copiedText ?? 'Nothing yet'}</p>
    </div>
  );
}

A hook that triggers a callback when a user clicks outside the referenced element.
Useful for modals, dropdowns, tooltips, and any UI that should close on outside click.

export default function ClickAwayExample() {
  const [open, setOpen] = useState(false);
  const ref = useClickAway<HTMLDivElement>(() => setOpen(false));

  return (
    <div>
      <button onClick={() => setOpen(true)}>Open Box</button>

      {open && (
        <div
          ref={(el) => {
            if (el) ref.current = el;
          }}
          style={{
            width: 200,
            height: 120,
            background: '#4caf50',
            color: '#fff',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            marginTop: 20,
          }}
        >
          Click outside to close
        </div>
      )}
    </div>
  );
}

📄 License

MIT License © 2025 @dhgg321