Five exports: a provider, a producer, a viewport, an imperative hook, and the underlying store factory. Everything is fully typed.

Exports
ts
import {
  StatusBarProvider,   // holds the store
  StatusBar,           // producer — registers content while mounted
  StatusBarViewport,   // host — reads a scope and renders it
  useStatusBar,        // imperative show()/hide()
  createStatusStore,   // the plain-JS store (tests / DI)
} from "@mrmartineau/react-status-bar";

import type { StatusEntry, StatusBarMode, StatusStore } from "@mrmartineau/react-status-bar";
<StatusBarProvider>
Prop Type Default Notes
children ReactNode — Your app subtree.
store StatusStore auto Inject your own store from createStatusStore() — useful for tests, or to share a store across islands/roots.
<StatusBar>

A side-effect component. Renders null; while mounted it upserts an entry into the store, and removes it on unmount.

Prop Type Default Notes
children ReactNode — Content to contribute.
priority number lowest Lower is more important (P0 > P1 > P5); lowest-numbered entry wins in replace mode. Unset → lowest, rendered last.
scope string "global" Target bar. Changing it migrates the entry correctly.
id string auto Stable identity across remounts. Defaults to a useId().
<StatusBarViewport>

Subscribes to a single scope and renders it. Owns presentation (replace vs stack) and optionally portals its output.

Prop Type Default Notes
scope string "global" Which scope to read.
mode "replace" | "stack" "replace" replace → top entry only; stack → all entries, sorted.
empty ReactNode null Rendered inside the always-mounted live region when idle.
separator ReactNode — Between items in stack mode. Marked aria-hidden.
portalTarget HTMLElement | string | null — Renders inline if omitted; warns in dev if a selector matches nothing.
className string — Added to the live region.
ariaLive "off" | "polite" | "assertive" "polite" Live-region politeness. Reserve assertive for urgent states.
renderItem (entry: StatusEntry) => ReactNode — Custom per-item wrapper (badges, icons, transitions).
useStatusBar({ scope? })

Returns an imperative handle. The entry it manages is removed automatically when the calling component unmounts.

ts
const sb = useStatusBar({ scope?: string });

sb.show(node: ReactNode, opts?: { priority?: number }): void;  // idempotent upsert
sb.hide(): void;                                               // remove the entry
createStatusStore()

The plain-JS store behind the provider. Inject it via <StatusBarProvider store={...}>, or unit-test it directly with no React involved.

ts
const store = createStatusStore();

store.upsert({ id, scope, priority, node });  // add or update (idempotent by id)
store.remove(scope, id);                      // remove an entry
store.subscribe(scope, listener);             // → unsubscribe fn
store.getSnapshot(scope);                     // StatusEntry[] (stable until changed)
Types
ts
type StatusEntry = {
  id: string;        // unique per producer instance
  scope: string;     // logical bar id
  priority: number;  // lower = more important (P0 wins); sorts first
  order: number;     // monotonic registration order (recency tiebreak)
  node: React.ReactNode;
};

type StatusBarMode = "replace" | "stack";
type StatusStore = ReturnType<typeof createStatusStore>;
idle — no global status