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

pandora-box-react

v0.3.0

Published

Puck-free, framework-agnostic runtime that renders low-code builder JSON with your own components (React web + React Native).

Readme

pandora-box-react

A Puck-free, framework-agnostic runtime that renders low-code builder JSON with your own components. Give it the page document + a component registry + the manifest; it walks the JSON and renders. The same document renders on React (web) and React Native — only the registry differs. No editor, no Puck, no design-system lock-in.

npm install pandora-box-react

Peer dependency: react >= 18.

Quick start

import { PageRuntime } from 'pandora-box-react';
import { registry } from './my-registry';        // type id → your component
import manifest from './manifest.generated.json'; // emitted by your builder/extractor

export function Page({ doc, locale }) {
  return (
    <PageRuntime
      doc={doc}                 // the "Page JSON" the builder produces
      registry={registry}       // { Button, Image, Swiper, ... }
      manifest={manifest}       // tells the walker which props are slots / arrays / text
      locale={locale}           // "en" | "zh" | …  → localized text resolves to this
      fallbackLocale="en"
    />
  );
}

Pre-bind once with createRuntime

Bind your registry + manifest (+ an optional provider) once, get a tiny <Runtime doc locale />:

import { createRuntime } from 'pandora-box-react';
import { registry } from './my-registry';
import manifest from './manifest.generated.json';
import { ThemeProvider } from './theme'; // optional design-system provider

export const PageRuntime = createRuntime({
  registry,
  manifest,
  wrapper: ThemeProvider,   // receives `locale`; wraps the rendered page
  fallbackLocale: 'en',
});

// anywhere:
<PageRuntime doc={pageJson} locale="zh" />

React Native

Same component, native registry — the document JSON is identical across platforms:

import { createRuntime } from 'pandora-box-react';
import { registry } from './my-registry.native'; // your RN components by the same type ids
import manifest from './manifest.generated.json';

export const PageRuntime = createRuntime({ registry, manifest });

How it works

  • The document is { root, content: Node[], zones }; each Node is { type, props }.
  • The manifest describes each component's props. The walker uses it to know which props are slots (Node[] → recurse), arrays (rows, each possibly with slots/text), and text (resolve a { locale: string } map to the active language).
  • Unknown node.types are skipped (or pass a fallback). Each component is wrapped in an error boundary, so one bad component never crashes the page.

API

| export | description | | --- | --- | | PageRuntime | { doc, registry, manifest, locale?, fallbackLocale?, fallback?, wrapper?, onAction? } → renders the page | | createRuntime | pre-bind { registry, manifest, wrapper?, fallbackLocale?, onAction? }(props) => <Runtime/> | | Render | the low-level walker: { data, registry, manifest, locale?, fallbackLocale?, fallback?, onAction? } | | resolveLocalized(value, locale?, fallback?) | resolve a LocalizedString to a string | | isLocalizedMap(value) | is a value a { locale: string } map? | | resolveMedia(value) / isMediaRef(value) | resolve a { $media } image reference to its snapshot URL | | isAction(value) | is a value a usable declarative Action? | | types | DocData, Node, Manifest, ComponentManifest, ManifestField, FieldDescriptor, LocalizedString, MediaRef, MediaValue, Action, ActionTarget |

i18n

Text props can be a plain string or a { locale: string } map:

{ "type": "Typography", "props": {
    "text": { "en": "Enjoy your Travel in China", "zh": "畅游中国之旅" } } }

The runtime resolves text to locale (→ fallbackLocale → first available → as-is). Plain strings keep working unchanged, so localization is fully backward-compatible.

Media ($media)

An image field's value can be a plain URL or a hybrid media reference carrying a CMS asset id plus a denormalized snapshot:

{ "src": { "$media": { "provider": "contentful", "kind": "asset", "id": "6WoO…", "url": "https://images.ctfassets.net/…/2.jpg" } } }

The runtime resolves it to the snapshot url before it reaches your component (top-level and inside array rows). Plain URL strings pass through unchanged.

Actions (onAction)

Documents are props-only JSON, so interactions are stored as DATA — an action descriptor ({ type: 'navigate', href } or { type: 'event', name, payload? }). The runtime turns it into a real onClick that calls YOUR onAction dispatcher (top-level action prop and per-row inside array fields with an action item field):

<PageRuntime
  doc={doc}
  registry={registry}
  manifest={manifest}
  onAction={(action) => {
    if (action.type === 'navigate') openWebview(action.href);
  }}
/>

The host decides what navigation means (web location, in-app webview, RN navigator) — the document stays portable.

License

MIT