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

@wingleeio/mugen-markdown

v0.4.4

Published

Measurable markdown for mugen — incremark-parsed, rendered with mugen primitives so the virtualizer's tree walker computes exact row heights.

Readme

@wingleeio/mugen-markdown

Measurable markdown for @wingleeio/mugen. Markdown is parsed with incremark into an mdast tree, then rendered with mugen primitives — so mugen's tree walker computes each row's height analytically, off-screen and never-mounted rows included, with no measure-on-mount layout shift.

The hard part of markdown in an analytic virtualizer is inline rich text: a sentence like “see foo() for details” is one wrapping flow of mixed fonts, which a single-font <Text> can't measure. mugen-markdown introduces a RichText primitive that measures mixed-font runs as one flow via @chenglou/pretext's rich-inline layout — the same layout the browser performs over the rendered spans, so the analytic height matches the paint exactly (verified by a real-browser accuracy gate).

Install

npm i @wingleeio/mugen-markdown @wingleeio/mugen

Requires React 18.2 or 19. ESM + CJS, Node ≥22.

Quick start

import { MugenVList, useMugenVirtualizer } from '@wingleeio/mugen';
import { Markdown } from '@wingleeio/mugen-markdown';

function Thread({ messages }: { messages: Message[] }) {
  const list = useMugenVirtualizer({ items: messages });
  return (
    <MugenVList
      instance={list}
      getKey={(m) => m.id}
      maxW="3xl"
      stickToBottom
      render={(m) => <Markdown source={m.body} />}
    />
  );
}

<Markdown> is a pure, hook-free component: it produces the identical primitive tree in mugen's measure walk and in React's render, so heights can't desync.

Streaming

Streaming a growing source (LLM output) just works — pass the new string each tick and every row re-measures to its exact height as it grows. Parsing is incremental automatically: when a source extends the one a row parsed last, mugen-markdown appends only the new text to a retained incremark parser (O(delta)), instead of re-parsing the whole prefix each tick (O(n²) over the stream). Unchanged rows (older messages) are served from a parse cache and never re-parsed; a non-extending edit falls back to a fresh parse. No API to learn — it keys off the source value, so the same <Markdown source={text} /> is fast whether text is static or still being written.

Theming

Everything that affects height — fonts, line heights, paddings, gaps — lives in the theme as concrete values (the measure walk only sees props, never React context). Fonts are a family plus sizes/weights; inline variants (bold in a heading, code in a paragraph) are composed automatically. Pass a deep-partial theme:

<Markdown
  source={md}
  theme={{
    fontFamily: 'Inter',
    monoFamily: 'JetBrains Mono',
    fontSize: 15,
    lineHeight: 24,
    link: { color: '#7c3aed' },
    code: { background: '#0b1020', color: '#e5e7eb' },
  }}
/>

Families must be measurable — a named web font ("Inter") or a canvas-safe generic ("sans-serif", "monospace"). "system-ui" is rejected, because its canvas metrics drift from what CSS paints.

Syntax highlighting

Fenced code blocks are syntax-highlighted by default — without ever touching layout, and without ever blocking a frame. The <pre><code> renders its plain text immediately (selectable, searchable, accessible) and stays the layout source of truth; the language is tokenized off the critical path in time-sliced chunks; and token colours are painted onto canvas tiles overlaying the text, at which point the DOM text flips to color: transparent in the same frame. Because highlighting is pure paint, it can't change a block's measured height — lines × lineHeight + padding stays exact, tokens or not — and streaming appends re-tokenize and repaint only the changed tail. Tiles allocate canvas memory only while near the viewport, so huge blocks stay cheap.

Tune the palette (or turn it off) through the theme:

<Markdown
  source={md}
  theme={{
    code: {
      highlight: { keyword: '#c678dd', string: '#98c379' }, // deep-partial
      // highlight: false,                                  // or disable
    },
  }}
/>

A compact built-in tokenizer covers the common fence languages (ts/js, python, rust, go, c/c++/c#, java, php, ruby, swift, kotlin, shell, sql, css/scss, html, json, yaml, toml, dockerfile, …); unknown languages simply stay plain. Register your own with registerLanguage(['mylang'], profile).

Extending: typed components

Override any block-level node with a typed component. The node is the matching mdast node, children is what the default would render (so you can wrap it), and ctx exposes recursion + theme helpers. Build overrides from mugen primitives (re-exported here) so they stay measurable:

import {
  Markdown,
  defineMarkdownComponents,
  VStack,
  RichText,
} from '@wingleeio/mugen-markdown';

const components = defineMarkdownComponents({
  // `node` is `Heading` — `node.depth` is 1..6.
  heading: ({ node, children, ctx }) =>
    node.depth === 1 ? (
      <VStack gap={4} padding={8} style={{ borderLeft: '3px solid #7c3aed' }}>
        {children}
      </VStack>
    ) : (
      children
    ),

  // `node` is `Code`.
  code: ({ node, ctx }) => <MyHighlightedCode value={node.value} lang={node.lang} ctx={ctx} />,
});

<Markdown source={md} components={components} />;

Inline marks (bold, italic, code, links, strikethrough) are styled through the theme, not as components — inline content must collapse into one wrapping flow to be measured exactly. For full inline control, override the block component (e.g. paragraph) and build runs with ctx.inlineRuns(...).

What's overridable

paragraph, heading, thematicBreak, blockquote, list, code, table, image, html. GFM (tables, task lists, strikethrough, autolinks) is on by default. Images have no intrinsic measurable height — the default renders the alt text; override image for real images with known dimensions.

Primitives

  • RichText — mixed-font inline that wraps as one flow; height is lines × lineHeight from pretext's rich-inline layout.
  • CodeBlock — non-wrapping code; height is lines × lineHeight + padding. Highlights known languages via the non-blocking canvas overlay (see above).
  • TableBlock — GFM tables with columns aligned across rows (widths proportional to content, identical in measure and paint), header background, hairline dividers, and a rounded outer ring — all height-neutral.

Both are built with mugen's markPrimitive, the same way you'd build your own.

Develop

pnpm --filter @wingleeio/mugen-markdown test          # node tests (happy-dom, pretext mocked)
pnpm --filter @wingleeio/mugen-markdown test:browser  # real-browser accuracy gate (Playwright/Chromium)
pnpm --filter @wingleeio/mugen-markdown check-types
pnpm --filter @wingleeio/mugen-markdown build         # ESM + CJS + d.ts via tsdown