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

@maholan/cli

v0.2.0

Published

CLI for installing MHL UI components and design tokens

Readme

@maholan/cli

CLI for installing MHL UI components and design tokens. Inspired by shadcn/ui's component registry pattern.

Features

  • 🎨 Interactive Setup - Choose your theme (brand color, gray base, radius style)
  • 📦 Component Registry - Install components on-demand from registry
  • 🔧 Smart Configuration - Auto-detects framework (Next.js, Vite, Remix)
  • 🎯 Dependency Resolution - Automatically installs component dependencies
  • 🌈 Theme Variants - 300+ theme combinations (10 brands × 6 grays × 5 radius)
  • 🔄 Diff Checking - Compare local files with registry versions
  • 🚀 Package Manager Detection - Works with npm, yarn, pnpm, bun

Installation

# Using npx (recommended)
npx @maholan/cli init

# Or install globally
npm install -g @maholan/cli
mhl init

# With other package managers
pnpm dlx @maholan/cli init
yarn dlx @maholan/cli init
bunx @maholan/cli init

Usage

Initialize Project

npx @maholan/cli init

This will:

  1. Detect your framework (Next.js App Router, Pages Router, Vite, Remix)
  2. Prompt you to select a brand color from 10 options (purple, blue, cerulean, teal, indigo, fuchsia, pink, magenta, orange, rose)
  3. Configure component and utility paths
  4. Create mhl.config.json configuration file
  5. Install base dependencies (@maholan/tokens, @maholan/theme, react-aria-components, class-variance-authority, clsx, tailwind-merge)
  6. Inject @import "@maholan/tokens/mhl-tokens.css" into your global CSS file
  7. Create cn() utility function

Add Components

# Add single component
npx @maholan/cli add button

# Add multiple components
npx @maholan/cli add button input dialog

# Add all components
npx @maholan/cli add --all

# Interactive selection
npx @maholan/cli add

# Skip confirmation prompts
npx @maholan/cli add button --yes

# Overwrite existing files
npx @maholan/cli add button --overwrite

# Install with custom theme variant (NEW! 🎨)
npx @maholan/cli add button --variant

# Install with Storybook stories (NEW! 📚)
npx @maholan/cli add button --with-stories

# Combine flags
npx @maholan/cli add button --variant --with-stories

Theme Variant Installation

The --variant flag allows you to install components with custom theme settings:

# Install button with custom theme
npx @maholan/cli add button --variant

# Interactive prompts:
? Change brand color? (current: purple) › Yes
? Select brand color: › blue
? Change gray base? (current: gray) › No
? Change border radius? (current: md) › Yes
? Select border radius: › lg (12px)

📦 Installing with custom theme:
  Brand: blue
  Gray: gray
  Radius: lg

✅ Component installed with custom theme variant!

Use Cases:

  • 🎨 Multi-brand monorepos - Different themes per app
  • 🧪 A/B testing - Test design variants
  • 👥 Client customization - Client-specific themes
  • 🔄 Progressive migration - Test new theme on specific components

Features:

  • ✅ 300+ theme combinations (10 brands × 6 grays × 5 radius)
  • ✅ Automatic kebab-case file naming
  • ✅ Theme variant comments in generated files
  • ✅ Compatible with standard installation

Storybook Stories Installation

The --with-stories flag installs Storybook stories alongside components:

# Install button with stories
npx @maholan/cli add button --with-stories

# Install multiple components with stories
npx @maholan/cli add button input dialog --with-stories

# Combine with theme variant
npx @maholan/cli add button --variant --with-stories

What gets installed:

  • Component files: button.tsx, button.variants.ts
  • Story file: button.stories.tsx (in the same directory)
  • Storybook dev dependencies (if not already installed)

File structure:

src/components/ui/
└── button/
    ├── button.tsx
    ├── button.variants.ts
    └── button.stories.tsx  ← Storybook story

