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

@bryan-cunningham-design/igenie-ui

v0.2.0

Published

i-Genie React component library — typed, accessible primitives with no copy of their own, themed entirely by CSS custom properties from @bryan-cunningham-design/igenie-tokens.

Readme

@bryan-cunningham-design/igenie-ui

React component library for i-Genie: typed, accessible primitives built on Base UI. They carry no colour values and no user-facing copy of their own — every surface, radius and shadow resolves to a token from @bryan-cunningham-design/igenie-tokens, and every string arrives through children or a prop. A new locale therefore costs nothing here.

Primitives only. The blocks are source you copy, not package API — see Looking for the blocks? below.

Install

pnpm add @bryan-cunningham-design/igenie-ui @bryan-cunningham-design/igenie-tokens

On the public npm registry — no token, no .npmrc. See docs/guides/engineer.md for the CSS setup that follows.

CSS setup — two lines

Tailwind v4 detects source files relative to wherever @import "tailwindcss" appears, so your app owns that import, not this package:

@import "tailwindcss";
@import "@bryan-cunningham-design/igenie-ui/index.css";

That is the whole setup. index.css pulls in the tokens, the base-vega variants, and an @source "./dist" that points Tailwind at this package's compiled output so our class names survive your build. No node_modules paths to write, no Tailwind config to extend.

Dark mode activates on either .dark or [data-theme="dark"] on an ancestor.

No Tailwind in your app? Take one line instead of two:

@import "@bryan-cunningham-design/igenie-ui/standalone.css";

That is every component's CSS, compiled when this package was published, for an app that resolves it from a CDN and has no node_modules to scan. Take one or the other and never both: this one carries Tailwind's preflight, and it cannot be extended with utilities of your own.

Usage

import { Button, Card, CardContent } from "@bryan-cunningham-design/igenie-ui"

Every component is a named export from the package root, with one exception, so a component moving between files inside the library is never a breaking change for you.

The one exception: Toaster

Toaster is not on the root. It lives behind its own subpath, and it is the only component that needs a package you install yourself:

pnpm add sonner
import { Toaster } from "@bryan-cunningham-design/igenie-ui/sonner"

That separation is deliberate rather than tidy-mindedness. toast() and <Toaster> talk to each other through one module-level store, so the library cannot ship its own copy of sonner without your toasts reaching a different toaster than the one on your page. Putting it on the root instead would make your bundler resolve sonner to build a Button, and break the build of anyone who declined the install.

sonner is marked optional in peerDependenciesMeta, so skipping the install is silent and costs nothing until you import that path. Nothing else in the library is affected.

The full account — where to mount it, the three things that break it quietly, and why richColors also wants a theme prop — is under Optional peers in docs/guides/engineer.md.

The other subpaths, none of them a component

  • @bryan-cunningham-design/igenie-ui/hooks/use-mobileuseIsMobile(), a matchMedia hook that returns true under 768px. It is what Sidebar uses to become a drawer, and it carries no peer.
  • @bryan-cunningham-design/igenie-ui/index.css — the stylesheet from the CSS setup above, and @bryan-cunningham-design/igenie-ui/standalone.css, its precompiled alternative.

SidebarProvider writes its open state to a cookie named sidebar_state, with the widths 16rem expanded and 3rem collapsed-to-icons. Read that cookie on the server and pass it as defaultOpen if you want the sidebar to render in the right state before hydration.

Looking for the blocks?

LoginForm, FilterPanel and StatsDashboard are not published, and no longer resolve from this package. A block is a whole screen — it decides where state lives, what the labels say and how the fields are grouped — and none of that can be reached from outside a subtree you do not render. So they are handed over as source instead: open the Blocks gallery and copy the file. It imports this package by name, so it compiles unchanged. The gallery sits behind a sign-in — the site is private. The way in is your address in .github/access-readers.jsonc: a one-line pull request if you can see this repository, and otherwise ask whoever gave you access to the package, since they can open it for you.

Extending it in your own application

