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

@zhin.js/jsx

v1.1.6

Published

Lazy message JSX trees and explicit HTML serialization for Zhin.js

Readme

@zhin.js/jsx

Lazy JSX elements and the HTML serializer used by zhin.js/jsx. Its only dependency is the canonical IM contract (imported as types) and it does not send messages, access a Plugin generation or take screenshots.

Use jsxImportSource: "zhin.js" in a Zhin application. A JSX expression produces a branded element; renderToHtml evaluates synchronous or asynchronous function components and preserves nested markup.

import { renderToHtml } from 'zhin.js/jsx';

const card = <section style={{ padding: 16 }}><h2>服务状态</h2><p>在线</p></section>;
const html = await renderToHtml(card);

Server-side TSX support only transpiles JSX; it is not a stylesheet build pipeline. Direct import './card.css', CSS Modules and CSS ?raw imports are unsupported. Sass/SCSS, Less, Stylus, PostCSS and other style preprocessing or generation are outside its scope. Use inline style objects or declaration strings on JSX elements, and ThemeProvider / custom.style for visual components. Browser Console pages use a separate build pipeline and are outside this server-side TSX contract.

Commands, inbound middleware and registered component renders can return JSX directly. Default JSX is message layout, producing ordered Segments. Built-in lowercase tags are typed and require no imports:

const message = <>hello<image src="https://example.com/photo.png" /><mention target="123" /></>;
const music = <share title="海阔天空" url="https://music.163.com/#/song?id=387717" />;
const card = <html width={540} text="服务状态:在线"><section><h2>服务状态</h2><p>在线</p></section></html>;

Only <html> / the imported Html component serializes its children as HTML. Outside it, a tag mirrors { type, data }: <mention target="123" /> produces { type: 'mention', data: { target: '123' } }. Function components may return Segments, JSX, text, arrays, promises or null. Registered components/music/index.tsx can be invoked as <music /> and return <share />. Native <card {...platformPayload} /> preserves the platform's payload; the styled Card from @zhin.js/components belongs inside <html>.

Native <button onClick={(message) => <text>Hello {message.sender?.name}</text>}>Reply</button> uses the current runtime's interactive routing. Its result is replied to in the clicking conversation, under the original plugin author. Callbacks are never serialized and only work in the original conversation and active generation; old buttons expire on reload. null, undefined and booleans send no reply. Use the clicking Message to enforce application-specific permissions. Lowercase message tag types are supplied by zhin.js/jsx-runtime, not this standalone HTML serializer package.

Strings are escaped text, including strings returned from function components. Only explicit rawHtml(markup), <Raw html={markup} /> or dangerouslySetInnerHTML={{ __html: markup }} insert trusted markup. Do not pass user-provided HTML into those raw channels. Intrinsic script elements, browser event handlers and React hooks are unsupported.

Fragments and arrays retain child order; promises are awaited. null, undefined and booleans render nothing, while 0 remains visible. Style objects use camelCase or CSS property names; nonzero numeric lengths acquire px, unitless properties and CSS variables do not. SVG case-sensitive names such as viewBox are preserved, and aliases such as strokeWidth are translated.

Use JSXRenderable for a custom component's children or display props, including values produced by calling an asynchronous component directly. An asynchronous component may declare its return type as Promise<JSXNode>; its result is accepted by JSX children, arrays, createElement and renderToHtml.

Cycles, malformed nodes, child content in HTML void elements and component errors reject rendering. renderToHtml(node, { maxDepth: 100 }) bounds nested elements, components, arrays and promises; 100 is the default.

Run pnpm --filter @zhin.js/jsx build, pnpm --filter @zhin.js/jsx test and pnpm --filter @zhin.js/jsx test-type.