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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hexhad/react-utils

v0.2.0

Published

@hexhad/react-utils

Readme

@hexhad/react-utils

Performance-focused React and React Native utilities, written in TypeScript.


Installation

npm install @hexhad/react-utils
# or
yarn add @hexhad/react-utils

React ≥ 17 is required as a peer dependency.


What's inside

src/
└── utils/
    ├── ProviderTreeCreator.ts
    └── GlobalModalManager.ts

ProviderTreeCreator

Composes multiple context providers into a single wrapper component, eliminating deeply nested "provider hell".

The problem

// Hard to read, hard to reorder, easy to get wrong
export default function App() {
  return (
    <ThemeProvider theme={darkTheme}>
      <AuthProvider>
        <QueryClientProvider client={queryClient}>
          <NavigationContainer>
            <RootNavigator />
          </NavigationContainer>
        </QueryClientProvider>
      </AuthProvider>
    </ThemeProvider>
  );
}

The solution

import { ProviderTreeCreator } from '@hexhad/react-utils';
import type { ProviderEntry } from '@hexhad/react-utils';

// Declare outside the component so WeakMap caching kicks in
const providers: ProviderEntry[] = [
  [ThemeProvider, { theme: darkTheme }],
  [AuthProvider],
  [QueryClientProvider, { client: queryClient }],
  [NavigationContainer],
];

const AppProviders = ProviderTreeCreator(providers);

export default function App() {
  return (
    <AppProviders>
      <RootNavigator />
    </AppProviders>
  );
}

Providers are applied outermost-first — left to right in the array maps to top to bottom in the tree.

Performance

  • The innermost FragmentWrapper is defined at module level and never recreated.
  • Each intermediate wrapper is a named function so React DevTools shows ProviderTreeCreator(ThemeProvider) instead of anonymous arrows.
  • When you declare the providers array outside your component, ProviderTreeCreator returns the cached result on repeat calls via a WeakMap — zero re-computation.

API

ProviderTreeCreator(providers: ProviderEntry[]): ComposedProvider
// A single entry — component plus optional props
type ProviderEntry<P> =
  | [ComponentType<PropsWithChildren<P>>, P]
  | [ComponentType<PropsWithChildren<P>>];

// The resulting wrapper component
type ComposedProvider = ComponentType<PropsWithChildren<object>>;

GlobalModalManager

A zero-dependency, typed modal manager for React Native (and React DOM). It manages state, refs, props, and listeners for every modal in your app from a single place, without any React context or re-renders.

Behaviour

  • Calling show closes all other open modals first by default (closeOthers: true).
  • If the target modal is already open, show updates its props and notifies listeners without calling present() again.
  • hide calls dismiss() on the modal ref, clears its props, and notifies listeners.
  • toggle calls hide if the modal is open, otherwise show.
  • updateState is for syncing external dismissal (e.g. a swipe-down gesture) back into the manager without calling dismiss() again.
  • Every listener removal returns an unsubscribe function — no need to call removeAllListeners manually.
  • After destroy() is called, every method becomes a no-op.

Setup

// src/modals.ts
import { createModalManager } from '@hexhad/react-utils';

export const MODAL_NAMES = {
  PORTAL_GUN: 'PortalGun',
  MEESEEKS_BOX: 'MeeseeksBox',
  PLUMBUS: 'Plumbus',
} as const;

export type ModalName = (typeof MODAL_NAMES)[keyof typeof MODAL_NAMES];

// Optional — gives you fully typed props per modal at zero runtime cost
declare module '@hexhad/react-utils' {
  interface ModalPropsRegistry {
    PortalGun: { destination: string; onConfirm: () => void };
    MeeseeksBox: { task: string; onComplete: () => void };
    Plumbus: { quantity: number };
  }
}

export const GlobalModalManager = createModalManager<ModalName>(MODAL_NAMES);

Attaching refs

Render all your modals in one place and attach the manager's refs:

// src/ModalCenter.tsx
import { GlobalModalManager, MODAL_NAMES } from './modals';

export function ModalCenter() {
  return (
    <>
      <PortalGunModal ref={GlobalModalManager.getRef(MODAL_NAMES.PORTAL_GUN)} />
      <MeeseeksBoxModal
        ref={GlobalModalManager.getRef(MODAL_NAMES.MEESEEKS_BOX)}
      />
      <PlumbusModal ref={GlobalModalManager.getRef(MODAL_NAMES.PLUMBUS)} />
    </>
  );
}

Opening and closing

// Auto-generated convenience methods (one per modal name)
GlobalModalManager.openPortalGun({
  destination: 'Dimension C-137',
  onConfirm: () => {},
});
GlobalModalManager.closePortalGun();
GlobalModalManager.togglePortalGun();

// Generic methods
GlobalModalManager.show(MODAL_NAMES.PORTAL_GUN, {
  destination: 'Dimension C-137',
  onConfirm: () => {},
});
GlobalModalManager.hide(MODAL_NAMES.PORTAL_GUN);
GlobalModalManager.toggle(MODAL_NAMES.PORTAL_GUN);

// Open alongside other modals instead of replacing them
GlobalModalManager.show(MODAL_NAMES.PLUMBUS, {
  closeOthers: false,
  quantity: 3,
});

// Close everything
GlobalModalManager.closeAll();

Reading state

GlobalModalManager.isOpen(MODAL_NAMES.PORTAL_GUN); // boolean
GlobalModalManager.isAnyOpen(); // boolean
GlobalModalManager.getOpenModal(); // first open name or null
GlobalModalManager.getOpenModals(); // all open modal names
GlobalModalManager.getState(); // frozen { isPortalGunOpen: false, ... }