You never need to fork this package to get a variant it does not have. Three moves cover it, all in your application's own stylesheet or source:

  • Redefine a semantic variable after the two imports, in both modes.
  • Add your own @theme block. Tailwind v4 merges theme namespaces, so --color-brand-500 mints bg-brand-500 for your app and no other.
  • Compose on an exported cva config. alertVariants, badgeVariants, buttonVariants, buttonGroupVariants and tabsListVariants are public; a variant layered on one keeps receiving upstream fixes.

Each is worked through on the docs site under Theming → Extending the system in your own application.


For maintainers of this library

Everything below is about producing this package, not consuming it. If you installed it, you are done above.

src/components/ is generated — do not edit it

src/components/*.tsx and styles/base.css are vendored from the shadcn registry by scripts/vendor-ui.mjs. Local edits are overwritten on the next re-vendor:

pnpm ui:vendor

That refetches every vendored component, rewrites their imports to local paths, resolves icons against lucide-react, refetches the vendored hooks, and regenerates styles/base.css. It is vendored rather than imported so the library does not take a CLI as a runtime dependency. Review the diff before committing — an upstream change to a component's DOM structure is a visual change to every consuming product.

The component list lives in scripts/lib/registry.mjs; add a name there and re-run the command to pull it in. To change how a component looks, either move the token it resolves to, or wrap it in a new hand-written file — never patch the vendored source.

Coverage against the upstream registry

pnpm parity

Diffs the pinned @shadcn registry's component list against this library and prints the table as markdown for a pull request description. The inventory has exactly one definition — scripts/lib/registry.mjs — which is why the table cannot drift, and the shipped column is derived from the site registry, so nothing reads as implemented until it has a demo.

Four statuses, matching STATUS in scripts/parity.mjs: shipped, deferred (would add a third-party runtime package not yet taken on), recipe (a documented composition with nothing to install, left out of the denominator) and planned.

This report is deliberately not published on the docs site. Coverage is a maintainer's progress bar; on a consumer page it invites the reader to model the library as a partial copy of something else.

Not every file in src/components/ is generated. A component whose banner says FORKED has been ejected from the vendor set: ui:vendor skips it, upstream fixes no longer arrive on their own, and the file is hand-owned from then on. FORKED in scripts/lib/registry.mjs is the list, and it records the shadcn version each fork happened at. Read the banner before you assume an edit will survive.

Hand-written code lives in src/lib/ and index.css, and is safe to edit.

Seeing what upstream offers

pnpm parity reports coverage against the pinned @shadcn registry. To look further — a namespaced or third-party registry the parity table knows nothing about — search the CLI instead:

pnpm dlx [email protected] search @shadcn -q <term> -t ui --cwd packages/ui

With no registry argument it searches every registry listed in components.json. Finding a name there is not an instruction to run add: the route in is still COMPONENTS in scripts/lib/registry.mjs plus pnpm ui:vendor --only <name>, which resolves the registry's import aliases and icon placeholders for you.

One-off shadcn add

components.json is kept accurate so the CLI still works for a single item:

pnpm dlx [email protected] add <name>

It writes @/lib/utils-style imports. Rewrite them to relative paths (../lib/utils, ./button) before building — the package ships unbundled, so an unresolved alias would reach consumers intact.

Keep components.json free of comments. Biome parses it as JSONC and will not complain, but the shadcn CLI parses it as strict JSON and dies on the first // — taking both commands above with it. The aliases in it exist only for these one-offs; nothing in src/ resolves them.

Build

pnpm --filter @bryan-cunningham-design/igenie-ui build

tsdown emits per-module ESM plus declarations, unbundled and unminified. That is deliberate: bundling would collapse the per-file "use client" directives most components rely on, and minifying would mangle the class strings Tailwind needs to scan.

Two settings in tsconfig.json exist only to serve the vendored code, and cannot be commented inline because Biome parses this package's tsconfig.json as strict JSON:

  • allowUmdGlobalAccess — the registry ships skeleton.tsx using the React UMD global with no import. Accommodating it here means a re-vendor never needs a hand-edit.
  • baseUrl / paths — resolves the @/ aliases in components.json so a one-off shadcn add works. Nothing in src/ uses them.