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

@enya-learning/nova

v0.4.3

Published

Enya Learning's component library for building modern web applications.

Readme

@enya-learning/nova

Enya Learning's component library for building modern web applications.

Nova provides accessible, themeable UI components built on Base UI primitives and styled with Tailwind CSS v4. It handles keyboard navigation, focus management, and ARIA attributes so you can build accessible applications without thinking through every detail.

Installation

pnpm add @enya-learning/nova

Peer Dependencies

pnpm add react react-dom

Import Components

// Main package import
import { Button, Input, Dialog } from "@enya-learning/nova"

// Granular imports (recommended for tree-shaking)
import { Button } from "@enya-learning/nova/components/button"

Import Styles

For Tailwind CSS v4 Users

Tailwind CSS v4 does not scan node_modules/ by default. Add a @source directive so Tailwind discovers the utility classes Nova uses — without this, components may render with missing styles.

In your main CSS file:

@source "../node_modules/@enya-learning/nova/dist/**/*.{js,jsx,ts,tsx}";
@import "@enya-learning/nova/styles";
@import "tailwindcss";

Import order matters — @enya-learning/nova/styles must come before @import "tailwindcss" so Nova's @theme tokens are registered first.

Note: The @source path is relative to your CSS file. Adjust it based on your project structure.

Global CSS (optional)

Nova ships a globals.css for base resets and font loading:

@import "@enya-learning/nova/globals.css";

Styles architecture

Nova's CSS is split across four files with distinct responsibilities:

| File | Role | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | nova-binding.css | Registers the raw palette into Tailwind's @theme — every nova-* colour stop and utilities like --ease-bounce. This is what makes bg-nova-sky-500 work as a class. | | theme-nova.css | Semantic tokens — maps palette stops to meaning (--color-nova-brand, --color-nova-success, --text-color-nova-subtle, etc.) with light-dark() for automatic light/dark switching. | | nova.css | The bridge to shadcn — remaps shadcn's generic variables (--primary, --background, --destructive, etc.) onto nova semantic tokens so shadcn components pick up nova colours without modification. | | globals.css | App entry point — imports Tailwind, fonts, shadcn base, and nova.css. Also sets @theme inline to wire shadcn colour vars into Tailwind's class system, defines the dark variant, and applies base body/border styles. |

Import chain:

globals.css → nova.css → nova-binding.css → theme-nova.css

Where to make changes:

  • Adding a new colour stop → nova-binding.css
  • Adding or changing what a colour means (e.g. a new nova-brand-subtle surface) → theme-nova.css
  • Swapping which palette scale powers a semantic role (e.g. changing the brand variant) → nova-binding.css brand alias block
  • Mapping a new shadcn variable to nova → nova.css

Base UI Primitives

Nova is built on Base UI. For advanced use cases requiring fine-grained control, reach into your own @base-ui/react dependency directly:

import { Popover } from "@base-ui/react"

Prefer styled Nova components when available — use Base UI primitives only for custom components not yet in Nova.


Table of contents


Overview

nova/
├── apps/
│   └── web/           Astro documentation site (localhost:4321)
└── packages/
    └── nova/          This package — the component library
        ├── src/
        │   ├── components/   One folder per component
        │   ├── styles/       Design tokens and global CSS
        │   ├── lib/          Utilities (cn, etc.)
        │   └── index.ts      Library barrel export
        └── .storybook/       Storybook configuration

Three moving parts:

| Tool | Purpose | Port | | ---------------------------- | ------------------------------------------------- | ---- | | Storybook | Isolated component development & interactive docs | 6006 | | pnpm dev | Vite watch build — feeds the Astro docs site | — | | Astro docs site (apps/web) | Static documentation website | 4321 |

Storybook is the primary development environment. The Astro docs site is for publishing static reference documentation.


Prerequisites

  • Node ≥ 22.12
  • pnpm 10
# From the monorepo root — installs all workspaces
pnpm install

Development workflows

Option A — Storybook (recommended for component work)

The fastest way to build and test components in isolation.

# From packages/nova
pnpm storybook
# → http://localhost:6006

What you get:

  • Full HMR with React Fast Refresh
  • Interactive controls for every prop
  • Auto-generated prop tables from TypeScript types (autodocs tag)
  • Light/dark mode toggle (sets data-mode="dark" on the root element)
  • Accessibility panel

Option B — Watch build + Astro docs site

Use this when you need to see your changes reflected in the actual documentation website.

# Terminal 1 — rebuild nova on every save (~400ms)
cd packages/nova
pnpm dev

