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

@stainless-code/react-layers

v0.1.0

Published

React adapter for @stainless-code/layers — call a layer like an async function and await its response.

Readme

@stainless-code/react-layers

Open any layer from anywhere and manage modal, dialog, drawer, popover, or toast UI as an ordered, named stack. This React adapter for @stainless-code/layers supports awaiting a typed result and fire-and-forget invocation (void client.open(...)) as equally first-class choices.

Named stacks, singletons with upsert and live update, serial queues, nested stacks, transitions, dismissal blockers, payload validation, and headless rendering each stand on their own. Full fit matrix: README — When to use it.

Install

bun add @stainless-code/react-layers

@stainless-code/layers core is pulled in automatically and re-exported — import both adapter hooks and core APIs (LayerClient, layerOptions, LayerState, LayerComponentProps, etc.) from this one package. react is a required peer dependency (you already have it; do not add it to the install line).

Getting started

1. Declare a layer

import {
  layerOptions,
  type LayerComponentProps,
} from "@stainless-code/react-layers";

export type ConfirmPayload = { title: string; message: string };
export type ConfirmResponse = boolean;

function ConfirmDialog({
  call,
  payload,
}: LayerComponentProps<ConfirmPayload, ConfirmResponse>) {
  return (
    <div role="dialog">
      <h2>{payload.title}</h2>
      <p>{payload.message}</p>
      <button type="button" onClick={() => void call.end(true)}>
        Yes
      </button>
      <button type="button" onClick={() => void call.end(false)}>
        No
      </button>
    </div>
  );
}

export const confirm = layerOptions<ConfirmPayload, ConfirmResponse>({
  stack: "confirm",
  key: ["confirm", "remove"],
  component: ConfirmDialog,
  exitingDelay: 200,
});

2. Mount a stack outlet

import { StackProvider, StackOutlet } from "@stainless-code/react-layers";

function App() {
  return (
    <StackProvider>
      <StackOutlet stack="confirm" />
    </StackProvider>
  );
}

3. Call and await

Response type ConfirmResponse is inferred from confirm — no explicit generics on open.

import { useLayerClient } from "@stainless-code/react-layers";
import { confirm } from "./confirm";

function RemoveButton() {
  const client = useLayerClient();

  async function handleRemove() {
    const ok: boolean = await client.open({
      ...confirm,
      payload: { title: "Remove?", message: "Sure?" },
    });
    if (!ok) return;
    deleteItem();
  }

  return (
    <button type="button" onClick={() => void handleRemove()}>
      Remove
    </button>
  );
}

Payload and response are both optional. A no-payload, fire-and-forget layer omits payload, does not await open, and dismisses without a response:

import {
  layerOptions,
  type LayerComponentProps,
  useLayerClient,
} from "@stainless-code/react-layers";

function Notice({ call }: LayerComponentProps) {
  return (
    <div role="status">
      Saved
      <button type="button" onClick={() => void call.dismiss()}>
        Close
      </button>
    </div>
  );
}

const notice = layerOptions({
  key: ["notice", "saved"],
  component: Notice,
});

function SaveNoticeButton() {
  const client = useLayerClient();

  return (
    <button type="button" onClick={() => void client.open(notice)}>
      Show saved notice
    </button>
  );
}

API

All imports from @stainless-code/react-layers.

Provider & client

| Export | Signature | Role | | ---------------------- | ----------------------- | ---------------------------------------------------------------------- | | StackProvider | { client?, children } | Mount a LayerClient for the subtree (creates one lazily if omitted). | | useLayerClient() | () => LayerClient | Read the nearest client; call client.open(...). |

Subscriptions

  • useStack(stackId?, selector?, compare?) => T — subscribe to a stack snapshot. The default selector returns LayerState[]; compare defaults to Object.is and preserves the previous selected reference when equal.
  • useLayer(key, stackId?, compare?) => LayerState | null — subscribe to one layer by key; null when inactive. DataTag keys from layerOptions / layerKey infer response R and error E.
  • StackSubscribe({ stack?, selector, children }) — isolate a render-prop subscription and pass its selected value to children.
const count = useStack("confirm", (states) => states.length);
const top = useStack("confirm", (states) => states.at(-1) ?? null);

Rendering

  • useStackHandles(stack?, rootProps?) => StackHandles — headless { states, getCall } for custom hosts.
  • StackOutlet({ stack?, rootProps? }) — render active layers with their registered component and full props. A missing component renders nothing and warns in development.

Nested stacks & async actions

  • useLayerGroup(call, options?) => LayerGroup — child stack scoped to a parent layer's lifetime; auto-drains on parent dismiss. Returns { open, dismissAll, states, Outlet, stackId }.
  • useMutationFlow(call) => MutationFlow<R> — drive actionStatus: "running" during async work. run(fn).orEnd(response) ends on success, or leaves the layer open and rethrows on failure.

App chrome factory

| Export | Signature | Role | | --------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | createStackHook | ({ stack?, client?, Host? }) => StackHook | Bind stack id and optional host wrapper once. Returns { StackProvider, useAppStack, AppHost, AppLayer }. |

  • useAppStack(){ open, dismissAll, states } with stack pre-bound.
  • AppHost — renders StackOutlet for the bound stack. Its props become rootProps; an optional configured Host receives the same props and wraps the outlet.
  • AppLayer — controlled open/close via props (open, payload, options, onResolved).

React-specific types

StackHandles, MutationRun<R>, MutationFlow<R>, ScopedOpen, LayerGroup, AppStack, AppLayerProps<P, R>, StackHook<HostProps>.

Core re-exports

This package export * from @stainless-code/layers — core types and APIs (LayerClient, LayerStack, layerOptions, layerKey, LayerState, LayerComponentProps, LayerCallContext, createLayerGroup, DataTag, ResponseOf, ErrorOf, validation helpers, etc.) import from the same path.

Engine concepts (transitions, blockers, validation, serial scope, gcTime) live in core — see the layers skill and architecture doc.

Full guide: repo README.