Benefits:

  • 📚 Interactive component documentation
  • 🎨 Visual testing in isolation
  • 🧪 Easy variant showcase
  • 📝 Usage examples
  • 🔍 Props documentation via autodocs

When you add a component:

  • Fetches component from registry
  • Resolves registry dependencies (e.g., dialog depends on button)
  • Installs npm dependencies automatically
  • Transforms imports to match your project aliases
  • Converts file names to kebab-case (Button.tsx → button.tsx)
  • Applies theme variant if --variant flag is used
  • Copies files to configured paths

Check for Updates

# Check specific component
npx @maholan/cli diff button

# See which files have changed

Output:

✓ OK      src/components/ui/button/button.tsx
⚠ MODIFIED src/components/ui/button/button.variants.ts

Sync Token CSS

Keep your local mhl-tokens.css in sync with the latest registry version:

# Re-fetch mhl-tokens.css and overwrite the local copy
npx @maholan/cli sync

# CI mode — exits 1 if local file is outdated, does not write
npx @maholan/cli sync --check

Output:

✓ mhl-tokens.css is up to date (0.2.1)

# or when outdated:
⚠ mhl-tokens.css is outdated (local: 0.2.1, registry: 0.3.0)
  Run `mhl sync` to update.

The local file location and version are stored in mhl.config.json:

{
  "tokens": {
    "css": "src/styles/mhl-tokens.css",
    "version": "0.2.1"
  }
}

Configuration

After running init, a mhl.config.json file is created:

{
  "$schema": "https://mhl-ui.dev/schema/config.json",
  "framework": "next-app",
  "typescript": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css"
  },
  "aliases": {
    "components": "@/components/ui",
    "utils": "@/lib/utils"
  },
  "theme": {
    "brand": "purple",
    "gray": "neutral",
    "radius": "base"
  },
  "registries": {
    "@maholan": "https://mhl-ui.dev/r"
  }
}

Theme Variants

Brand Colors (10 options)

| Key | Description | | ---------- | ------------------------ | | purple | MHL default | | blue | Professional, enterprise | | cerulean | Fresh, modern | | teal | Calm, balanced | | indigo | Deep, sophisticated | | fuchsia | Bold, vibrant | | pink | Playful, energetic | | magenta | Creative, artistic | | orange | Warm, friendly | | rose | Elegant, refined |

Gray Bases (6 options)

| Key | Tone | Description | | --------- | -------- | ------------------------------------ | | neutral | Warm | Default — slightly warm gray | | steel | Cool | Cool gray (used for dark mode bases) | | slate | Cool | Blue-tinted gray | | zinc | Neutral | True neutral gray | | stone | Warm | Warm brown-gray | | gray | Balanced | Balanced gray |

Border Radius (5 options)

| Key | Value | Use Case | | ---------- | ----- | ---------------------- | | base | 8px | Balanced (default) | | sharp | 0px | Brutalist, modern | | square | 4px | Subtle roundness | | round | 16px | Friendly, approachable | | circular | pill | Maximum rounding |

Component Registry

Components are distributed via a JSON registry (similar to shadcn/ui):

Registry Structure

https://mhl-ui.dev/r/
├── index.json           # List of all components
├── button.json          # Button component
├── input.json           # Input component
├── dialog.json          # Dialog component
└── ...

Registry Item Example

{
  "name": "button",
  "type": "registry:component",
  "description": "Accessible button built on React Aria",
  "dependencies": [
    "react-aria-components",
    "class-variance-authority",
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/mhl/button/button.tsx",
      "content": "...",
      "type": "registry:component"
    },
    {
      "path": "registry/mhl/button/button.variants.ts",
      "content": "...",
      "type": "registry:component"
    }
  ],
  "cssVars": {
    "light": {
      "brand-600": "257 90% 58%"
    },
    "dark": {
      "brand-600": "257 90% 65%"
    }
  }
}

How It Works

1. Initialization Flow

