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

@waveso/ui

v0.14.0

Published

Wave UI component library built on Base UI and Tailwind CSS

Readme

npm license React 19 Tailwind CSS v4

Full documentation coming soon at ui.wave.so


Why Wave UI

A production-ready design-token architecture that's modern, semantic, and highly maintainable.

Most UI libraries carry two structural problems:

  1. Redundant token names (border-border, ring-ring) — which read backwards the moment background and text swap roles: a background becomes bg-foreground, text becomes text-background.
  2. Material-style paired tokens (card + card-foreground, popover + popover-foreground) — flexible per layer, but they add complexity, kill the emphasis ladder, and lose free composability. foreground-muted is meant as "text on muted," yet most people read it as "muted text." The result is ~14 tokens, half of them redundant.

Both models work, and end users never notice. But for the people building on the system, the shape matters.

Wave builds around an intuitive, intentional 3-tier hierarchy — for almost everything:

  • 3 themes — Paper, Graphite, Ink palettes
  • 3 background colors for surfaces
  • 3 content colors for text
  • 3 identity colors for brand
  • 3 border colors for structural luminance
  • 3 duration tiers for transitions
  • 3 blur values
  • 3 scale sizes
  • 3 stagger times
  • 3 shadows with adaptable color
  • 3 offset amounts for transforms
  • …and more

It also builds around 3 semantic intents:

  • Background colors focus on elevation — how deep a surface sits
  • Content colors focus on emphasis — how strongly something reads
  • Border colors focus on structure — how functional a boundary is

This is the right shape for a system centered on an emphasis ladder: clean and minimal, but flexible.

Themes

The three themes are a homage to the pre-digital writing desk — the surface, the pen, the pencil — and each maps to its color: cream Paper, blue-black Ink, gray Graphite.

Wave follows your operating system by default — a light OS gets Paper, a dark OS gets Graphite (the neutral pencil-gray theme, a low-saturation dark-neutral with a subtle blue bias so its steps never go flat). Ink, the deep-navy night theme, is opt-in.

| Theme | Role | Select with | | --- | --- | --- | | Paper | Light | light OS · <html class="paper"> | | Graphite | Dark | dark OS · <html class="graphite"> | | Ink | Night (premium) | <html class="ink"> |

A pinned class always beats the OS — put .paper, .graphite, or .ink on your <html> (or any subtree) from your app's own theme toggle. In every theme the structure (text and borders) stays a cool-biased neutral, while the surface carries the identity.

Taxonomy

Wave pays close attention to token taxonomy. Surfaces encode elevation; borders act as light interference rather than geometry.

Background

  • --foundation — the deepest layer, the base where elevation starts
  • --surface — the middle layer: cards, sidebars, content boxes
  • --elevated — the highest layer: floating windows, modals, dropdowns, dialogs

Foreground

  • --contrast — titles, primary text
  • --muted — body text, icons, any mark
  • --soft — placeholders, hints

Borders

  • --line — subtle separators
  • --edge — component boundary
  • --solid — structural definition

Ring

  • --focus — active / focus states

Brand

  • --primary — wired to the Wave ramp
  • --secondary — neutral fill
  • --accent — alternative emphasis

Border strategy

This is the sophisticated move most libraries skip.

Wave biases heavily toward transparent (alpha) borders as the default, with a solid token reserved for functional states.

Wave's palette behaves like a layered material system, not a flat UI. Dark surfaces, a soft text hierarchy, and subtle elevation shifts (low-contrast steps) mean borders should not introduce a new "color layer" — that would break the illusion of depth — yet structure still needs a solid option.

Alpha borders inherit the surface beneath them, take the content color as their luminance source, keep hue consistent across surfaces, and scale naturally.

Solid borders compete with the surface ladder and create visual "grid noise" if overused, so use them sparingly. Overusing them flattens everything into "outlined boxes" with reduced perceived elevation — the "Bootstrap feel."

The default alpha borders are ideal for:

  • Cards
  • Panels
  • Inputs
  • Subtle separators

The solid borders are ideal for:

  • Layout definition (sidebar vs. content)
  • Component grouping
  • Focus containment
  • "Frame-like" boundaries

Rule of thumb:

  • If it separates surface from surface → alpha border
  • If it separates layout regions → solid border
  • If it indicates interaction / state → colored alpha border

Installation

npm install @waveso/ui @base-ui/react class-variance-authority clsx tailwind-merge

Setup

Import Tailwind, then the Wave UI preset, in your CSS entry point:

@import "tailwindcss";
@import "@waveso/ui/styles.css";

The preset provides every CSS variable (colors, radii, motion, shadows) with light and dark support. Override any variable in your own :root or a theme block (.graphite, .ink, …) to customize the theme.

Usage

Every component is its own entry point, so you ship only what you import:

import { Button } from '@waveso/ui/button';
import { Card, CardHeader, CardTitle, CardContent } from '@waveso/ui/card';

export function Example() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Get started</CardTitle>
      </CardHeader>
      <CardContent>
        <Button>Click me</Button>
      </CardContent>
    </Card>
  );
}

Every component is built on a Base UI primitive — full keyboard and ARIA support — and styled entirely through the theme tokens above, so overriding a token propagates everywhere.

Components

A comprehensive set spanning actions, forms, layout, navigation, overlays, feedback, data display, and motion effects — all built on Base UI primitives and driven by the theme tokens.

Browse every component, with live variants and source, in Storybook (npm run storybook). A full documentation site is on the way at ui.wave.so.

Requirements

| Dependency | Version | |---|---| | React | ^19.0.0 | | React DOM | ^19.0.0 | | Base UI | ^1.6.0 | | Tailwind CSS | v4 | | CVA | ^0.7.0 | | clsx | ^2.0.0 | | tailwind-merge | ^3.0.0 |

Some components have optional peer dependencies — install only what you use:

  • Formreact-hook-form
  • Input OTPinput-otp
  • Animationsmotion

Development

npm install
npm run storybook    # Start Storybook
npm run build        # Build the library
npm run typecheck    # Type-check
npm run dev          # Watch mode

Project structure

.changeset/          # Changesets config
.storybook/          # Storybook config + theme CSS
assets/              # README / brand assets
src/
  *.tsx              # Component source files
  *.stories.tsx      # Storybook stories
  styles.css         # Theme preset (CSS variables + Tailwind mapping)
  hooks/             # Custom hooks
  lib/               # Utilities (cn, internal icons)

Releasing

This project uses Changesets with GitHub Actions.

  1. Run npx changeset to describe your changes (patch, minor, or major)
  2. Commit the generated changeset file with your PR
  3. When merged to main, CI automatically versions and publishes to npm

If you're not using the GitHub Actions workflow, you can publish manually. Changesets skips versions already published to npm, so this won't conflict if CI has already run.

npx changeset              # Create a changeset
npx changeset version      # Apply version bump
npm run release            # Build and publish to npm

License

MIT