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

@fuaran-ui/renderer

v0.5.0

Published

React renderer + reference CSS + per-instance custom-renderer registry for the Fuaran UI typed Node tree — a conformant TypeScript host of the language-neutral contract in fuaran-dotnet/docs/WIRE_FORMAT.md. Renders any tree @fuaran-ui/ui authors or @fuara

Downloads

840

Readme

@fuaran-ui/renderer

The React renderer for the Fuaran UI typed Node tree — the user-visible surface of the TypeScript reference implementation. A conformant host of the language-neutral wire-format contract (fuaran-dotnet/docs/WIRE_FORMAT.md): it renders any tree @fuaran-ui/ui authors or @fuaran-ui/ops decodes, with class-name and ARIA parity to the F# reference renderer (the packaged reference CSS keys off those exact class names).

npm install @fuaran-ui/ui @fuaran-ui/ops @fuaran-ui/renderer react react-dom
import { FuaranRenderer } from '@fuaran-ui/renderer';
import '@fuaran-ui/renderer/css';
import { fuaran, node } from '@fuaran-ui/ui';

const tree = node('root', fuaran.heading({ level: 1, text: { kind: 'Literal', value: 'Hello' } }));

export const App = () => <FuaranRenderer tree={tree} />;

Custom-renderer registry

NodeKind.Custom is the bounded escape hatch. Registries are per-instance (never module-global) — the host threads one in via the runtime prop:

import {
  createCustomRendererRegistry,
  registerCustomRenderer,
  FuaranRenderer,
} from '@fuaran-ui/renderer';

const registry = createCustomRendererRegistry();
registerCustomRenderer(registry, 'charts', 'sparkline', ({ props }) => (
  <MySparkline data={props.points} />
));

<FuaranRenderer tree={tree} runtime={{ registry }} />;

Theme bridge

import { FuaranRenderer, defaultTheme } from '@fuaran-ui/renderer';

<FuaranRenderer tree={tree} theme={defaultTheme} />; // injects --fuaran-* vars at the root

In-page introspection (window.__fuaran)

Pass debug to register a DEBUG-only console global that exposes the running UI's typed layer — so the browser DevTools console answers "which node is this, what did this binding resolve to, where is it on screen?" instead of handing back an untyped post-projection DOM node.

// Gate on the bundler's dev flag so it never registers in a production build.
<FuaranRenderer tree={tree} sources={sources} debug={import.meta.env.DEV} />

Then, in the DevTools console of the running app:

__fuaran.help(); // method reference
__fuaran.inspectTree(); // recursive structural snapshot (every node id)
__fuaran.getNodeState('submit-btn'); // kind + bound binding slots + child ids
__fuaran.getBindingValue('counter-kpi', 'Source'); // resolved value vs the live sources
__fuaran.getRenderedDom('counter-kpi'); // live geometry (x/y/size + overflow/hidden)
__fuaran.findNodes('Button'); // ids of every node of a kind
__fuaran.apply(op); // policy-gated TreeOp mutation (default-deny)
__fuaran.getBindingState('counter-kpi', 'Source'); // as getBindingValue, tagged with the binding's identity
__fuaran.treeRevision(); // opaque token identifying the current tree state
__fuaran.subscribe((c) => console.log(c)); // committed-tree-change signal → unsubscribe fn

The global tracks the live tree + sources (it re-registers on each render), so a value read after a state change reflects the new state. Its shape is DEBUG-only and unstable (excluded from semver), and it is undefined unless debug is set — leave it on import.meta.env.DEV and a production build never registers it. buildDebugGlobal(tree, sources, options?) / registerDebugGlobal(global) are exported for hosts that want to wire the global on their own terms.

Policy-gated apply(op)

apply decodes a canonical TreeOp and applies it to the live tree — but only when the host's policy gate permits, so an in-page mutation obeys the same default-deny contract as every other dispatch path. Wire it by passing onApply (the host's "re-render with this tree" callback, typically a setState) alongside debug; the apply consults runtime.canDispatch first:

<FuaranRenderer
  tree={tree}
  runtime={runtime}
  debug={import.meta.env.DEV}
  onApply={setTree}
  validate={(candidate) => {
    const r = preEmitValidate(candidate); // @fuaran-ui/ui — optional
    return r.ok ? [] : r.error;
  }}
/>

The op may be a JSON string (paste it into the console) or a structured object — the same edit, and the host serialises the object canonically rather than asking the caller to.

apply returns a structured envelope, never a silent no-op: { ok: true, status: 'applied', treeRevision } on success; { ok: false, status: 'denied', denied: true, error } when the gate refuses (the tree is unchanged); 'decodeFailed' (carrying the codec's DecodeError) / 'rejected' (carrying the diagnostic code) for a malformed or inapplicable op; and 'unwired' when no onApply was supplied (a read-only surface). A host that omits runtime (or its canDispatch) allows by default, matching every other dispatch path.

The optional validate prop runs the host's tree validator on the candidate tree and folds the edit only when it introduces no defect the tree did not already carry — a pre-existing defect is not the edit's fault and does not block it.

Change subscription

__fuaran.subscribe(cb) reports committed tree changes and returns an unsubscribe handle. It pushes — there is nothing to poll — and rapid changes coalesce into one notification carrying the latest treeRevision, because a change is a staleness signal rather than a change log: re-read what you need. The subscription lives on a page-wide hub, so it survives the surface rebuild that every tree change causes.

const off = __fuaran.subscribe(({ treeRevision, cause }) => refresh(treeRevision, cause));
off(); // stop

treeRevision is opaque: compare it for equality to notice a cached read has gone stale; never parse or order it.

DevTools relay (relay) — off by default

relay installs a same-origin postMessage endpoint that carries the surface above across the page/extension boundary, so a browser extension (or any other same-page script) can inspect — and, where onApply is wired, edit — the live tree. It implements the [email protected] contract (DEVTOOLS_RELAY.md in the specification repository) and is pinned against that contract's fixture family.

<FuaranRenderer
  tree={tree}
  debug={import.meta.env.DEV}
  relay={import.meta.env.DEV}
  onApply={setTree}
/>

Three properties are deliberate and worth knowing before you enable it:

  • Off by default, and absent rather than inert. Without relay, no listener is installed at all, so a probe gets no answer whatsoever. Gate it on the same dev flag as debug; it is a debugging affordance, not a feature flag.
  • No side door. Every relayed mutation crosses this host's own decode → validate → policy path, in the page. The relay contributes no apply engine, no validator, and no policy — a relay client's reach is exactly the set of legal, permitted ops, and no message can widen it.
  • Origin discipline. Messages are accepted only from this same window at this same origin, replies are posted at window.origin (never "*"), and anything failing those checks is ignored in silence — a refusal would itself disclose that a Fuaran host is present.

createRelayPeer / installRelayPeer are exported for hosts wiring the peer on their own terms; both are not opted in unless told to be.

Sanitisation

Every string→DOM seam (href, dangerouslySetInnerHTML, custom attributes) routes through @fuaran-ui/renderer/sanitize. Custom-registered React components are a host trust boundary — they are expected to do their own escaping.

Apache-2.0. Part of the @fuaran-ui/* package set.