┌─────────────────────────────────────────┐
│  npx @maholan/cli init                      │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Detect Framework (Next.js, Vite, etc) │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Interactive Prompts:                   │
│  - Brand Color (10 options)             │
│  - Component Path                       │
│  - Utils Path                           │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Create mhl.config.json                 │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Install Base Dependencies              │
│  (@maholan/tokens, @maholan/theme,      │
│   react-aria-components, CVA, clsx,     │
│   tailwind-merge)                       │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Inject CSS into globals.css:           │
│  @import "@maholan/tokens/mhl-tokens"   │
│  @import "@maholan/theme/global"        │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Create Directories & cn() Utility      │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  ✅ Ready to add components!            │
└─────────────────────────────────────────┘

2. Component Installation Flow

┌─────────────────────────────────────────┐
│  npx @maholan/cli add button                │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Fetch button.json from Registry        │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Resolve Registry Dependencies          │
│  (e.g., dialog needs button)            │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Install npm Dependencies                │
│  (react-aria-components, etc.)          │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Transform Imports                       │
│  (@/components/ui → your alias)         │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  Copy Files to Project                   │
│  (src/components/ui/button/...)         │
└─────────────────┬───────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────┐
│  ✅ Component ready to import!          │
└─────────────────────────────────────────┘

Architecture

This CLI follows the shadcn/ui pattern:

  1. Registry-Based - Components stored as JSON with source code
  2. Copy, Not Install - Files copied to your project (you own the code)
  3. Dependency Resolution - Automatically handles component dependencies
  4. Import Transformation - Adjusts imports to match your project structure
  5. Theme Variants - Select design tokens during initialization

Commands Reference

| Command | Description | Example | | --------------------- | ---------------------------- | ---------------------------- | | init | Initialize MHL UI in project | mhl init | | add [components...] | Add components | mhl add button input | | add --all | Install all components | mhl add --all | | add --yes | Skip confirmation prompts | mhl add button --yes | | add --overwrite | Overwrite existing files | mhl add button --overwrite | | diff [component] | Check for changes | mhl diff button | | sync | Update local mhl-tokens.css | mhl sync | | sync --check | CI check (exits 1 if stale) | mhl sync --check |

Examples

Example 1: New Next.js App Router Project

# Initialize
npx @maholan/cli init

# Select theme:
# Brand: Purple
# Gray: Gray
# Radius: Medium

# Add components
npx @maholan/cli add button input dialog

# Use in your app
import { Button } from "@/components/ui/button";

Example 2: Existing Vite Project

# Initialize with custom paths
npx @maholan/cli init

# Select:
# Components: src/components
# Utils: src/lib

# Add all components
npx @maholan/cli add --all --yes

Example 3: Check for Updates

# Check if components need updating
npx @maholan/cli diff button
npx @maholan/cli diff input

# Update if needed
npx @maholan/cli add button --overwrite

Comparison with shadcn/ui

| Feature | shadcn/ui | @maholan/cli | | ------------------------- | --------- | -------------------- | | Registry Pattern | ✅ | ✅ | | Component Copy | ✅ | ✅ | | Theme Variants | Limited | ✅ 300+ combinations | | Design Tokens | Basic | ✅ 4-tier system | | Framework Detection | ✅ | ✅ | | Package Manager Detection | ✅ | ✅ | | Dependency Resolution | ✅ | ✅ | | React Aria Foundation | ❌ | ✅ | | MHL Design System | ❌ | ✅ |

Troubleshooting

CLI not found

# Use npx instead
npx @maholan/cli init

# Or install globally
npm install -g @maholan/cli

Import errors

Check your tsconfig.json has correct path aliases:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Component not found

Verify registry URL in mhl.config.json:

{
  "registries": {
    "@maholan": "https://mhl-ui.dev/r"
  }
}

Related Packages

  • @maholan/tokens - Design token system (Figma → TypeScript)
  • @maholan/ui - Pre-built component library (npm install model)
  • @maholan/theme - Theme provider and global styles

License

MIT © MHL Platform