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

@lockerverse/react

v0.2.97

Published

Tree-shakable React payment and signup UI for Lockerverse

Readme

@lockerverse/react

Tree-shakable React UI for Lockerverse payment and signup widgets. The Core SDK is installed automatically as a normal package dependency.

Install

npm install @lockerverse/react react react-dom

For payment UI, also install the optional Stripe peers:

npm install @stripe/react-stripe-js @stripe/stripe-js

Use

import {
  LockerversePayment,
  type LockerversePaymentCompletion,
  type LockerversePaymentSelectionItem,
} from "@lockerverse/react/payment";
import "@lockerverse/react/payment.css";
import { useLockerverseWidget } from "@lockerverse/react/widget";

export function Checkout() {
  const widget = useLockerverseWidget({
    communitySlug: "auburn",
    widgetSlug: "tailgate-party",
  });
  return (
    <LockerversePayment
      metadata={{ source: "community-site" }}
      onPaymentComplete={(payment: LockerversePaymentCompletion) => {
        console.info("Payment complete", payment.checkoutId);
        console.info("Customer", payment.email);
        console.info("Authoritative items", payment.lineItems);
      }}
      onPaymentUncertain={({ paymentReference, reason }) => {
        console.info("Payment needs status recovery", paymentReference, reason);
      }}
      selection={[{ productSlug: "adult", quantity: 1 }]}
      theme="dark"
      widget={widget}
    />
  );
}

The original @lockerverse/react and @lockerverse/react/styles.css payment imports remain supported.

Resource identity

A mounted hook or widget keeps one resource identity. Do not change its API, environment, community slug, widget slug, or signup slug. To show a different resource, remount the owning component with a new React key:

<Checkout
  key={`${communitySlug}:${widgetSlug}`}
  communitySlug={communitySlug}
  widgetSlug={widgetSlug}
/>

Selection, theme, callbacks, and other view properties can change without a remount. refresh() reloads the same resource.

Custom Product UI

Use useLockerverseWidget to build custom Product presentation from the live Lockerverse catalog. This entry point does not import the payment UI or Stripe.

import {
  LockerversePayment,
  preloadLockerversePayment,
  type LockerversePaymentSelectionItem,
} from "@lockerverse/react/payment";
import "@lockerverse/react/payment.css";
import { useLockerverseWidget } from "@lockerverse/react/widget";
import { useState } from "react";

const widgetOptions = {
  communitySlug: "auburn",
  widgetSlug: "tailgate-party",
};

export function CustomProductCheckout() {
  const widget = useLockerverseWidget(widgetOptions);
  const [selection, setSelection] =
    useState<LockerversePaymentSelectionItem | null>(null);

  if (widget.loading) {
    return <p>Loading checkout...</p>;
  }
  if (widget.error) {
    return <button onClick={widget.refresh}>Try again</button>;
  }
  if (!widget.catalog) {
    return null;
  }
  if (selection) {
    return (
      <LockerversePayment
        selection={[selection]}
        widget={widget}
      />
    );
  }

  return widget.catalog.products
    .filter((product) => product.pricingMode === "fixed")
    .map((product) => (
      <button
        key={product.id}
        onFocus={() => {
          void preloadLockerversePayment(widget.catalog);
        }}
        onClick={() =>
          setSelection(
            product.paymentOption === "one-time"
              ? { productSlug: product.slug, quantity: 1 }
              : { productSlug: product.slug }
          )
        }
        onPointerEnter={() => {
          void preloadLockerversePayment(widget.catalog);
        }}
      >
        {product.name}
      </button>
    ));
}

The hook returns immutable catalog data together with loading, error, and refresh. The host owns presentation and selection state. Pass the selected Product slugs to LockerversePayment; Lockerverse remains authoritative for availability, pricing, and payment.

Pass the hook result to LockerversePayment with widget={widget}. The result contains the loaded catalog and its client, so the component requests only the authoritative quote without repeated configuration. The host can show a local catalog total before checkout. The component uses the same local estimate to mount the payment form and Stripe immediately, then replaces it with the authoritative quote in the background. Payment confirmation still requires the current authoritative quote.

This small example shows fixed-price Products. For a custom-price Product, ask for the amount in the host UI and pass amountCents with productSlug.

For a monthly or annual Product, omit quantity. The component shows the cadence and configures Stripe Elements for a subscription:

<LockerversePayment
  selection={[{ productSlug: "monthly-supporter" }]}
  widget={widget}
/>

Recurring checkout accepts one fixed Product. It does not accept quantities, custom amounts, or multiple Products.

Donate launcher

LockerverseDonateLauncher turns an existing payment widget into a native React dialog. The launcher selects its controls from each Product's existing capabilities. Visitors can set quantities for fixed one-time Products and add an inline amount for custom one-time Products. The launcher combines these one-time choices in one checkout. Monthly and annual Products are exclusive: the visitor selects one tier before the same LockerversePayment form opens in subscription mode.

