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

@wave-rf/astro-themed-mermaid

v0.3.1

Published

Build-time, theme-aware Mermaid diagrams for Astro / Starlight — color-agnostic SVG rewriting (CSS-variable theming, cluster-title pills, edge-label pills) on top of rehype-mermaid.

Readme

@wave-rf/astro-themed-mermaid

Build-time, theme-aware Mermaid diagrams for Astro / Starlight docs sites. Renders diagrams with rehype-mermaid (inline SVG, SSR'd at build), then rewrites the emitted SVG to:

  • survive Chromium's HTML parser<br></br><br> (Mermaid emits the former; the void end tag otherwise renders an extra line and overflows the <foreignObject>);
  • respond to light/dark themes — baked colors are rewritten to var(--…) references you supply, so a runtime stylesheet drives them;
  • polish flowcharts — cluster-title pills are re-centered over the subgraph border and lifted above edges/nodes; Mermaid's forced white label color is stripped so themed text works in light mode; the viewBox is expanded so the straddling title pill isn't clipped.

It is color-agnostic: the module defines no colors. You pass the Mermaid theme, the classDef palette, and the hex→CSS-var replacement map; the displayed colors live wherever those CSS variables are defined (your stylesheet). That's what makes it shareable across docs sites with different brands.

Install

pnpm add @wave-rf/astro-themed-mermaid rehype-mermaid

rehype-mermaid (and its peer mermaid) is a peer dependency — you wire it up yourself (see below).

Published under semver: ^0.3.0 tracks features and fixes without breaking changes (during 0.x, breaking changes bump the minor). For the bleeding edge, the dev dist-tag follows main: pnpm add @wave-rf/astro-themed-mermaid@dev.

Diagram SSR needs a headless Chromium. rehype-mermaid uses Playwright — pnpm exec playwright install chromium (Astro/Starlight setups usually do this already).

Usage

// astro.config.mjs
import { defineConfig } from "astro/config";
import { themedMermaid } from "@wave-rf/astro-themed-mermaid";

const mermaid = themedMermaid({
  font: { family: '"Inter Variable", sans-serif', woff2: "/abs/path/to/inter.woff2" },
  themeVariables: { primaryColor: "#14171C", lineColor: "#6B7280", /* … */ },
  classDefs: ["classDef wh fill:#0e7f8f,stroke:#5bbfcf,color:#fff,stroke-width:3px", /* … */],
  colorReplacements: [
    ["#14171C", "var(--mermaid-surface)"],
    ["#0e7f8f", "var(--mermaid-wh-bg)"],
    // …baked hex (exactly as Mermaid serializes) → your CSS variable
  ],
  flowchart: { curve: "basis", useMaxWidth: true /* … */ },
  sequence: { useMaxWidth: true, wrap: false },
});

export default defineConfig({
  markdown: {
    remarkPlugins: [mermaid.remarkInjectClassdefs],
    rehypePlugins: [mermaid.rehypeMermaid],
  },
  integrations: [/* starlight(...), */ mermaid.integration],
});

Then author diagrams normally, using the injected classes:

```mermaid
flowchart TD
  A["Client"]:::client --> B["WaveHouse"]:::wh
```

A complete, copy-pasteable config + stylesheet lives in example/.

Render cache

mermaid.rehypeMermaid wraps rehype-mermaid with a per-diagram render cache, because diagram SSR goes through a headless Chromium and dominates the build time of any site that didn't touch its diagrams — i.e. almost every build. The cache is content-addressed: each entry is keyed on sha256(diagram source + render options + package versions), so theme, config, and toolchain changes invalidate automatically, and the entry stores the rendered hast element exactly as rehype-mermaid would have spliced it (ids are rewritten to content-derived ones so entries from different builds can't collide on one page). A document whose diagrams all hit never launches the browser — nor even imports rehype-mermaid; a document with any miss is rendered by rehype-mermaid as one normal batch and harvested back into the cache. Cache I/O is best-effort: a corrupt or unwritable cache degrades to a normal render, never a failed build.

Entries land in node_modules/.cache/astro-themed-mermaid/ by default — delete it freely. Configure via cache:

themedMermaid({ cache: ".mermaid-cache" }); // custom dir (resolved from cwd)
themedMermaid({ cache: false });            // disable; render every build

In CI the directory is cold unless you persist it (e.g. actions/cache keyed on the lockfile); with it persisted, diagram-free doc changes skip Chromium entirely. The uncached spelling rehypePlugins: [[rehypeMermaid, mermaid.rehypeMermaidOptions]] keeps working if you prefer to wire rehype-mermaid yourself.

