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

@pawells/react-shared

v3.0.0

Published

Shared React utilities library for hooks, components, context, and HOCs

Readme

React Shared Utility Library

CI npm version Node License: MIT

Description

@pawells/react-shared is a shared React component and hook library providing MUI-based UI components, a global notification context, an inactivity warning system, and an animated Voronoi background. It is intended for use across @pawells React applications that share a MUI + Emotion stack.

Requirements

  • Node.js >=22
  • react >=19.0.0 (required peer)
  • react-dom >=19.0.0 (required peer)
  • @mui/material >=9.0.0 <10.0.0 (required peer)
  • @emotion/react >=11.0.0 (required peer)
  • @emotion/styled >=11.0.0 (required peer)
  • @mui/icons-material >=9.0.0 <10.0.0 (required peer — used whenever StatCard is imported)

Installation

Install the package along with all required peer dependencies:

npm install @pawells/react-shared react react-dom @mui/material @emotion/react @emotion/styled

If you use StatCard, also install the optional peer:

npm install @mui/icons-material

Quick Start

Wrap your application (or the relevant subtree) in NotificationProvider, then call useNotification in any descendant component to display notifications.

import { NotificationProvider } from '@pawells/react-shared';

function Root() {
  return (
    <NotificationProvider>
      <App />
    </NotificationProvider>
  );
}
import { useNotification } from '@pawells/react-shared';

function SaveButton() {
  const { showNotification } = useNotification();

  const handleSave = async () => {
    await saveData();
    showNotification('Changes saved', 'success');
  };

  return <button onClick={handleSave}>Save</button>;
}

API Reference

Components

InactivityWarningDialog

A controlled MUI dialog that warns the user about an upcoming session timeout. Displays a live countdown and provides "Stay Logged In" and "Logout Now" actions. The parent component manages open state and all callbacks.

Props — InactivityWarningDialogProps

| Prop | Type | Required | Description | |---|---|---|---| | open | boolean | Yes | Whether the dialog is open | | countdownSeconds | number | Yes | Remaining seconds before session timeout | | onStayLoggedIn | () => void | Yes | Called when the user clicks "Stay Logged In" | | onLogout | () => void \| Promise<void> | Yes | Called when the user clicks "Logout Now" |


LoadingState

A centered loading spinner with an optional status message. Useful as a React Suspense fallback or during async data fetching. Accepts a forwarded ref to the outer div.

Props — LoadingStateProps

| Prop | Type | Default | Description | |---|---|---|---| | size | 'small' \| 'medium' \| 'large' | 'medium' | Spinner size variant | | message | string | — | Message displayed below the spinner |


PageHeader

A responsive page header rendering a title at h1 level, an optional subtitle, and optional action elements aligned to the right. Stacks vertically on mobile and displays as a row on desktop.

Props — PageHeaderProps

| Prop | Type | Required | Description | |---|---|---|---| | title | string | Yes | Main heading text | | subtitle | string | No | Secondary text displayed below the title | | actions | React.ReactNode | No | Action elements (e.g. buttons) rendered on the right |


StatCard

A MUI Card displaying a named metric with an icon and an optional trending indicator chip. Includes a hover lift effect. Requires @mui/icons-material as a peer dependency since the component imports trending icons unconditionally.

Props — StatCardProps

| Prop | Type | Default | Description | |---|---|---|---| | title | string | — | Card heading | | value | string \| number | — | Metric value displayed prominently | | icon | React.ReactNode | — | Icon element rendered in the card body | | color | 'primary' \| 'success' \| 'warning' \| 'error' | 'primary' | Color theme applied to the value and icon | | change | number | — | Percentage change; renders a trending chip with an up or down indicator |


VoronoiBackground

A full-viewport animated Voronoi triangle mesh rendered as a position: fixed SVG background. Uses a seeded Mulberry32 PRNG for deterministic point generation and D3-Delaunay for triangulation. Regenerates on window resize with a 150 ms debounce.

This component accesses window directly and is not compatible with server-side rendering. The seed prop is read only on initial mount; changes after mount are ignored. Memoize primaryColor and secondaryColor objects at the call site to avoid triggering full regeneration on every parent render.

Note: Throws a BaseError with code INVALID_COLOR if primaryColor or secondaryColor is an invalid hex color string (e.g., '#xyz', '#12345'). RGB objects are always valid.

Props — VoronoiBackgroundProps

