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

@still-void/ui

v1.1.1

Published

Still Void design system — framework-agnostic TypeScript core (tokens, CSS, recipes, behaviors) with an optional React adapter compatible with Next.js Server Components.

Readme

@still-void/ui

npm CI

Still Void design system as a framework-agnostic TypeScript library — extracted from the blog.kalleopinheiro.dev prototype. Works with React, Angular, Vue, or plain HTML, with first-class support for Next.js Server Components.

Architecture

The library is layered so the core never depends on any framework:

| Layer | Entry | Runs where | What it is | |---|---|---|---| | Tokens | @still-void/ui | anywhere | Typed constants: colors (hex + oklch), typography, spacing, radii, motion | | Theme CSS | @still-void/ui/theme.css | browser | CSS vars (--sv-*), dark/light via data-theme, accents via data-accent, signature utilities | | Component CSS | @still-void/ui/style.css | browser | All component classes (sv-*) | | Recipes | @still-void/ui | anywhere (RSC-safe) | Pure functions returning class strings: postCard({ dense: true }) | | Behaviors | @still-void/ui | client | Vanilla DOM: createThemeManager, createScrollSpy, createReadingProgress, copyToClipboard | | React (server-safe) | @still-void/ui/react | server or client | Components without hooks — render inside Server Components | | React (client) | @still-void/ui/react/client | client | 'use client' bundle: ThemeProvider, ThemeToggle, CopyButton, TableOfContents, ReadingProgress, hooks |

Install

npm install @still-void/ui

React is an optional peer dependency — non-React consumers install nothing extra.

Usage — Next.js (App Router, Server Components)

// app/layout.tsx (Server Component)
import '@still-void/ui/theme.css';
import '@still-void/ui/style.css';
import { Header, Logo, Footer, ThemeScript } from '@still-void/ui/react';
import { ThemeProvider, ThemeToggle } from '@still-void/ui/react/client';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    // Server-rendered attributes = correct theme for a first-time visitor.
    // <ThemeScript /> runs before paint and re-applies a *returning* visitor's
    // stored preference, so there's no flash of the wrong theme either way.
    <html lang="en" data-theme="dark" data-accent="cyan" suppressHydrationWarning>
      <head>
        <ThemeScript />
      </head>
      <body className="sv-body">
        <ThemeProvider>
          <Header
            logo={<Logo label="still.void" />}
            items={[{ label: 'Home', href: '/', active: true }]}
            actions={<ThemeToggle />}
          />
          {children}
          <Footer author="Kalleo Pinheiro" links={[{ label: 'RSS', href: '/rss' }]} />
        </ThemeProvider>
      </body>
    </html>
  );
}
// app/page.tsx (Server Component — zero client JS for this content)
import { Hero, PostGrid, PostCard, Layout } from '@still-void/ui/react';

export default async function Home() {
  const posts = await getPosts(); // fetch on the server
  return (
    <Layout>
      <Hero eyebrow="blog" title="Calm engineering, sharp accents" />
      <PostGrid>
        {posts.map((post) => (
          <PostCard key={post.href} post={post} />
        ))}
      </PostGrid>
    </Layout>
  );
}

Everything in @still-void/ui/react is hook-free and browser-API-free, so it renders on the server. Interactive pieces come from @still-void/ui/react/client and are composed in via slots (actions, visual, eyebrow).

// CodeBlock stays a Server Component; only the copy button hydrates.
import { CodeBlock } from '@still-void/ui/react';
import { CopyButton } from '@still-void/ui/react/client';

<CodeBlock code={source} language="ts" actions={<CopyButton code={source} />} />;

Syntax highlighting is bring-your-own (by design — the prototype tokenizer was demo-only): render with Shiki on the server and pass the markup via rendered.

Usage — any other framework (recipes + behaviors)