import { LockerverseDonateLauncher } from "@lockerverse/react/donate-launcher";
import { useLockerverseWidget } from "@lockerverse/react/widget";
import "@lockerverse/react/payment.css";

export function Donate() {
  const widget = useLockerverseWidget({
    communitySlug: "auburn",
    widgetSlug: "general-donations",
  });
  return (
    <LockerverseDonateLauncher
      buttonLabel="Donate"
      position="bottom-right"
      widget={widget}
    />
  );
}

Use position="inline" to place the launcher in the normal page layout. Use bottom-left or bottom-right for a fixed launcher. Payment callbacks, branding, themes, metadata, and recovery properties are the same as LockerversePayment. API and transport options belong to useLockerverseWidget.

The launcher starts loading Stripe when the visitor opens it. Catalog-only pages do not load Stripe.

Signup

The signup entry does not import payment or Stripe code.

import {
  LockerverseSignup,
  useLockerverseSignup,
} from "@lockerverse/react/signup";
import "@lockerverse/react/signup.css";

export function Signup() {
  const widget = useLockerverseSignup({
    communitySlug: "auburn",
    signupSlug: "tailgate-guests",
  });
  return (
    <LockerverseSignup
      branding={{
        accentColor: "#5751f2",
        imageUrl: "https://cdn.example.com/community.png",
        name: "Auburn",
      }}
      onSignupComplete={(submission) => {
        console.info("Signup complete", submission.id);
      }}
      widget={widget}
    />
  );
}

Pass googlePlacesApiKey to enable US address suggestions when the signup asks for an address. Manual address entry always remains available.

For a development HTTPS backend, provide apiBaseUrl to the hook. The backend supplies the correct Stripe public key.

const widget = useLockerverseWidget({
  apiBaseUrl: "https://portal-dev.lockerverse.com/api",
  communitySlug: "luis-c",
  environment: "development",
  widgetSlug: "new-payment-widget",
});

<LockerversePayment
  selection={[{ productSlug: "adult", quantity: 1 }]}
  widget={widget}
/>

Styling

Use theme="dark" or theme="light". Lockerverse applies the community branding returned by the widget API. Pass the same LockerverseStyle object to payment, signup, and donate launcher components.

import type { LockerverseStyle } from "@lockerverse/react";

const lockerverseStyle = {
  "--lockerverse-accent": "#ff6b35",
  "--lockerverse-bg": "#fffaf0",
  "--lockerverse-control": "#f5eddf",
  "--lockerverse-radius": "14px",
  "--lockerverse-text": "#211c17",
} satisfies LockerverseStyle;

<LockerversePayment
  selection={selection}
  style={lockerverseStyle}
  widget={widget}
/>

The canonical --lockerverse-* tokens control every component. Existing --lockerverse-signup-* tokens remain supported as signup-only aliases.

The package keeps React, React DOM, and Stripe's React libraries as peer dependencies so it does not ship duplicate framework code. LockerversePayment leaves product selection to its host. LockerverseDonateLauncher provides selection from the existing widget catalog. Neither component depends on Lockerverse's Next.js application components.

Payment outcomes

onPaymentComplete runs only after Lockerverse reports success. A successful payment is terminal, even if the host callback throws.

A direct completion includes the normalized customer email and authoritative lineItems. A completion recovered after reload has null for both fields.

If the authoritative total, discount, currency, line items, or connected Stripe account changes, the component displays the new quote before creating a Stripe token. The customer must explicitly submit again.

An authoritative failed result is retryable and the next submit receives a new payment reference. pending, unresolved action_required, and failed same-reference recovery stay locked so the customer cannot accidentally create a second payment. The optional onPaymentUncertain callback receives the retained paymentReference and one of these reasons:

  • pending
  • action_required
  • recovery_failed

To abandon a locked attempt and intentionally start a new checkout, the host must remount LockerversePayment with a new React key after resolving the payment status through its own workflow.

Persist onPaymentRecoveryChange synchronously before navigation and pass the saved value back through resumePayment after a refresh. The recovery value contains a Lockerverse reference and public connected-account ID, never a Stripe secret.

import type { LockerversePaymentRecovery } from "@lockerverse/react";

const recoveryKey = "lockerverse:tailgate-party:payment";
const savedRecovery = sessionStorage.getItem(recoveryKey);
const recovery = savedRecovery
  ? (JSON.parse(savedRecovery) as LockerversePaymentRecovery)
  : null;

<LockerversePayment
  selection={selection}
  resumePayment={recovery}
  onPaymentRecoveryChange={(nextRecovery) => {
    if (nextRecovery) {
      sessionStorage.setItem(recoveryKey, JSON.stringify(nextRecovery));
    } else {
      sessionStorage.removeItem(recoveryKey);
    }
  }}
  widget={widget}
/>

Malformed host selections and invalid custom tips render customer-safe validation messages and do not call the Lockerverse API. Product selection remains owned by the host application.