# Terminal 2 — Astro dev server
cd apps/web
pnpm dev
# → http://localhost:4321

Refresh the browser after a nova rebuild to see changes.


Adding a new component

Use the generator to scaffold the files and wire up the exports in one step:

pnpm --filter @enya-learning/nova new-component

The generator creates the component file, barrel index, and story, then automatically adds the barrel export to src/index.ts and the build entry to vite.config.ts. The package.json exports use a wildcard ("./components/*") — no manual edit needed.

After running the generator, complete these final steps manually:

1. Implement the component

Fill in src/components/{name}/{name}.tsx — the generator creates a minimal <div> shell.

2. Write a story

The generator creates a stub story with a single Default export. Add variant and state stories. See Writing stories below.

3. Generate the docs page

pnpm generate-docs

This creates apps/web/src/content/components/{name}.mdx from your story file. Commit it.


Reference: what the generator does

For manual setups or debugging, here is what pnpm new-component automates:

Creates:

src/components/{name}/
├── {name}.tsx          component shell
├── {name}.stories.tsx  Storybook story stub
└── index.ts            barrel re-export (export * from "./{name}")

Modifies src/index.ts — appends before the utils export:

export * from "./components/{name}"

Modifies vite.config.ts — inserts before // ADD_COMPONENT_ENTRY_HERE:

"components/{name}": resolve(__dirname, "src/components/{name}/index.ts"),

Writing stories

Stories live alongside their component:

src/components/button/
├── button.tsx
├── button.stories.tsx   ← story file
└── index.ts

Canonical pattern

import type { Meta, StoryObj } from "@storybook/react"
import { Button } from "./button"

// Meta: describes the component and sets defaults shared across all stories
const meta: Meta<typeof Button> = {
  title: "Components/Button",
  component: Button,
  tags: ["autodocs"], // enables the auto-generated Docs tab
  args: { children: "Click me" }, // default prop values for all stories
}

export default meta
type Story = StoryObj<typeof meta>

// Each named export is one story (one state of the component)
export const Default: Story = {}

export const Outline: Story = {
  args: { variant: "outline" }, // overrides meta.args
}

export const Disabled: Story = {
  args: { disabled: true },
}

Rules of thumb:

  • Set shared defaults in meta.args (e.g. children, placeholder). Per-story args merge on top.
  • Add tags: ["autodocs"] to every meta object — this activates the auto-generated props table.
  • Give every variant and state its own named export so it appears in the sidebar.
  • For components that render void HTML elements (e.g. Input, Checkbox), do not set children in args — the generator produces self-closing JSX.
  • Use a render: function for multi-component showcase stories (AllVariants, AllSizes). The doc generator skips these.

Dark mode

The Storybook toolbar has a light/dark toggle. It sets data-mode="dark" on the HTML root, activating Nova's dark: Tailwind variant. All components respond automatically — no extra work needed in stories.


Generating docs

The generate-docs script reads every *.stories.tsx file, extracts prop types and story examples, and writes a .mdx file to the Astro docs site.

# From packages/nova
pnpm generate-docs

Output: apps/web/src/content/components/{name}.mdx

Re-run this whenever you:

  • Add a new component story
  • Add or rename stories
  • Update meta.args

The generated MDX files are committed to the repo so the Astro site can build without running the script in CI.


Testing and quality

# Unit tests (vitest)
pnpm test           # single run
pnpm test:watch     # watch mode

# TypeScript
pnpm typecheck

# Lint
pnpm lint

# Format
pnpm format

Run all checks from the monorepo root:

pnpm --filter @enya-learning/nova test
pnpm typecheck   # runs across all workspaces via turbo
pnpm lint

Publishing

Nova is published to the GitHub npm registry (npm.pkg.github.com). Publishing requires a GitHub Personal Access Token with packages:write scope in your ~/.npmrc:

//npm.pkg.github.com/:_authToken=YOUR_TOKEN

Release flow

1. Create a changeset — describe what changed and choose a semver bump:

# From the monorepo root
pnpm changeset

Select @enya-learning/nova, choose patch / minor / major, write a one-line description. This creates a .changeset/*.md file — commit it with your feature branch.

Semver guide: | Change type | Bump | |-------------|------| | Bug fix, style tweak | patch | | New component, new prop, new variant | minor | | Removed export, renamed prop, breaking API change | major |

2. Bump the version — consumes all pending changesets and updates CHANGELOG.md:

pnpm version

3. Build and publish:

pnpm release
# → builds packages/nova, then runs changeset publish

4. Push the version commit and tags:

git push && git push --tags