import { postCard, postCardClasses, createThemeManager } from '@still-void/ui';
<!-- Angular -->
<article [class]="postCard({ dense: true })">
  <h3 [class]="postCardClasses.title">{{ post.title }}</h3>
</article>

Behaviors are plain DOM and return a destroy():

const theme = createThemeManager(); // drives data-theme / data-accent, persists to localStorage
theme.toggleMode();
theme.setAccent('violet');

See playground/index.html for the full catalog rendered with zero framework code — open it with npm run playground after npm run build.

Fonts

theme.css sets --sv-font-display/--sv-font-body/--sv-font-mono to Sora, Manrope and JetBrains Mono, but does not load them — that's a render-blocking @import on every consumer's critical path, and a runtime dependency on a third-party CDN. Load them yourself:

// app/layout.tsx — next/font self-hosts and inlines the @font-face rules, no network request
import { Sora, Manrope, JetBrains_Mono } from 'next/font/google';

const sora = Sora({ subsets: ['latin'], weight: ['400', '600', '700'], variable: '--sv-font-display' });
const manrope = Manrope({ subsets: ['latin'], weight: ['400', '500', '600', '700'], variable: '--sv-font-body' });
const mono = JetBrains_Mono({ subsets: ['latin'], weight: ['400', '500'], variable: '--sv-font-mono' });
<!-- any other framework: preconnect + stylesheet -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Sora:wght@400;600;700&family=Manrope:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
  rel="stylesheet"
/>

System-font fallbacks (ui-sans-serif, system-ui, ui-monospace) already cover the gap before your chosen font loads — see Fidelity rules.

Theming

  • Mode: data-theme="dark" | "light" on <html> (dark is default).
  • Accent: data-accent="cyan" | "violet" | "mint" | "amber" — pure CSS, so it works in Server Components with no JS.
  • Everything is overridable via CSS vars (--sv-accent, --sv-bg, …). No !important anywhere.

Fidelity rules (do not regress)

  • Color values (hex/oklch) are literal from the spec — never rounded.
  • .sv-gradient-border is the visual signature; never replace with box-shadow.
  • Cards have no shadow.
  • text-wrap: balance on every display heading.
  • Fonts: Sora (display) / Manrope (body) / JetBrains Mono (code). System fonts are loading fallbacks only.
  • Hover easing cubic-bezier(.3,.7,.4,1); reading progress bar is linear.
  • Categories are colored dots + label — never emoji.

Note: the reference sources (colors_and_type.css, ui_kits/blog/*.jsx) were not available at extraction time. Colors, accents, fonts, radii, easing and component inventory come literally from the spec document; the numeric type/spacing scales were derived and are centralized in src/tokens/ for easy correction against the originals.

Scripts

npm run build             # tsup (ESM + CJS + .d.ts) + CSS to dist/
npm test                  # vitest (31 tests)
npm run typecheck         # tsc --noEmit (strict)
npm run lint:package      # publint + are-the-types-wrong on the packed tarball
npm run playground        # serve the framework-free catalog
npm run storybook         # component catalog at localhost:6006
npm run build-storybook   # static Storybook build → storybook-static/
npm run changeset         # record a change for the next release
npm run version-packages  # apply pending changesets, bump version, update CHANGELOG (CI does this)
npm run release           # build + publish to npm (CI does this)

Versioning

Releases are managed with Changesets and are fully automated — nobody publishes from a laptop:

  1. A pull request that touches src/ or scripts/ must carry a changeset (npm run changeset); CI fails without one.
  2. Merging into main opens a chore: version packages pull request with the version bump and the generated CHANGELOG.md.
  3. Merging that publishes to npm with provenance, tags v<version>, creates the GitHub release and redeploys Storybook.

The changelog and the version are generated from changeset entries, never written by hand. Unreleased changes can be tried out from a canary snapshot before they ship.

Bump levels for a design system (what counts as breaking, and why a corrected token is a patch while a redesigned one is a major) are documented in CONTRIBUTING.md.