@pawells/react-shared
v3.0.0
Published
Shared React utilities library for hooks, components, context, and HOCs
Maintainers
Readme
React Shared Utility Library
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 wheneverStatCardis imported)
Installation
Install the package along with all required peer dependencies:
npm install @pawells/react-shared react react-dom @mui/material @emotion/react @emotion/styledIf you use StatCard, also install the optional peer:
npm install @mui/icons-materialQuick 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
): voidNotificationOptions
| 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.
