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

@ravnhq/efni

v0.3.0

Published

Efni — Ravn's design system: framework-free React components on Base UI, with the token layer they are built on.

Readme

@ravnhq/efni

Ravn's design system: framework-free React components on Base UI, built on a three-tier token layer.

Docs: https://ravnhq.github.io/efni-ds/

To work on Efni's components, tokens, or documentation site, clone ravnhq/efni-ds and run pnpm dev.

Install

Efni is a public package on npm, under Ravn's @ravnhq org:

pnpm add @ravnhq/efni

The package ships compiled JavaScript and type declarations. Public npm access allows installation in local projects and CI.

Setup

Three things, and the package cannot do them for you.

1. The stylesheet. Replace the contents of app/globals.css with this one line — do not add it alongside what is already there.

/* app/globals.css */
@import "@ravnhq/efni/styles.css";

It brings Tailwind, the tokens, the shadcn bridge, and an @source pointing at this package, since Tailwind v4 does not scan node_modules.

Replacing matters. create-next-app writes a globals.css that defines --background and --foreground — the same names the shadcn bridge maps onto Efni tokens — plus body { font-family: Arial, … } and its own @theme inline font mapping. Keep them and they win: the page stays light with data-theme="dark" set, and every component renders in Arial. Nothing errors, so it is easy to miss.

2. The three font variables. The tokens map --font-sans, --font-mono and --font-display onto them, so without these you get no typography.

import { Hanken_Grotesk, Inter, JetBrains_Mono } from "next/font/google";

const display = Hanken_Grotesk({ variable: "--font-hanken-grotesk", subsets: ["latin"] });
const body = Inter({ variable: "--font-inter", subsets: ["latin"] });
const mono = JetBrains_Mono({ variable: "--font-jetbrains-mono", subsets: ["latin"] });

3. The theme attributes on <html>. data-theme is required; data-tool only if you want an accent other than the default.

<html data-theme="light" className={`${display.variable} ${body.variable} ${mono.variable}`}>

Use

One import per component:

import { Button } from "@ravnhq/efni/button";
import { Typography } from "@ravnhq/efni/typography";

<Typography variant="h1">Mission MB-4472</Typography>
<Button>Save</Button>

Peer dependencies

react, react-dom and tailwindcss come with create-next-app. lucide-react does not — install it:

pnpm add lucide-react

Sixteen components import it directly, so you need it even if you never touch Icon. It is a peer rather than a bundled dependency because Icon takes an icon you pass in, which has to resolve from your tree:

import { Star } from "lucide-react";
import { Icon } from "@ravnhq/efni/icon";

<Icon icon={Star} />

Four more are optional, needed only by the component that uses them — and needed directly in your project, because a component's own dependency is not importable from your code:

| Add this | If you use | |---|---| | pnpm add react-hook-form | Form — you call useForm yourself | | pnpm add "@tanstack/react-table@^8" | DataTable with typed ColumnDef columns | | pnpm add sonner | toast() — the package exports Toaster, you call toast | | pnpm add react-day-picker | Calendar or DatePicker with typed props — Calendar types its props as ComponentProps<typeof DayPicker> |

The ^8 on react-table is not optional. Plain pnpm add @tanstack/react-table installs v9, which renamed getCoreRowModel to createCoreRowModel and useReactTable to ReactTable. DataTable is on v8 deliberately, so v9 breaks the build with Export getCoreRowModel doesn't exist in target module.

If you see TypeScript errors inside @ravnhq/efni/dist, you are missing a peer. The declarations reference the peers' types, so an absent peer surfaces as Cannot find module inside our .d.ts files. Install the peer the first error names.

Inside a monorepo, as a workspace package

A monorepo that wants to edit Efni alongside its apps — Mission Board is the first — can bring packages/ui in as a workspace member instead of installing from npm. Prefer a git submodule or subtree of ravnhq/efni-ds: it keeps the history, and git submodule update is the upgrade. A copy of the directory works too.

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "vendor/efni-ds/packages/ui"   # wherever you put it
// apps/<app>/package.json
"dependencies": { "@ravnhq/efni": "workspace:*" }

In a workspace the package's exports point at its TypeScript source. Edits show up on save through Turborepo's Just-in-Time internal package pattern:

  • Your bundler compiles our source. In Next: transpilePackages: ["@ravnhq/efni"].
  • Peers resolve from your workspace — the same list as above.

With Turborepo. The package carries the check-types script the Just-in-Time shape expects (tsc --noEmit), plus one it does not: build (tsup), which produces what npm receives. A host with build: { dependsOn: ["^build"] } will run that tsup before your app builds, and check-types: { dependsOn: ["^check-types"] } will typecheck the package, tests included. Both are unnecessary for you — your app compiles the source — and both pass, because the directory is self-contained: its tsconfig.json extends nothing, and everything its build and tests import — the peers included — is declared in its own devDependencies, so it does not depend on your auto-install-peers setting. Let them run; Turborepo caches them.

dist/ is gitignored here, so a submodule never carries one. A directory copy taken after a local pnpm build does, and styles.css would scan those stale files alongside src — delete dist when you copy.

Licence

MIT