| Prop | Type | Default | Description | |---|---|---|---| | primaryColor | { r: number; g: number; b: number } \| string | — | Primary/start color (RGB object or hex string) | | secondaryColor | { r: number; g: number; b: number } \| string | derived | Secondary/end color; if omitted, derived from primaryColor via HSV | | seed | number | Math.floor(Date.now() / 1000) | Seed for deterministic PRNG (read only on initial mount) | | zIndex | number | -1 | CSS z-index for layering | | opacity | number | 1 | Opacity of the entire background | | overlay | string | — | CSS color string for a translucent overlay, e.g. 'rgba(0,0,0,0.3)' | | blur | number | 0 | Blur amount in pixels applied to the triangles | | className | string | — | CSS class applied to the container div | | style | React.CSSProperties | — | Inline styles for the container div | | pointerEventsNone | boolean | true | When true, disables pointer events so clicks pass through | | pointCount | number | 98 | Number of internal seed points used for triangulation | | edgePointCount | number | 20 | Points placed along each viewport edge for full coverage | | minAreaDivisor | number | 750 | Divisor applied to viewport area to compute the minimum triangle area threshold | | maxPruningIterations | number | 10 | Maximum small-triangle pruning iterations |


Hooks

useInactivityWarning(config)

Tracks user activity events (mousedown, keydown, scroll, touchstart, click, visibilitychange) and drives a warning countdown before the session expires. Automatically calls onTimeout when the countdown reaches zero.

Note: If warningSeconds >= timeoutSeconds, the hook throws an Error at call time validating the configuration.

Parameters — InactivityWarningConfig

| Property | Type | Default | Description | |---|---|---|---| | onTimeout | () => void \| Promise<void> | — | Callback invoked when the session expires | | timeoutMinutes | number | 60 | Total inactivity timeout in minutes | | warningSeconds | number | 300 | Seconds before timeout at which to show the warning |

Returns — UseInactivityWarningReturn

| Property | Type | Description | |---|---|---| | isWarningActive | boolean | Whether the warning dialog should be shown | | countdownSeconds | number | Remaining seconds when the warning is active | | extendSession | () => void | Resets the inactivity timer and hides the warning | | dismissWarning | () => void | Hides the warning without resetting the inactivity timer; the session still expires at the original time |

Example

import { useInactivityWarning, InactivityWarningDialog } from '@pawells/react-shared';

function App() {
  const { isWarningActive, countdownSeconds, dismissWarning, extendSession } =
    useInactivityWarning({
      timeoutMinutes: 30,
      warningSeconds: 60,
      onTimeout: async () => {
        await LoginService.Logout();
        navigate('/login');
      },
    });

  return (
    <InactivityWarningDialog
      open={isWarningActive}
      countdownSeconds={countdownSeconds}
      onStayLoggedIn={extendSession}
      onLogout={async () => {
        await LoginService.Logout();
        navigate('/login');
      }}
    />
  );
}

Context

NotificationProvider

Wraps a component tree with a global notification system backed by MUI Snackbar and Alert. Supports queuing (up to 3 visible simultaneously), configurable auto-dismiss (default 6 s), manual dismiss, and four severity variants. Positioning is bottom-left on desktop and bottom-center on mobile.

Place NotificationProvider near the root of your application so all descendant components can call useNotification.

useNotification()

Returns the NotificationContextValue for the nearest NotificationProvider. Throws a BaseError with code NOTIFICATION_CONTEXT_ERROR if called outside of a NotificationProvider.

showNotification(
  message: string,
  severity: 'success' | 'error' | 'warning' | 'info',
  options?: NotificationOptions
): void

NotificationOptions

| Property | Type | Default | Description | |---|---|---|---| | duration | number | 6000 | Auto-dismiss duration in milliseconds |


Types

| Type | Description | |---|---| | InactivityWarningDialogProps | Props for InactivityWarningDialog | | LoadingStateProps | Props for LoadingState | | PageHeaderProps | Props for PageHeader | | StatCardProps | Props for StatCard | | VoronoiBackgroundProps | Props for VoronoiBackground | | InactivityWarningConfig | Configuration object passed to useInactivityWarning | | UseInactivityWarningReturn | Return value of useInactivityWarning | | NotificationContextValue | Shape of the value returned by useNotification | | NotificationOptions | Optional configuration for individual showNotification calls |

License

MIT — See LICENSE for details.