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

v1.0.5

Published

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

Readme

@pawells/react-shared

npm License

Shared React UI components, hooks, and notification context for @pawells applications. Built on MUI (Material UI).

Installation

yarn add @pawells/react-shared

MUI and React must be present as peer dependencies in your project.

Components

VoronoiBackground

Animated SVG canvas background using Voronoi/Delaunay triangulation. Renders an array of colored triangles that fill the viewport, derived from a seeded or random point distribution.

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

<VoronoiBackground primaryColor="#1a73e8" />

// With explicit gradient endpoints
<VoronoiBackground primaryColor="#1a73e8" secondaryColor="#e8f0fe" seed={42} />

| Prop | Type | Default | Description | |---|---|---|---| | primaryColor | { r, g, b } \| string | — | Required. Primary gradient color (RGB object or hex string). When secondaryColor is omitted, a monochromatic gradient is derived from this color via HSV interpolation | | secondaryColor | { r, g, b } \| string | derived | Secondary/end color. When omitted, the hue and saturation of primaryColor are preserved while brightness is set to 90% (bright) vs 10% (dark) | | seed | number | Date.now() | Seed for deterministic random generation. Only read on initial mount; changes after mount are ignored | | zIndex | number | -1 | CSS z-index for layering | | opacity | number | 1 | Opacity of the entire background | | overlay | string | — | CSS color with alpha for a darkening/lightening overlay, e.g. 'rgba(0,0,0,0.3)' | | blur | number | 0 | Blur in pixels applied to the triangles | | className | string | — | CSS class for the container div | | style | React.CSSProperties | — | Inline styles for the container div | | pointerEventsNone | boolean | true | Disables pointer events so clicks pass through to content below | | pointCount | number | 98 | Number of internal seed points; higher values produce more polygons | | edgePointCount | number | 20 | Points placed along each viewport edge to ensure full coverage | | minAreaDivisor | number | 750 | Controls small-triangle pruning aggressiveness | | maxPruningIterations | number | 10 | Maximum pruning iterations |

InactivityWarningDialog

Controlled dialog that warns the user about an upcoming session timeout. Displays a formatted countdown timer and "Stay Logged In" / "Logout Now" buttons. The parent component manages open state and callbacks.

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

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

| Prop | Type | Required | Description | |---|---|---|---| | open | boolean | Yes | Whether the dialog is visible | | 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" or the countdown expires |

Pair with useInactivityWarning to manage state automatically.

LoadingState

Centered MUI spinner with an optional message. Suitable as a Suspense fallback or a data-loading placeholder.

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

<LoadingState />
<LoadingState size="large" message="Fetching data..." />

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

PageHeader

Page-level header with a title, optional subtitle, and optional action slot. Stacks vertically on mobile, displays as a row on desktop.

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

<PageHeader
	title="Dashboard"
	subtitle="Welcome back"
	actions={<Button variant="contained">Add User</Button>}
/>

| Prop | Type | Required | Description | |---|---|---|---| | title | string | Yes | Main heading text (rendered as h1 / h4 variant) | | subtitle | string | No | Subdued subtitle displayed below the title | | actions | React.ReactNode | No | Action elements displayed on the right side |

StatCard

MUI Card that displays a metric with an icon and optional trending indicator. Includes a hover lift animation.

import { StatCard } from '@pawells/react-shared';
import PeopleIcon from '@mui/icons-material/People';

<StatCard
	title="Total Users"
	value="1,234"
	icon={<PeopleIcon />}
	color="success"
	change={12}
/>

| Prop | Type | Default | Description | |---|---|---|---| | title | string | — | Required. Card title | | value | string \| number | — | Required. Prominent metric value | | icon | React.ReactNode | — | Required. Icon element displayed in the card | | color | 'primary' \| 'success' \| 'warning' \| 'error' | 'primary' | MUI color theme applied to the value and icon | | change | number | — | Percentage change; renders a trending chip with ↑/↓ indicator |

Hooks

useNotification / NotificationProvider

Global notification queue backed by MUI Snackbar + Alert. Supports up to 3 simultaneously visible notifications with auto-dismiss and manual dismiss.

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

// 1. Wrap your app (once, near the root)
<NotificationProvider>
	<App />
</NotificationProvider>

// 2. Show notifications from any component
function SaveButton() {
	const { showNotification } = useNotification();

	const handleSave = async () => {
		try {
			await api.save();
			showNotification('Saved successfully', 'success');
		} catch {
			showNotification('Failed to save', 'error');
		}
	};

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

showNotification(message, severity, options?)

| Parameter | Type | Description | |---|---|---| | message | string | Notification text | | severity | 'success' \| 'error' \| 'warning' \| 'info' | Alert severity level | | options.duration | number | Auto-dismiss duration in ms. Defaults to 6000 |

Features: queue management (max 3 visible), responsive positioning (bottom-left on desktop, bottom-center on mobile), manual dismiss via close button.

useInactivityWarning

Tracks user inactivity via DOM events (mousedown, keydown, scroll, touchstart, click) and triggers a countdown warning before the session expires.

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

function App() {
	const { isAuthenticated, logout } = useAuth();
	const { isWarningActive, countdownSeconds, extendSession } = useInactivityWarning({
		timeoutMinutes: 30,
		warningSeconds: 60,
		onTimeout: async () => {
			await logout();
			navigate('/login');
		},
	});

	return (
		<>
			<Routes />
			{isAuthenticated && (
				<InactivityWarningDialog
					open={isWarningActive}
					countdownSeconds={countdownSeconds}
					onStayLoggedIn={extendSession}
					onLogout={logout}
				/>
			)}
		</>
	);
}

Config

| Option | Type | Default | Description | |---|---|---|---| | timeoutMinutes | number | 60 | Total inactivity timeout before onTimeout is called | | warningSeconds | number | 300 | How many seconds before timeout to show the warning | | onTimeout | () => void \| Promise<void> | — | Required. Called when the countdown reaches zero |

Return value

| Field | Type | Description | |---|---|---| | isWarningActive | boolean | Whether the warning dialog should be shown | | countdownSeconds | number | Remaining seconds shown in the countdown | | extendSession | () => void | Resets the inactivity timer and hides the warning | | dismissWarning | () => void | Hides the warning without resetting the timer |