Styling

The plugin rewrites SVG geometry and swaps in your CSS variables; the matching visuals (pill chips, drop-shadows, typography) are CSS. Two options:

  1. Use the bundled stylesheet (fastest):

    // in your global CSS, or customCss in Starlight
    import "@wave-rf/astro-themed-mermaid/styles.css";

    then define the color variables it reads (--mermaid-surface, --mermaid-ink, --mermaid-ink-muted, --mermaid-border, --mermaid-cluster-border) plus the colorReplacements right-hand sides (--mermaid-wh-bg, …) for light/dark. See example/mermaid.css.

  2. Write your own scoped via svg[aria-roledescription^="flowchart"] — copy styles.css as a starting point and tune freely.

Paired magic numbers. The plugin expands the flowchart viewBox up by 22px (PAD_TOP in index.mjs) precisely so the cluster-title pill — shifted up translateY(-17px) in the CSS — isn't clipped. If you change one, revisit the other.

Config

| key | type | purpose | |---|---|---| | font.family | string | font for build-time SSR measurement | | font.woff2 | string (abs path) | woff2 inlined into build Chromium so it measures with the real font | | measurementCss | string | label-metric CSS injected at measure time (see Label clipping) | | themeVariables | object | Mermaid base theme variables (build-time hex) | | classDefs | string[] | classDef … lines injected into every flowchart/graph block | | colorReplacements | [from,to][] | baked color → runtime CSS var; the only place colors enter | | flowchart, sequence | object | non-color Mermaid config | | securityLevel | string | Mermaid securityLevel (default "strict") | | mermaidConfig | object | escape hatch for other non-color Mermaid settings; merged beneath the module's own config (which wins) |

mermaidConfig is for Mermaid settings this plugin doesn't surface directly (e.g. gantt, er, pie, htmlLabels, maxTextSize). It's merged beneath the module's own config, so it can't override the theme/color/security settings — the color-agnostic invariant holds.

The factory returns four things to wire up:

| return value | wire into | |---|---| | remarkInjectClassdefs | markdown.remarkPlugins | | rehypeMermaid | markdown.rehypePlugins (recommended — the cached drop-in) | | rehypeMermaidOptions | markdown.rehypePlugins: [[rehypeMermaid, …]] (uncached; wire rehype-mermaid yourself) | | integration | integrations |

Label clipping

Mermaid sizes each node's box by measuring the label in the build-time Chromium; the browser then displays it. If display is even ~1px wider than the measurement, the <foreignObject> crops the last glyph (Buffer ConsumerBuffer Consume). Two things cause that drift, and both are fixed by feeding the build the same inputs the browser uses:

  • Font — set font.woff2 so the real font is loaded at measure time (a fallback like Arial measures ~6–8% narrower than Inter).

  • Label metrics — if your stylesheet renders labels at, say, font-weight: 500 (or any letter-spacing), Mermaid measured them at the default 400 and every box is a hair too narrow. Pass those rules as measurementCss:

    themedMermaid({
      font: { family: '"Inter Variable", sans-serif', woff2: "/abs/inter.woff2" },
      // matches what your global CSS applies to node labels at display time,
      // plus a hair of padding for sub-pixel safety:
      measurementCss:
        ".nodeLabel p{font-weight:500;letter-spacing:-0.005em;padding-inline:1.5px;}",
    });

    Selectors must be bare. Mermaid measures the label before it's parented by the final svg[aria-roledescription="flowchart…"], so a rule scoped as svg[aria-roledescription^="flowchart"] .nodeLabel p { … } matches at display time but is a no-op at measure time. Drop the ancestor: .nodeLabel p { … }. (Edge/cluster labels usually render as overflow: visible pills and don't need this — scope to .nodeLabel p.)

How it works

classDefs are injected (via the remark plugin) after each flowchart/graph header, so source diagrams use :::name without restating the palette. Mermaid renders to inline SVG at build time with concrete hex (it needs real colors to lay out geometry). The Astro integration then post-processes the built HTML: normalizes <br></br>, swaps each baked hex for your var(--…), strips Mermaid's forced-white label color, and (for flowcharts) lifts + centers the cluster-title pills and pads the viewBox. The hex are effectively sentinels — only the right-hand side of colorReplacements (your var names) reaches the browser, where your stylesheet drives the actual colors in both themes.

Caveats

The SVG rewriting is regex over Mermaid's output, which can change between Mermaid versions (developed against Mermaid v11.x). Pin mermaid and re-verify diagrams after upgrades. pnpm test runs a smoke test over the rewrite passes to catch gross breakage.

License

MIT © Wave RF