Props

// Get all props for a modal (typed if ModalPropsRegistry is augmented)
const props = GlobalModalManager.getProps(MODAL_NAMES.PORTAL_GUN);
// props.destination → string

// Get one prop with an optional default
const dest = GlobalModalManager.getProp(
  MODAL_NAMES.PORTAL_GUN,
  'destination',
  'Citadel'
);

// Replace all props
GlobalModalManager.setProps(MODAL_NAMES.PORTAL_GUN, {
  destination: 'Blips and Chitz',
  onConfirm: () => {},
});

// Merge into existing props
GlobalModalManager.updateProps(MODAL_NAMES.PORTAL_GUN, {
  destination: 'Cronenberg World',
});

// Set one prop
GlobalModalManager.setProp(
  MODAL_NAMES.PORTAL_GUN,
  'destination',
  'Bird Person Home'
);

// Clear props for one modal
GlobalModalManager.clearProps(MODAL_NAMES.PORTAL_GUN);

// Clear all
GlobalModalManager.clearAllProps();

Reading props inside a modal component

// src/modals/PortalGunModal.tsx
import { forwardRef, useEffect, useState } from 'react';
import { BottomSheetModal } from '@gorhom/bottom-sheet';
import { GlobalModalManager, MODAL_NAMES } from '../modals';

export const PortalGunModal = forwardRef((_, ref) => {
  const [props, setProps] = useState(
    GlobalModalManager.getProps(MODAL_NAMES.PORTAL_GUN)
  );

  useEffect(() => {
    return GlobalModalManager.addListener(
      MODAL_NAMES.PORTAL_GUN,
      (isOpen, latest) => {
        if (isOpen) setProps(latest);
      }
    );
  }, []);

  return (
    <BottomSheetModal ref={ref}>
      <Text>{props.destination}</Text>
      <Button title="Go" onPress={props.onConfirm} />
    </BottomSheetModal>
  );
});

Listeners

// Per-modal listener
const unsub = GlobalModalManager.addListener(
  MODAL_NAMES.PORTAL_GUN,
  (isOpen, props) => {
    console.log(isOpen, props.destination);
  }
);
unsub(); // unsubscribe

// Global listener — fires for every modal event
const unsub = GlobalModalManager.addGlobalListener(
  ({ type, modalName, isOpen }) => {
    analytics.track('modal', { type, modalName, isOpen });
  }
);
unsub();

// Remove all listeners for one modal
GlobalModalManager.removeAllListeners(MODAL_NAMES.PORTAL_GUN);

// Remove everything
GlobalModalManager.removeAllListeners();

Syncing external dismissal

When a bottom sheet is swiped closed by the user, the manager doesn't know. Call updateState from the sheet's onDismiss to keep state in sync without triggering a redundant dismiss() call:

<BottomSheetModal
  ref={ref}
  onDismiss={() =>
    GlobalModalManager.updateState(MODAL_NAMES.PORTAL_GUN, false)
  }
/>

Dynamic registration

// Register a modal that is not in MODAL_NAMES
GlobalModalManager.registerModal('Snuffles');
GlobalModalManager.openSnuffles({ wantsTalk: true }); // convenience method auto-attached

// Remove it
GlobalModalManager.unregisterModal('Snuffles');

Cleanup

// Useful for test teardown or module hot reload
GlobalModalManager.destroy();
// All modals closed, all listeners cleared, all state wiped.
// Every method is a silent no-op after this point.

Debugging

No-op in production (NODE_ENV === 'production').

GlobalModalManager._debugConfigs();
// [GlobalModalManager] configs: { PortalGun: { stateKey: '...', listenerKey: '...' }, ... }
// [GlobalModalManager] state: { isPortalGunOpen: false, ... }
// [GlobalModalManager] openModals: []
// [GlobalModalManager] listenerCounts: { onPortalGunStateChange: 0, ... }
// [GlobalModalManager] globalListeners: 0

Extending the library

The library is structured so new utilities drop in without touching existing code.

src/
└── utils/
    ├── ProviderTreeCreator.ts   ← existing
    ├── GlobalModalManager.ts   ← existing
    ├── useToggle.ts             ← add new file here
    └── index.ts                 ← export it from here

Step 1 — create src/utils/yourUtil.ts and write your utility following the same patterns: strict TypeScript, no runtime deps, React Native compatible (no DOM APIs).

Step 2 — add its exports to src/utils/index.ts:

export { useToggle } from './useToggle';
export type { UseToggleReturn } from './useToggle';

That's it. The root src/index.ts re-exports everything from ./utils, so consumers get it automatically from @hexhad/react-utils.

Conventions to follow

  • One file per utility.
  • Export all public types — consumers should never need to reconstruct types manually.
  • Use for...of over .forEach in imperative loops.
  • Use early returns over nested if blocks.
  • Use Set or Map over plain objects for collections that are mutated at runtime.
  • Gate any console.log calls with process.env['NODE_ENV'] !== 'production'.
  • No runtime dependencies — React is a peer dep only.

Project structure

@hexhad/react-utils/
├── src/
│   ├── index.ts               re-exports everything from ./utils
│   └── utils/
│       ├── index.ts           barrel for all utilities
│       ├── ProviderTreeCreator.ts
│       └── GlobalModalManager.ts
├── dist/                      compiled JS + .d.ts + source maps
├── tsconfig.json
└── package.json

Build

npm run build        # compile to dist/
npm run type-check   # tsc --noEmit
npm run clean        # remove dist/